blob: b63389b96ead793aa490595e5e3f51a469d7aaaa [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
rspangler@google.com49fdf182009-10-10 00:57:34 +000017#include "update_engine/mock_http_fetcher.h"
18
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070019#include <algorithm>
20
21#include <base/logging.h>
22#include <gtest/gtest.h>
23
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070024// This is a mock implementation of HttpFetcher which is useful for testing.
rspangler@google.com49fdf182009-10-10 00:57:34 +000025
Alex Deymo60ca1a72015-06-18 18:19:15 -070026using chromeos::MessageLoop;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000027using std::min;
28
rspangler@google.com49fdf182009-10-10 00:57:34 +000029namespace chromeos_update_engine {
30
31MockHttpFetcher::~MockHttpFetcher() {
Alex Deymo60ca1a72015-06-18 18:19:15 -070032 CHECK(timeout_id_ == MessageLoop::kTaskIdNull) <<
33 "Call TerminateTransfer() before dtor.";
rspangler@google.com49fdf182009-10-10 00:57:34 +000034}
35
36void MockHttpFetcher::BeginTransfer(const std::string& url) {
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070037 EXPECT_FALSE(never_use_);
Darin Petkovedc522e2010-11-05 09:35:17 -070038 if (fail_transfer_ || data_.empty()) {
39 // No data to send, just notify of completion..
40 SignalTransferComplete();
41 return;
42 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000043 if (sent_size_ < data_.size())
44 SendData(true);
45}
46
Alex Deymo60ca1a72015-06-18 18:19:15 -070047// Returns false on one condition: If timeout_id_ was already set
48// and it needs to be deleted by the caller. If timeout_id_ is null
rspangler@google.com49fdf182009-10-10 00:57:34 +000049// when this function is called, this function will always return true.
50bool MockHttpFetcher::SendData(bool skip_delivery) {
Darin Petkovedc522e2010-11-05 09:35:17 -070051 if (fail_transfer_) {
52 SignalTransferComplete();
Alex Deymo60ca1a72015-06-18 18:19:15 -070053 return timeout_id_ != MessageLoop::kTaskIdNull;
Darin Petkovedc522e2010-11-05 09:35:17 -070054 }
55
rspangler@google.com49fdf182009-10-10 00:57:34 +000056 CHECK_LT(sent_size_, data_.size());
57 if (!skip_delivery) {
58 const size_t chunk_size = min(kMockHttpFetcherChunkSize,
59 data_.size() - sent_size_);
60 CHECK(delegate_);
61 delegate_->ReceivedBytes(this, &data_[sent_size_], chunk_size);
Darin Petkov9ce452b2010-11-17 14:33:28 -080062 // We may get terminated in the callback.
63 if (sent_size_ == data_.size()) {
64 LOG(INFO) << "Terminated in the ReceivedBytes callback.";
Alex Deymo60ca1a72015-06-18 18:19:15 -070065 return timeout_id_ != MessageLoop::kTaskIdNull;
Darin Petkov9ce452b2010-11-17 14:33:28 -080066 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000067 sent_size_ += chunk_size;
68 CHECK_LE(sent_size_, data_.size());
69 if (sent_size_ == data_.size()) {
Darin Petkovcb466212010-08-26 09:40:11 -070070 // We've sent all the data. Notify of success.
Darin Petkovedc522e2010-11-05 09:35:17 -070071 SignalTransferComplete();
rspangler@google.com49fdf182009-10-10 00:57:34 +000072 }
73 }
74
75 if (paused_) {
Alex Deymo60ca1a72015-06-18 18:19:15 -070076 // If we're paused, we should return true if timeout_id_ is set,
rspangler@google.com49fdf182009-10-10 00:57:34 +000077 // since we need the caller to delete it.
Alex Deymo60ca1a72015-06-18 18:19:15 -070078 return timeout_id_ != MessageLoop::kTaskIdNull;
rspangler@google.com49fdf182009-10-10 00:57:34 +000079 }
80
Alex Deymo60ca1a72015-06-18 18:19:15 -070081 if (timeout_id_ != MessageLoop::kTaskIdNull) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000082 // we still need a timeout if there's more data to send
83 return sent_size_ < data_.size();
84 } else if (sent_size_ < data_.size()) {
85 // we don't have a timeout source and we need one
Alex Deymo60ca1a72015-06-18 18:19:15 -070086 timeout_id_ = MessageLoop::current()->PostDelayedTask(
87 FROM_HERE,
88 base::Bind(&MockHttpFetcher::TimeoutCallback, base::Unretained(this)),
89 base::TimeDelta::FromMilliseconds(10));
rspangler@google.com49fdf182009-10-10 00:57:34 +000090 }
91 return true;
92}
93
Alex Deymo60ca1a72015-06-18 18:19:15 -070094void MockHttpFetcher::TimeoutCallback() {
rspangler@google.com49fdf182009-10-10 00:57:34 +000095 CHECK(!paused_);
Alex Deymo60ca1a72015-06-18 18:19:15 -070096 if (SendData(false)) {
97 // We need to re-schedule the timeout.
98 timeout_id_ = MessageLoop::current()->PostDelayedTask(
99 FROM_HERE,
100 base::Bind(&MockHttpFetcher::TimeoutCallback, base::Unretained(this)),
101 base::TimeDelta::FromMilliseconds(10));
102 } else {
103 timeout_id_ = MessageLoop::kTaskIdNull;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000104 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000105}
106
107// If the transfer is in progress, aborts the transfer early.
108// The transfer cannot be resumed.
109void MockHttpFetcher::TerminateTransfer() {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800110 LOG(INFO) << "Terminating transfer.";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000111 sent_size_ = data_.size();
Alex Deymo60ca1a72015-06-18 18:19:15 -0700112 // Kill any timeout, it is ok to call with kTaskIdNull.
113 MessageLoop::current()->CancelTask(timeout_id_);
114 timeout_id_ = MessageLoop::kTaskIdNull;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800115 delegate_->TransferTerminated(this);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000116}
117
118void MockHttpFetcher::Pause() {
119 CHECK(!paused_);
120 paused_ = true;
Alex Deymo60ca1a72015-06-18 18:19:15 -0700121 MessageLoop::current()->CancelTask(timeout_id_);
122 timeout_id_ = MessageLoop::kTaskIdNull;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000123}
124
125void MockHttpFetcher::Unpause() {
126 CHECK(paused_) << "You must pause before unpause.";
127 paused_ = false;
128 if (sent_size_ < data_.size()) {
129 SendData(false);
130 }
131}
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