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/strings/string_util.h>
24 #include <base/time/time.h>
25 #include <gtest/gtest.h>
26 
27 // This is a mock implementation of HttpFetcher which is useful for testing.
28 
29 using brillo::MessageLoop;
30 using std::min;
31 
32 namespace chromeos_update_engine {
33 
~MockHttpFetcher()34 MockHttpFetcher::~MockHttpFetcher() {
35   CHECK(timeout_id_ == MessageLoop::kTaskIdNull)
36       << "Call TerminateTransfer() before dtor.";
37 }
38 
BeginTransfer(const std::string & url)39 void MockHttpFetcher::BeginTransfer(const std::string& url) {
40   EXPECT_FALSE(never_use_);
41   if (fail_transfer_ || data_.empty()) {
42     // No data to send, just notify of completion..
43     SignalTransferComplete();
44     return;
45   }
46   if (sent_size_ < data_.size())
47     SendData(true);
48 }
49 
SendData(bool skip_delivery)50 void MockHttpFetcher::SendData(bool skip_delivery) {
51   if (fail_transfer_ || sent_size_ == data_.size()) {
52     SignalTransferComplete();
53     return;
54   }
55 
56   if (paused_) {
57     // If we're paused, we should return so no callback is scheduled.
58     return;
59   }
60 
61   // Setup timeout callback even if the transfer is about to be completed in
62   // order to get a call to |TransferComplete|.
63   if (timeout_id_ == MessageLoop::kTaskIdNull) {
64     timeout_id_ = MessageLoop::current()->PostDelayedTask(
65         FROM_HERE,
66         base::Bind(&MockHttpFetcher::TimeoutCallback, base::Unretained(this)),
67         base::TimeDelta::FromMilliseconds(10));
68   }
69 
70   if (!skip_delivery) {
71     const size_t chunk_size =
72         min(kMockHttpFetcherChunkSize, data_.size() - sent_size_);
73     sent_size_ += chunk_size;
74     CHECK(delegate_);
75     delegate_->ReceivedBytes(this, &data_[sent_size_ - chunk_size], chunk_size);
76   }
77   // We may get terminated and deleted right after |ReceivedBytes| call, so we
78   // should not access any class member variable after this call.
79 }
80 
TimeoutCallback()81 void MockHttpFetcher::TimeoutCallback() {
82   CHECK(!paused_);
83   timeout_id_ = MessageLoop::kTaskIdNull;
84   CHECK_LE(sent_size_, data_.size());
85   // Same here, we should not access any member variable after this call.
86   SendData(false);
87 }
88 
89 // If the transfer is in progress, aborts the transfer early.
90 // The transfer cannot be resumed.
TerminateTransfer()91 void MockHttpFetcher::TerminateTransfer() {
92   LOG(INFO) << "Terminating transfer.";
93   // Kill any timeout, it is ok to call with kTaskIdNull.
94   MessageLoop::current()->CancelTask(timeout_id_);
95   timeout_id_ = MessageLoop::kTaskIdNull;
96   delegate_->TransferTerminated(this);
97 }
98 
SetHeader(const std::string & header_name,const std::string & header_value)99 void MockHttpFetcher::SetHeader(const std::string& header_name,
100                                 const std::string& header_value) {
101   extra_headers_[base::ToLowerASCII(header_name)] = header_value;
102 }
103 
GetHeader(const std::string & header_name) const104 std::string MockHttpFetcher::GetHeader(const std::string& header_name) const {
105   const auto it = extra_headers_.find(base::ToLowerASCII(header_name));
106   if (it == extra_headers_.end())
107     return "";
108   return it->second;
109 }
110 
Pause()111 void MockHttpFetcher::Pause() {
112   CHECK(!paused_);
113   paused_ = true;
114   MessageLoop::current()->CancelTask(timeout_id_);
115   timeout_id_ = MessageLoop::kTaskIdNull;
116 }
117 
Unpause()118 void MockHttpFetcher::Unpause() {
119   CHECK(paused_) << "You must pause before unpause.";
120   paused_ = false;
121   SendData(false);
122 }
123 
FailTransfer(int http_response_code)124 void MockHttpFetcher::FailTransfer(int http_response_code) {
125   fail_transfer_ = true;
126   http_response_code_ = http_response_code;
127 }
128 
SignalTransferComplete()129 void MockHttpFetcher::SignalTransferComplete() {
130   // If the transfer has been failed, the HTTP response code should be set
131   // already.
132   if (!fail_transfer_) {
133     http_response_code_ = 200;
134   }
135   delegate_->TransferComplete(this, !fail_transfer_);
136 }
137 
138 }  // namespace chromeos_update_engine
139