blob: 668d249af4ffa2e6d99c83042d740c79d2f7bf01 [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 Deymoc1c17b42015-11-23 03:53:15 -030023#include <base/time/time.h>
Kelvin Zhang9dd93052020-07-21 17:31:19 -040024#include <brillo/message_loops/message_loop.h>
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070025#include <gtest/gtest.h>
26
Kelvin Zhang0c184242024-10-25 11:19:27 -070027#include "update_engine/common/utils.h"
28
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070029// This is a mock implementation of HttpFetcher which is useful for testing.
rspangler@google.com49fdf182009-10-10 00:57:34 +000030
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070031using brillo::MessageLoop;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000032using std::min;
33
rspangler@google.com49fdf182009-10-10 00:57:34 +000034namespace chromeos_update_engine {
35
36MockHttpFetcher::~MockHttpFetcher() {
Amin Hassanib2689592019-01-13 17:04:28 -080037 CHECK(timeout_id_ == MessageLoop::kTaskIdNull)
38 << "Call TerminateTransfer() before dtor.";
rspangler@google.com49fdf182009-10-10 00:57:34 +000039}
40
41void MockHttpFetcher::BeginTransfer(const std::string& url) {
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070042 EXPECT_FALSE(never_use_);
Darin Petkovedc522e2010-11-05 09:35:17 -070043 if (fail_transfer_ || data_.empty()) {
44 // No data to send, just notify of completion..
45 SignalTransferComplete();
46 return;
47 }
Kelvin Zhang9dd93052020-07-21 17:31:19 -040048 if (sent_offset_ < data_.size())
rspangler@google.com49fdf182009-10-10 00:57:34 +000049 SendData(true);
50}
51
Amin Hassanid3f4bea2018-04-30 14:52:40 -070052void MockHttpFetcher::SendData(bool skip_delivery) {
Kelvin Zhang9dd93052020-07-21 17:31:19 -040053 if (fail_transfer_ || sent_offset_ == data_.size()) {
Darin Petkovedc522e2010-11-05 09:35:17 -070054 SignalTransferComplete();
Amin Hassanid3f4bea2018-04-30 14:52:40 -070055 return;
rspangler@google.com49fdf182009-10-10 00:57:34 +000056 }
57
58 if (paused_) {
Amin Hassanid3f4bea2018-04-30 14:52:40 -070059 // If we're paused, we should return so no callback is scheduled.
60 return;
rspangler@google.com49fdf182009-10-10 00:57:34 +000061 }
62
Amin Hassanid3f4bea2018-04-30 14:52:40 -070063 // Setup timeout callback even if the transfer is about to be completed in
64 // order to get a call to |TransferComplete|.
Kelvin Zhang9dd93052020-07-21 17:31:19 -040065 if (timeout_id_ == MessageLoop::kTaskIdNull && delay_) {
66 CHECK(MessageLoop::current());
Alex Deymo60ca1a72015-06-18 18:19:15 -070067 timeout_id_ = MessageLoop::current()->PostDelayedTask(
68 FROM_HERE,
69 base::Bind(&MockHttpFetcher::TimeoutCallback, base::Unretained(this)),
70 base::TimeDelta::FromMilliseconds(10));
rspangler@google.com49fdf182009-10-10 00:57:34 +000071 }
Amin Hassanid3f4bea2018-04-30 14:52:40 -070072
Kelvin Zhang9dd93052020-07-21 17:31:19 -040073 if (!skip_delivery || !delay_) {
Amin Hassanid3f4bea2018-04-30 14:52:40 -070074 const size_t chunk_size =
Kelvin Zhang9dd93052020-07-21 17:31:19 -040075 min(kMockHttpFetcherChunkSize, data_.size() - sent_offset_);
76 sent_offset_ += chunk_size;
77 bytes_sent_ += chunk_size;
Amin Hassanid3f4bea2018-04-30 14:52:40 -070078 CHECK(delegate_);
Kelvin Zhang9dd93052020-07-21 17:31:19 -040079 delegate_->ReceivedBytes(
80 this, &data_[sent_offset_ - chunk_size], chunk_size);
Amin Hassanid3f4bea2018-04-30 14:52:40 -070081 }
82 // We may get terminated and deleted right after |ReceivedBytes| call, so we
83 // should not access any class member variable after this call.
rspangler@google.com49fdf182009-10-10 00:57:34 +000084}
85
Alex Deymo60ca1a72015-06-18 18:19:15 -070086void MockHttpFetcher::TimeoutCallback() {
rspangler@google.com49fdf182009-10-10 00:57:34 +000087 CHECK(!paused_);
Amin Hassanid3f4bea2018-04-30 14:52:40 -070088 timeout_id_ = MessageLoop::kTaskIdNull;
Kelvin Zhang9dd93052020-07-21 17:31:19 -040089 CHECK_LE(sent_offset_, data_.size());
Amin Hassanid3f4bea2018-04-30 14:52:40 -070090 // Same here, we should not access any member variable after this call.
91 SendData(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +000092}
93
94// If the transfer is in progress, aborts the transfer early.
95// The transfer cannot be resumed.
96void MockHttpFetcher::TerminateTransfer() {
Darin Petkov9ce452b2010-11-17 14:33:28 -080097 LOG(INFO) << "Terminating transfer.";
Kelvin Zhang9dd93052020-07-21 17:31:19 -040098 // 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 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000107}
108
Alex Deymofdd6dec2016-03-03 22:35:43 -0800109void MockHttpFetcher::SetHeader(const std::string& header_name,
110 const std::string& header_value) {
Kelvin Zhang0c184242024-10-25 11:19:27 -0700111 extra_headers_[ToLower(header_name)] = header_value;
Alex Deymofdd6dec2016-03-03 22:35:43 -0800112}
113
Alex Deymo14ad88e2016-06-29 12:30:14 -0700114std::string MockHttpFetcher::GetHeader(const std::string& header_name) const {
Kelvin Zhang0c184242024-10-25 11:19:27 -0700115 const auto it = extra_headers_.find(ToLower(header_name));
Alex Deymo14ad88e2016-06-29 12:30:14 -0700116 if (it == extra_headers_.end())
117 return "";
118 return it->second;
119}
120
rspangler@google.com49fdf182009-10-10 00:57:34 +0000121void MockHttpFetcher::Pause() {
122 CHECK(!paused_);
123 paused_ = true;
Alex Deymo60ca1a72015-06-18 18:19:15 -0700124 MessageLoop::current()->CancelTask(timeout_id_);
125 timeout_id_ = MessageLoop::kTaskIdNull;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000126}
127
128void MockHttpFetcher::Unpause() {
129 CHECK(paused_) << "You must pause before unpause.";
130 paused_ = false;
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700131 SendData(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000132}
133
Darin Petkovedc522e2010-11-05 09:35:17 -0700134void MockHttpFetcher::FailTransfer(int http_response_code) {
135 fail_transfer_ = true;
136 http_response_code_ = http_response_code;
137}
138
139void 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
rspangler@google.com49fdf182009-10-10 00:57:34 +0000148} // namespace chromeos_update_engine