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