| Alex Deymo | aea4c1c | 2015-08-19 20:24:43 -0700 | [diff] [blame] | 1 | // | 
 | 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.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 16 |  | 
| Alex Deymo | 39910dc | 2015-11-09 17:04:30 -0800 | [diff] [blame] | 17 | #include "update_engine/common/mock_http_fetcher.h" | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 18 |  | 
| Andrew de los Reyes | 173e63c | 2011-04-04 17:19:57 -0700 | [diff] [blame] | 19 | #include <algorithm> | 
 | 20 |  | 
| Alex Deymo | c1c17b4 | 2015-11-23 03:53:15 -0300 | [diff] [blame] | 21 | #include <base/bind.h> | 
| Andrew de los Reyes | 173e63c | 2011-04-04 17:19:57 -0700 | [diff] [blame] | 22 | #include <base/logging.h> | 
| Alex Deymo | fdd6dec | 2016-03-03 22:35:43 -0800 | [diff] [blame] | 23 | #include <base/strings/string_util.h> | 
| Alex Deymo | c1c17b4 | 2015-11-23 03:53:15 -0300 | [diff] [blame] | 24 | #include <base/time/time.h> | 
| Andrew de los Reyes | 173e63c | 2011-04-04 17:19:57 -0700 | [diff] [blame] | 25 | #include <gtest/gtest.h> | 
 | 26 |  | 
| Andrew de los Reyes | 173e63c | 2011-04-04 17:19:57 -0700 | [diff] [blame] | 27 | // This is a mock implementation of HttpFetcher which is useful for testing. | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 28 |  | 
| Alex Vakulenko | 3f39d5c | 2015-10-13 09:27:13 -0700 | [diff] [blame] | 29 | using brillo::MessageLoop; | 
| adlr@google.com | c98a7ed | 2009-12-04 18:54:03 +0000 | [diff] [blame] | 30 | using std::min; | 
 | 31 |  | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 32 | namespace chromeos_update_engine { | 
 | 33 |  | 
 | 34 | MockHttpFetcher::~MockHttpFetcher() { | 
| Alex Deymo | 60ca1a7 | 2015-06-18 18:19:15 -0700 | [diff] [blame] | 35 |   CHECK(timeout_id_ == MessageLoop::kTaskIdNull) << | 
 | 36 |       "Call TerminateTransfer() before dtor."; | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 37 | } | 
 | 38 |  | 
 | 39 | void MockHttpFetcher::BeginTransfer(const std::string& url) { | 
| Andrew de los Reyes | 173e63c | 2011-04-04 17:19:57 -0700 | [diff] [blame] | 40 |   EXPECT_FALSE(never_use_); | 
| Darin Petkov | edc522e | 2010-11-05 09:35:17 -0700 | [diff] [blame] | 41 |   if (fail_transfer_ || data_.empty()) { | 
 | 42 |     // No data to send, just notify of completion.. | 
 | 43 |     SignalTransferComplete(); | 
 | 44 |     return; | 
 | 45 |   } | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 46 |   if (sent_size_ < data_.size()) | 
 | 47 |     SendData(true); | 
 | 48 | } | 
 | 49 |  | 
| Amin Hassani | d3f4bea | 2018-04-30 14:52:40 -0700 | [diff] [blame] | 50 | void MockHttpFetcher::SendData(bool skip_delivery) { | 
 | 51 |   if (fail_transfer_ || sent_size_ == data_.size()) { | 
| Darin Petkov | edc522e | 2010-11-05 09:35:17 -0700 | [diff] [blame] | 52 |     SignalTransferComplete(); | 
| Amin Hassani | d3f4bea | 2018-04-30 14:52:40 -0700 | [diff] [blame] | 53 |     return; | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 54 |   } | 
 | 55 |  | 
 | 56 |   if (paused_) { | 
| Amin Hassani | d3f4bea | 2018-04-30 14:52:40 -0700 | [diff] [blame] | 57 |     // If we're paused, we should return so no callback is scheduled. | 
 | 58 |     return; | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 59 |   } | 
 | 60 |  | 
| Amin Hassani | d3f4bea | 2018-04-30 14:52:40 -0700 | [diff] [blame] | 61 |   // Setup timeout callback even if the transfer is about to be completed in | 
 | 62 |   // order to get a call to |TransferComplete|. | 
 | 63 |   if (timeout_id_ == MessageLoop::kTaskIdNull) { | 
| Alex Deymo | 60ca1a7 | 2015-06-18 18:19:15 -0700 | [diff] [blame] | 64 |     timeout_id_ = MessageLoop::current()->PostDelayedTask( | 
 | 65 |         FROM_HERE, | 
 | 66 |         base::Bind(&MockHttpFetcher::TimeoutCallback, base::Unretained(this)), | 
 | 67 |         base::TimeDelta::FromMilliseconds(10)); | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 68 |   } | 
| Amin Hassani | d3f4bea | 2018-04-30 14:52:40 -0700 | [diff] [blame] | 69 |  | 
 | 70 |   if (!skip_delivery) { | 
 | 71 |     const size_t chunk_size = | 
 | 72 |         min(kMockHttpFetcherChunkSize, data_.size() - sent_size_); | 
 | 73 |     sent_size_ += chunk_size; | 
 | 74 |     CHECK(delegate_); | 
 | 75 |     delegate_->ReceivedBytes(this, &data_[sent_size_ - chunk_size], chunk_size); | 
 | 76 |   } | 
 | 77 |   // We may get terminated and deleted right after |ReceivedBytes| call, so we | 
 | 78 |   // should not access any class member variable after this call. | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 79 | } | 
 | 80 |  | 
| Alex Deymo | 60ca1a7 | 2015-06-18 18:19:15 -0700 | [diff] [blame] | 81 | void MockHttpFetcher::TimeoutCallback() { | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 82 |   CHECK(!paused_); | 
| Amin Hassani | d3f4bea | 2018-04-30 14:52:40 -0700 | [diff] [blame] | 83 |   timeout_id_ = MessageLoop::kTaskIdNull; | 
 | 84 |   CHECK_LE(sent_size_, data_.size()); | 
 | 85 |   // Same here, we should not access any member variable after this call. | 
 | 86 |   SendData(false); | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 87 | } | 
 | 88 |  | 
 | 89 | // If the transfer is in progress, aborts the transfer early. | 
 | 90 | // The transfer cannot be resumed. | 
 | 91 | void MockHttpFetcher::TerminateTransfer() { | 
| Darin Petkov | 9ce452b | 2010-11-17 14:33:28 -0800 | [diff] [blame] | 92 |   LOG(INFO) << "Terminating transfer."; | 
| Alex Deymo | 60ca1a7 | 2015-06-18 18:19:15 -0700 | [diff] [blame] | 93 |   // Kill any timeout, it is ok to call with kTaskIdNull. | 
 | 94 |   MessageLoop::current()->CancelTask(timeout_id_); | 
 | 95 |   timeout_id_ = MessageLoop::kTaskIdNull; | 
| Darin Petkov | 9ce452b | 2010-11-17 14:33:28 -0800 | [diff] [blame] | 96 |   delegate_->TransferTerminated(this); | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 97 | } | 
 | 98 |  | 
| Alex Deymo | fdd6dec | 2016-03-03 22:35:43 -0800 | [diff] [blame] | 99 | void MockHttpFetcher::SetHeader(const std::string& header_name, | 
 | 100 |                                 const std::string& header_value) { | 
 | 101 |   extra_headers_[base::ToLowerASCII(header_name)] = header_value; | 
 | 102 | } | 
 | 103 |  | 
| Alex Deymo | 14ad88e | 2016-06-29 12:30:14 -0700 | [diff] [blame] | 104 | std::string MockHttpFetcher::GetHeader(const std::string& header_name) const { | 
 | 105 |   const auto it = extra_headers_.find(base::ToLowerASCII(header_name)); | 
 | 106 |   if (it == extra_headers_.end()) | 
 | 107 |     return ""; | 
 | 108 |   return it->second; | 
 | 109 | } | 
 | 110 |  | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 111 | void MockHttpFetcher::Pause() { | 
 | 112 |   CHECK(!paused_); | 
 | 113 |   paused_ = true; | 
| Alex Deymo | 60ca1a7 | 2015-06-18 18:19:15 -0700 | [diff] [blame] | 114 |   MessageLoop::current()->CancelTask(timeout_id_); | 
 | 115 |   timeout_id_ = MessageLoop::kTaskIdNull; | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 116 | } | 
 | 117 |  | 
 | 118 | void MockHttpFetcher::Unpause() { | 
 | 119 |   CHECK(paused_) << "You must pause before unpause."; | 
 | 120 |   paused_ = false; | 
| Amin Hassani | d3f4bea | 2018-04-30 14:52:40 -0700 | [diff] [blame] | 121 |   SendData(false); | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 122 | } | 
 | 123 |  | 
| Darin Petkov | edc522e | 2010-11-05 09:35:17 -0700 | [diff] [blame] | 124 | void MockHttpFetcher::FailTransfer(int http_response_code) { | 
 | 125 |   fail_transfer_ = true; | 
 | 126 |   http_response_code_ = http_response_code; | 
 | 127 | } | 
 | 128 |  | 
 | 129 | void MockHttpFetcher::SignalTransferComplete() { | 
 | 130 |   // If the transfer has been failed, the HTTP response code should be set | 
 | 131 |   // already. | 
 | 132 |   if (!fail_transfer_) { | 
 | 133 |     http_response_code_ = 200; | 
 | 134 |   } | 
 | 135 |   delegate_->TransferComplete(this, !fail_transfer_); | 
 | 136 | } | 
 | 137 |  | 
| rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 138 | }  // namespace chromeos_update_engine |