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