blob: 1b3cd7d746711e77157c9862dd572c2d8ff28418 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
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//
rspangler@google.com49fdf182009-10-10 00:57:34 +000016
Alex Deymo39910dc2015-11-09 17:04:30 -080017#include "update_engine/common/mock_http_fetcher.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000018
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070019#include <algorithm>
20
Alex Deymoc1c17b42015-11-23 03:53:15 -030021#include <base/bind.h>
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070022#include <base/logging.h>
Alex Deymofdd6dec2016-03-03 22:35:43 -080023#include <base/strings/string_util.h>
Alex Deymoc1c17b42015-11-23 03:53:15 -030024#include <base/time/time.h>
Kelvin Zhang9dd93052020-07-21 17:31:19 -040025#include <brillo/message_loops/message_loop.h>
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070026#include <gtest/gtest.h>
27
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070028// This is a mock implementation of HttpFetcher which is useful for testing.
rspangler@google.com49fdf182009-10-10 00:57:34 +000029
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070030using brillo::MessageLoop;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000031using std::min;
32
rspangler@google.com49fdf182009-10-10 00:57:34 +000033namespace chromeos_update_engine {
34
35MockHttpFetcher::~MockHttpFetcher() {
Amin Hassanib2689592019-01-13 17:04:28 -080036 CHECK(timeout_id_ == MessageLoop::kTaskIdNull)
37 << "Call TerminateTransfer() before dtor.";
rspangler@google.com49fdf182009-10-10 00:57:34 +000038}
39
40void MockHttpFetcher::BeginTransfer(const std::string& url) {
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070041 EXPECT_FALSE(never_use_);
Darin Petkovedc522e2010-11-05 09:35:17 -070042 if (fail_transfer_ || data_.empty()) {
43 // No data to send, just notify of completion..
44 SignalTransferComplete();
45 return;
46 }
Kelvin Zhang9dd93052020-07-21 17:31:19 -040047 if (sent_offset_ < data_.size())
rspangler@google.com49fdf182009-10-10 00:57:34 +000048 SendData(true);
49}
50
Amin Hassanid3f4bea2018-04-30 14:52:40 -070051void MockHttpFetcher::SendData(bool skip_delivery) {
Kelvin Zhang9dd93052020-07-21 17:31:19 -040052 if (fail_transfer_ || sent_offset_ == data_.size()) {
Darin Petkovedc522e2010-11-05 09:35:17 -070053 SignalTransferComplete();
Amin Hassanid3f4bea2018-04-30 14:52:40 -070054 return;
rspangler@google.com49fdf182009-10-10 00:57:34 +000055 }
56
57 if (paused_) {
Amin Hassanid3f4bea2018-04-30 14:52:40 -070058 // If we're paused, we should return so no callback is scheduled.
59 return;
rspangler@google.com49fdf182009-10-10 00:57:34 +000060 }
61
Amin Hassanid3f4bea2018-04-30 14:52:40 -070062 // Setup timeout callback even if the transfer is about to be completed in
63 // order to get a call to |TransferComplete|.
Kelvin Zhang9dd93052020-07-21 17:31:19 -040064 if (timeout_id_ == MessageLoop::kTaskIdNull && delay_) {
65 CHECK(MessageLoop::current());
Alex Deymo60ca1a72015-06-18 18:19:15 -070066 timeout_id_ = MessageLoop::current()->PostDelayedTask(
67 FROM_HERE,
68 base::Bind(&MockHttpFetcher::TimeoutCallback, base::Unretained(this)),
69 base::TimeDelta::FromMilliseconds(10));
rspangler@google.com49fdf182009-10-10 00:57:34 +000070 }
Amin Hassanid3f4bea2018-04-30 14:52:40 -070071
Kelvin Zhang9dd93052020-07-21 17:31:19 -040072 if (!skip_delivery || !delay_) {
Amin Hassanid3f4bea2018-04-30 14:52:40 -070073 const size_t chunk_size =
Kelvin Zhang9dd93052020-07-21 17:31:19 -040074 min(kMockHttpFetcherChunkSize, data_.size() - sent_offset_);
75 sent_offset_ += chunk_size;
76 bytes_sent_ += chunk_size;
Amin Hassanid3f4bea2018-04-30 14:52:40 -070077 CHECK(delegate_);
Kelvin Zhang9dd93052020-07-21 17:31:19 -040078 delegate_->ReceivedBytes(
79 this, &data_[sent_offset_ - chunk_size], chunk_size);
Amin Hassanid3f4bea2018-04-30 14:52:40 -070080 }
81 // We may get terminated and deleted right after |ReceivedBytes| call, so we
82 // should not access any class member variable after this call.
rspangler@google.com49fdf182009-10-10 00:57:34 +000083}
84
Alex Deymo60ca1a72015-06-18 18:19:15 -070085void MockHttpFetcher::TimeoutCallback() {
rspangler@google.com49fdf182009-10-10 00:57:34 +000086 CHECK(!paused_);
Amin Hassanid3f4bea2018-04-30 14:52:40 -070087 timeout_id_ = MessageLoop::kTaskIdNull;
Kelvin Zhang9dd93052020-07-21 17:31:19 -040088 CHECK_LE(sent_offset_, data_.size());
Amin Hassanid3f4bea2018-04-30 14:52:40 -070089 // Same here, we should not access any member variable after this call.
90 SendData(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +000091}
92
93// If the transfer is in progress, aborts the transfer early.
94// The transfer cannot be resumed.
95void MockHttpFetcher::TerminateTransfer() {
Darin Petkov9ce452b2010-11-17 14:33:28 -080096 LOG(INFO) << "Terminating transfer.";
Kelvin Zhang9dd93052020-07-21 17:31:19 -040097 // 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 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000106}
107
Alex Deymofdd6dec2016-03-03 22:35:43 -0800108void MockHttpFetcher::SetHeader(const std::string& header_name,
109 const std::string& header_value) {
110 extra_headers_[base::ToLowerASCII(header_name)] = header_value;
111}
112
Alex Deymo14ad88e2016-06-29 12:30:14 -0700113std::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
rspangler@google.com49fdf182009-10-10 00:57:34 +0000120void MockHttpFetcher::Pause() {
121 CHECK(!paused_);
122 paused_ = true;
Alex Deymo60ca1a72015-06-18 18:19:15 -0700123 MessageLoop::current()->CancelTask(timeout_id_);
124 timeout_id_ = MessageLoop::kTaskIdNull;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000125}
126
127void MockHttpFetcher::Unpause() {
128 CHECK(paused_) << "You must pause before unpause.";
129 paused_ = false;
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700130 SendData(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000131}
132
Darin Petkovedc522e2010-11-05 09:35:17 -0700133void MockHttpFetcher::FailTransfer(int http_response_code) {
134 fail_transfer_ = true;
135 http_response_code_ = http_response_code;
136}
137
138void 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
rspangler@google.com49fdf182009-10-10 00:57:34 +0000147} // namespace chromeos_update_engine