blob: a8dd1aee5b7ba09b097e034045d12df1ee160573 [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
rspangler@google.com49fdf182009-10-10 00:57:34 +00005#include "update_engine/mock_http_fetcher.h"
6
Andrew de los Reyes173e63c2011-04-04 17:19:57 -07007#include <algorithm>
8
9#include <base/logging.h>
10#include <gtest/gtest.h>
11
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070012// This is a mock implementation of HttpFetcher which is useful for testing.
rspangler@google.com49fdf182009-10-10 00:57:34 +000013
Alex Deymo60ca1a72015-06-18 18:19:15 -070014using chromeos::MessageLoop;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000015using std::min;
16
rspangler@google.com49fdf182009-10-10 00:57:34 +000017namespace chromeos_update_engine {
18
19MockHttpFetcher::~MockHttpFetcher() {
Alex Deymo60ca1a72015-06-18 18:19:15 -070020 CHECK(timeout_id_ == MessageLoop::kTaskIdNull) <<
21 "Call TerminateTransfer() before dtor.";
rspangler@google.com49fdf182009-10-10 00:57:34 +000022}
23
24void MockHttpFetcher::BeginTransfer(const std::string& url) {
Andrew de los Reyes173e63c2011-04-04 17:19:57 -070025 EXPECT_FALSE(never_use_);
Darin Petkovedc522e2010-11-05 09:35:17 -070026 if (fail_transfer_ || data_.empty()) {
27 // No data to send, just notify of completion..
28 SignalTransferComplete();
29 return;
30 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000031 if (sent_size_ < data_.size())
32 SendData(true);
33}
34
Alex Deymo60ca1a72015-06-18 18:19:15 -070035// Returns false on one condition: If timeout_id_ was already set
36// and it needs to be deleted by the caller. If timeout_id_ is null
rspangler@google.com49fdf182009-10-10 00:57:34 +000037// when this function is called, this function will always return true.
38bool MockHttpFetcher::SendData(bool skip_delivery) {
Darin Petkovedc522e2010-11-05 09:35:17 -070039 if (fail_transfer_) {
40 SignalTransferComplete();
Alex Deymo60ca1a72015-06-18 18:19:15 -070041 return timeout_id_ != MessageLoop::kTaskIdNull;
Darin Petkovedc522e2010-11-05 09:35:17 -070042 }
43
rspangler@google.com49fdf182009-10-10 00:57:34 +000044 CHECK_LT(sent_size_, data_.size());
45 if (!skip_delivery) {
46 const size_t chunk_size = min(kMockHttpFetcherChunkSize,
47 data_.size() - sent_size_);
48 CHECK(delegate_);
49 delegate_->ReceivedBytes(this, &data_[sent_size_], chunk_size);
Darin Petkov9ce452b2010-11-17 14:33:28 -080050 // We may get terminated in the callback.
51 if (sent_size_ == data_.size()) {
52 LOG(INFO) << "Terminated in the ReceivedBytes callback.";
Alex Deymo60ca1a72015-06-18 18:19:15 -070053 return timeout_id_ != MessageLoop::kTaskIdNull;
Darin Petkov9ce452b2010-11-17 14:33:28 -080054 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000055 sent_size_ += chunk_size;
56 CHECK_LE(sent_size_, data_.size());
57 if (sent_size_ == data_.size()) {
Darin Petkovcb466212010-08-26 09:40:11 -070058 // We've sent all the data. Notify of success.
Darin Petkovedc522e2010-11-05 09:35:17 -070059 SignalTransferComplete();
rspangler@google.com49fdf182009-10-10 00:57:34 +000060 }
61 }
62
63 if (paused_) {
Alex Deymo60ca1a72015-06-18 18:19:15 -070064 // If we're paused, we should return true if timeout_id_ is set,
rspangler@google.com49fdf182009-10-10 00:57:34 +000065 // since we need the caller to delete it.
Alex Deymo60ca1a72015-06-18 18:19:15 -070066 return timeout_id_ != MessageLoop::kTaskIdNull;
rspangler@google.com49fdf182009-10-10 00:57:34 +000067 }
68
Alex Deymo60ca1a72015-06-18 18:19:15 -070069 if (timeout_id_ != MessageLoop::kTaskIdNull) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000070 // we still need a timeout if there's more data to send
71 return sent_size_ < data_.size();
72 } else if (sent_size_ < data_.size()) {
73 // we don't have a timeout source and we need one
Alex Deymo60ca1a72015-06-18 18:19:15 -070074 timeout_id_ = MessageLoop::current()->PostDelayedTask(
75 FROM_HERE,
76 base::Bind(&MockHttpFetcher::TimeoutCallback, base::Unretained(this)),
77 base::TimeDelta::FromMilliseconds(10));
rspangler@google.com49fdf182009-10-10 00:57:34 +000078 }
79 return true;
80}
81
Alex Deymo60ca1a72015-06-18 18:19:15 -070082void MockHttpFetcher::TimeoutCallback() {
rspangler@google.com49fdf182009-10-10 00:57:34 +000083 CHECK(!paused_);
Alex Deymo60ca1a72015-06-18 18:19:15 -070084 if (SendData(false)) {
85 // We need to re-schedule the timeout.
86 timeout_id_ = MessageLoop::current()->PostDelayedTask(
87 FROM_HERE,
88 base::Bind(&MockHttpFetcher::TimeoutCallback, base::Unretained(this)),
89 base::TimeDelta::FromMilliseconds(10));
90 } else {
91 timeout_id_ = MessageLoop::kTaskIdNull;
rspangler@google.com49fdf182009-10-10 00:57:34 +000092 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000093}
94
95// If the transfer is in progress, aborts the transfer early.
96// The transfer cannot be resumed.
97void MockHttpFetcher::TerminateTransfer() {
Darin Petkov9ce452b2010-11-17 14:33:28 -080098 LOG(INFO) << "Terminating transfer.";
rspangler@google.com49fdf182009-10-10 00:57:34 +000099 sent_size_ = data_.size();
Alex Deymo60ca1a72015-06-18 18:19:15 -0700100 // Kill any timeout, it is ok to call with kTaskIdNull.
101 MessageLoop::current()->CancelTask(timeout_id_);
102 timeout_id_ = MessageLoop::kTaskIdNull;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800103 delegate_->TransferTerminated(this);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000104}
105
106void MockHttpFetcher::Pause() {
107 CHECK(!paused_);
108 paused_ = true;
Alex Deymo60ca1a72015-06-18 18:19:15 -0700109 MessageLoop::current()->CancelTask(timeout_id_);
110 timeout_id_ = MessageLoop::kTaskIdNull;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000111}
112
113void MockHttpFetcher::Unpause() {
114 CHECK(paused_) << "You must pause before unpause.";
115 paused_ = false;
116 if (sent_size_ < data_.size()) {
117 SendData(false);
118 }
119}
120
Darin Petkovedc522e2010-11-05 09:35:17 -0700121void MockHttpFetcher::FailTransfer(int http_response_code) {
122 fail_transfer_ = true;
123 http_response_code_ = http_response_code;
124}
125
126void MockHttpFetcher::SignalTransferComplete() {
127 // If the transfer has been failed, the HTTP response code should be set
128 // already.
129 if (!fail_transfer_) {
130 http_response_code_ = 200;
131 }
132 delegate_->TransferComplete(this, !fail_transfer_);
133}
134
rspangler@google.com49fdf182009-10-10 00:57:34 +0000135} // namespace chromeos_update_engine