xref: /aosp_15_r20/system/update_engine/common/mock_http_fetcher.cc (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
1 //
2 // Copyright (C) 2009 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 #include "update_engine/common/mock_http_fetcher.h"
18 
19 #include <algorithm>
20 
21 #include <base/bind.h>
22 #include <base/logging.h>
23 #include <base/time/time.h>
24 #include <brillo/message_loops/message_loop.h>
25 #include <gtest/gtest.h>
26 
27 #include "update_engine/common/utils.h"
28 
29 // This is a mock implementation of HttpFetcher which is useful for testing.
30 
31 using brillo::MessageLoop;
32 using std::min;
33 
34 namespace chromeos_update_engine {
35 
~MockHttpFetcher()36 MockHttpFetcher::~MockHttpFetcher() {
37   CHECK(timeout_id_ == MessageLoop::kTaskIdNull)
38       << "Call TerminateTransfer() before dtor.";
39 }
40 
BeginTransfer(const std::string & url)41 void MockHttpFetcher::BeginTransfer(const std::string& url) {
42   EXPECT_FALSE(never_use_);
43   if (fail_transfer_ || data_.empty()) {
44     // No data to send, just notify of completion..
45     SignalTransferComplete();
46     return;
47   }
48   if (sent_offset_ < data_.size())
49     SendData(true);
50 }
51 
SendData(bool skip_delivery)52 void MockHttpFetcher::SendData(bool skip_delivery) {
53   if (fail_transfer_ || sent_offset_ == data_.size()) {
54     SignalTransferComplete();
55     return;
56   }
57 
58   if (paused_) {
59     // If we're paused, we should return so no callback is scheduled.
60     return;
61   }
62 
63   // Setup timeout callback even if the transfer is about to be completed in
64   // order to get a call to |TransferComplete|.
65   if (timeout_id_ == MessageLoop::kTaskIdNull && delay_) {
66     CHECK(MessageLoop::current());
67     timeout_id_ = MessageLoop::current()->PostDelayedTask(
68         FROM_HERE,
69         base::Bind(&MockHttpFetcher::TimeoutCallback, base::Unretained(this)),
70         base::TimeDelta::FromMilliseconds(10));
71   }
72 
73   if (!skip_delivery || !delay_) {
74     const size_t chunk_size =
75         min(kMockHttpFetcherChunkSize, data_.size() - sent_offset_);
76     sent_offset_ += chunk_size;
77     bytes_sent_ += chunk_size;
78     CHECK(delegate_);
79     delegate_->ReceivedBytes(
80         this, &data_[sent_offset_ - chunk_size], chunk_size);
81   }
82   // We may get terminated and deleted right after |ReceivedBytes| call, so we
83   // should not access any class member variable after this call.
84 }
85 
TimeoutCallback()86 void MockHttpFetcher::TimeoutCallback() {
87   CHECK(!paused_);
88   timeout_id_ = MessageLoop::kTaskIdNull;
89   CHECK_LE(sent_offset_, data_.size());
90   // Same here, we should not access any member variable after this call.
91   SendData(false);
92 }
93 
94 // If the transfer is in progress, aborts the transfer early.
95 // The transfer cannot be resumed.
TerminateTransfer()96 void MockHttpFetcher::TerminateTransfer() {
97   LOG(INFO) << "Terminating transfer.";
98   // During testing, MessageLoop may or may not be available.
99   // So don't call CancelTask() unless necessary.
100   if (timeout_id_ != MessageLoop::kTaskIdNull) {
101     MessageLoop::current()->CancelTask(timeout_id_);
102     timeout_id_ = MessageLoop::kTaskIdNull;
103   }
104   if (delegate_) {
105     delegate_->TransferTerminated(this);
106   }
107 }
108 
SetHeader(const std::string & header_name,const std::string & header_value)109 void MockHttpFetcher::SetHeader(const std::string& header_name,
110                                 const std::string& header_value) {
111   extra_headers_[ToLower(header_name)] = header_value;
112 }
113 
GetHeader(const std::string & header_name) const114 std::string MockHttpFetcher::GetHeader(const std::string& header_name) const {
115   const auto it = extra_headers_.find(ToLower(header_name));
116   if (it == extra_headers_.end())
117     return "";
118   return it->second;
119 }
120 
Pause()121 void MockHttpFetcher::Pause() {
122   CHECK(!paused_);
123   paused_ = true;
124   MessageLoop::current()->CancelTask(timeout_id_);
125   timeout_id_ = MessageLoop::kTaskIdNull;
126 }
127 
Unpause()128 void MockHttpFetcher::Unpause() {
129   CHECK(paused_) << "You must pause before unpause.";
130   paused_ = false;
131   SendData(false);
132 }
133 
FailTransfer(int http_response_code)134 void MockHttpFetcher::FailTransfer(int http_response_code) {
135   fail_transfer_ = true;
136   http_response_code_ = http_response_code;
137 }
138 
SignalTransferComplete()139 void MockHttpFetcher::SignalTransferComplete() {
140   // If the transfer has been failed, the HTTP response code should be set
141   // already.
142   if (!fail_transfer_) {
143     http_response_code_ = 200;
144   }
145   delegate_->TransferComplete(this, !fail_transfer_);
146 }
147 
148 }  // namespace chromeos_update_engine
149