blob: f2f127272d8de5c0fafa8895e7b665e9986d49a7 [file] [log] [blame]
Mike Frysinger8155d082012-04-06 15:23:18 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
rspangler@google.com49fdf182009-10-10 00:57:34 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <unistd.h>
Darin Petkov41c2fcf2010-08-25 13:14:48 -07006
adlr@google.comc98a7ed2009-12-04 18:54:03 +00007#include <string>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07008#include <utility>
adlr@google.comc98a7ed2009-12-04 18:54:03 +00009#include <vector>
Darin Petkov41c2fcf2010-08-25 13:14:48 -070010
Andrew de los Reyes45168102010-11-22 11:13:50 -080011#include <base/logging.h>
Chris Masoned903c3b2011-05-12 15:35:46 -070012#include <base/memory/scoped_ptr.h>
Andrew de los Reyes45168102010-11-22 11:13:50 -080013#include <base/string_util.h>
Mike Frysinger8155d082012-04-06 15:23:18 -040014#include <base/stringprintf.h>
Jay Srinivasan43488792012-06-19 00:25:31 -070015#include <chromeos/dbus/service_constants.h>
Andrew de los Reyes45168102010-11-22 11:13:50 -080016#include <glib.h>
17#include <gtest/gtest.h>
18
Gilad Arnold9bedeb52011-11-17 16:19:57 -080019#include "update_engine/http_common.h"
20#include "update_engine/http_fetcher_unittest.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000021#include "update_engine/libcurl_http_fetcher.h"
Jay Srinivasan43488792012-06-19 00:25:31 -070022#include "update_engine/mock_connection_manager.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000023#include "update_engine/mock_http_fetcher.h"
Jay Srinivasan08fce042012-06-07 16:31:01 -070024#include "update_engine/mock_system_state.h"
Andrew de los Reyes819fef22010-12-17 11:33:58 -080025#include "update_engine/multi_range_http_fetcher.h"
Andrew de los Reyes45168102010-11-22 11:13:50 -080026#include "update_engine/proxy_resolver.h"
Jay Srinivasan08fce042012-06-07 16:31:01 -070027#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000028
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070029using std::make_pair;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080030using std::pair;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000031using std::string;
32using std::vector;
33
Jay Srinivasan43488792012-06-19 00:25:31 -070034using testing::_;
35using testing::SetArgumentPointee;
36using testing::DoAll;
37using testing::Return;
38
Gilad Arnold9bedeb52011-11-17 16:19:57 -080039namespace {
40
41const int kBigLength = 100000;
42const int kMediumLength = 1000;
Gilad Arnold34bf1ee2012-02-09 16:16:02 -080043const int kFlakyTruncateLength = 29000;
44const int kFlakySleepEvery = 3;
Gilad Arnold9bedeb52011-11-17 16:19:57 -080045const int kFlakySleepSecs = 10;
46
47} // namespace
48
rspangler@google.com49fdf182009-10-10 00:57:34 +000049namespace chromeos_update_engine {
50
Gilad Arnold9bedeb52011-11-17 16:19:57 -080051static const char *kUnusedUrl = "unused://unused";
52
53static inline string LocalServerUrlForPath(const string& path) {
Jay Srinivasan43488792012-06-19 00:25:31 -070054 return base::StringPrintf("http://127.0.0.1:%d%s", kServerPort, path.c_str());
rspangler@google.com49fdf182009-10-10 00:57:34 +000055}
56
Gilad Arnold9bedeb52011-11-17 16:19:57 -080057//
58// Class hierarchy for HTTP server implementations.
59//
60
61class HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000062 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080063 // This makes it an abstract class (dirty but works).
64 virtual ~HttpServer() = 0;
65
rspangler@google.com49fdf182009-10-10 00:57:34 +000066 bool started_;
67};
68
Gilad Arnold9bedeb52011-11-17 16:19:57 -080069HttpServer::~HttpServer() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000070
Gilad Arnold9bedeb52011-11-17 16:19:57 -080071
72class NullHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000073 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080074 NullHttpServer() {
75 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000076 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000077};
78
Gilad Arnold9bedeb52011-11-17 16:19:57 -080079
80class PythonHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000081 public:
82 PythonHttpServer() {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000083 char *argv[2] = {strdup("./test_http_server"), NULL};
rspangler@google.com49fdf182009-10-10 00:57:34 +000084 GError *err;
85 started_ = false;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070086 validate_quit_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000087 if (!g_spawn_async(NULL,
88 argv,
89 NULL,
90 G_SPAWN_DO_NOT_REAP_CHILD,
91 NULL,
92 NULL,
93 &pid_,
94 &err)) {
95 return;
96 }
97 int rc = 1;
Andrew de los Reyese7dcc2a2011-08-19 10:50:37 -070098 const uint64_t kMaxSleep = 60UL * 60UL * 1000UL * 1000UL; // 60 min
99 uint64_t timeout = 15 * 1000; // 15 ms
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700100 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000101 while (0 != rc) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700102 LOG(INFO) << "running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000103 rc = system((string("wget --output-document=/dev/null ") +
104 LocalServerUrlForPath("/test")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700105 LOG(INFO) << "done running wget to start";
Josh Horwich2d4e1c52011-08-22 11:58:02 -0700106 if (0 != rc) {
107 if (timeout > kMaxSleep) {
108 LOG(ERROR) << "Unable to start server.";
109 started_ = false;
110 break;
111 }
112 if (timeout < (1000 * 1000)) // sub 1-second sleep, use usleep
113 usleep(static_cast<useconds_t>(timeout));
114 else
115 sleep(static_cast<unsigned int>(timeout / (1000 * 1000)));
116 timeout *= 2;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700117 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000118 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000119 free(argv[0]);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700120 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000121 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800122
rspangler@google.com49fdf182009-10-10 00:57:34 +0000123 ~PythonHttpServer() {
124 if (!started_)
125 return;
126 // request that the server exit itself
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700127 LOG(INFO) << "running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700128 int rc = system((string("wget -t 1 --output-document=/dev/null ") +
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700129 LocalServerUrlForPath("/quitquitquit")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700130 LOG(INFO) << "done running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700131 if (validate_quit_)
132 EXPECT_EQ(0, rc);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000133 waitpid(pid_, NULL, 0);
134 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800135
rspangler@google.com49fdf182009-10-10 00:57:34 +0000136 GPid pid_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700137 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000138};
139
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800140//
141// Class hierarchy for HTTP fetcher test wrappers.
142//
143
144class AnyHttpFetcherTest {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000145 public:
Jay Srinivasan43488792012-06-19 00:25:31 -0700146 AnyHttpFetcherTest()
147 : mock_connection_manager_(&mock_system_state_) {
148 mock_system_state_.SetConnectionManager(&mock_connection_manager_);
149 }
150
151 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) = 0;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800152 HttpFetcher* NewLargeFetcher() {
153 return NewLargeFetcher(1);
154 }
155
156 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) = 0;
157 HttpFetcher* NewSmallFetcher() {
158 return NewSmallFetcher(1);
159 }
160
161 virtual string BigUrl() const { return kUnusedUrl; }
162 virtual string SmallUrl() const { return kUnusedUrl; }
163 virtual string ErrorUrl() const { return kUnusedUrl; }
164
165 virtual bool IsMock() const = 0;
166 virtual bool IsMulti() const = 0;
167
168 virtual void IgnoreServerAborting(HttpServer* server) const {}
169
170 virtual HttpServer *CreateServer() = 0;
171
172 protected:
173 DirectProxyResolver proxy_resolver_;
Jay Srinivasan43488792012-06-19 00:25:31 -0700174 MockSystemState mock_system_state_;
175 MockConnectionManager mock_connection_manager_;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800176};
177
178class MockHttpFetcherTest : public AnyHttpFetcherTest {
179 public:
180 // Necessary to unhide the definition in the base class.
181 using AnyHttpFetcherTest::NewLargeFetcher;
182 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
183 vector<char> big_data(1000000);
184 CHECK(num_proxies > 0);
185 proxy_resolver_.set_num_proxies(num_proxies);
186 return new MockHttpFetcher(
187 big_data.data(),
188 big_data.size(),
189 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
190 }
191
192 // Necessary to unhide the definition in the base class.
193 using AnyHttpFetcherTest::NewSmallFetcher;
194 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
195 CHECK(num_proxies > 0);
196 proxy_resolver_.set_num_proxies(num_proxies);
197 return new MockHttpFetcher(
198 "x",
199 1,
200 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
201 }
202
203 virtual bool IsMock() const { return true; }
204 virtual bool IsMulti() const { return false; }
205
206 virtual HttpServer *CreateServer() {
207 return new NullHttpServer;
208 }
209};
210
211class LibcurlHttpFetcherTest : public AnyHttpFetcherTest {
212 public:
213 // Necessary to unhide the definition in the base class.
214 using AnyHttpFetcherTest::NewLargeFetcher;
215 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
216 CHECK(num_proxies > 0);
217 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes45168102010-11-22 11:13:50 -0800218 LibcurlHttpFetcher *ret = new
Jay Srinivasan08fce042012-06-07 16:31:01 -0700219 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_),
220 &mock_system_state_);
Darin Petkovb83371f2010-08-17 09:34:49 -0700221 // Speed up test execution.
222 ret->set_idle_seconds(1);
223 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700224 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000225 return ret;
226 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800227
228 // Necessary to unhide the definition in the base class.
229 using AnyHttpFetcherTest::NewSmallFetcher;
230 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
231 return NewLargeFetcher(num_proxies);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000232 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800233
234 virtual string BigUrl() const {
235 return LocalServerUrlForPath(base::StringPrintf("/download/%d",
236 kBigLength));
rspangler@google.com49fdf182009-10-10 00:57:34 +0000237 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800238 virtual string SmallUrl() const {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000239 return LocalServerUrlForPath("/foo");
240 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800241 virtual string ErrorUrl() const {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800242 return LocalServerUrlForPath("/error");
243 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800244
245 virtual bool IsMock() const { return false; }
246 virtual bool IsMulti() const { return false; }
247
248 virtual void IgnoreServerAborting(HttpServer* server) const {
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700249 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
250 pyserver->validate_quit_ = false;
251 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800252
253 virtual HttpServer *CreateServer() {
254 return new PythonHttpServer;
255 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000256};
257
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800258class MultiRangeHttpFetcherTest : public LibcurlHttpFetcherTest {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700259 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800260 // Necessary to unhide the definition in the base class.
261 using AnyHttpFetcherTest::NewLargeFetcher;
262 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
263 CHECK(num_proxies > 0);
264 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800265 ProxyResolver* resolver =
266 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
Jay Srinivasan08fce042012-06-07 16:31:01 -0700267 MultiRangeHttpFetcher *ret = new MultiRangeHttpFetcher(
268 new LibcurlHttpFetcher(resolver, &mock_system_state_));
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800269 ret->ClearRanges();
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800270 ret->AddRange(0);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700271 // Speed up test execution.
272 ret->set_idle_seconds(1);
273 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700274 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700275 return ret;
276 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800277
278 // Necessary to unhide the definition in the base class.
279 using AnyHttpFetcherTest::NewSmallFetcher;
280 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
281 return NewLargeFetcher(num_proxies);
282 }
283
284 virtual bool IsMulti() const { return true; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700285};
286
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800287
288//
289// Infrastructure for type tests of HTTP fetcher.
290// See: http://code.google.com/p/googletest/wiki/AdvancedGuide#Typed_Tests
291//
292
293// Fixture class template. We use an explicit constraint to guarantee that it
294// can only be instantiated with an AnyHttpFetcherTest type, see:
295// http://www2.research.att.com/~bs/bs_faq2.html#constraints
296template <typename T>
297class HttpFetcherTest : public ::testing::Test {
298 public:
299 T test_;
300
301 private:
302 static void TypeConstraint(T *a) {
303 AnyHttpFetcherTest *b = a;
304 }
305};
306
307// Test case types list.
308typedef ::testing::Types<LibcurlHttpFetcherTest,
309 MockHttpFetcherTest,
310 MultiRangeHttpFetcherTest> HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000311TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
312
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800313
rspangler@google.com49fdf182009-10-10 00:57:34 +0000314namespace {
315class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000316 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800317 HttpFetcherTestDelegate() :
Gilad Arnold48085ba2011-11-16 09:36:08 -0800318 is_expect_error_(false), times_transfer_complete_called_(0),
319 times_transfer_terminated_called_(0), times_received_bytes_called_(0) {}
320
rspangler@google.com49fdf182009-10-10 00:57:34 +0000321 virtual void ReceivedBytes(HttpFetcher* fetcher,
322 const char* bytes, int length) {
323 char str[length + 1];
324 memset(str, 0, length + 1);
325 memcpy(str, bytes, length);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800326
327 // Update counters
328 times_received_bytes_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000329 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800330
rspangler@google.com49fdf182009-10-10 00:57:34 +0000331 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800332 if (is_expect_error_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800333 EXPECT_EQ(kHttpResponseNotFound, fetcher->http_response_code());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800334 else
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800335 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000336 g_main_loop_quit(loop_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800337
338 // Update counter
339 times_transfer_complete_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000340 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800341
Darin Petkov9ce452b2010-11-17 14:33:28 -0800342 virtual void TransferTerminated(HttpFetcher* fetcher) {
343 ADD_FAILURE();
Gilad Arnold48085ba2011-11-16 09:36:08 -0800344 times_transfer_terminated_called_++;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800345 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800346
rspangler@google.com49fdf182009-10-10 00:57:34 +0000347 GMainLoop* loop_;
Gilad Arnold48085ba2011-11-16 09:36:08 -0800348
349 // Are we expecting an error response? (default: no)
350 bool is_expect_error_;
351
352 // Counters for callback invocations.
353 int times_transfer_complete_called_;
354 int times_transfer_terminated_called_;
355 int times_received_bytes_called_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000356};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000357
358struct StartTransferArgs {
359 HttpFetcher *http_fetcher;
360 string url;
361};
362
363gboolean StartTransfer(gpointer data) {
364 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
365 args->http_fetcher->BeginTransfer(args->url);
366 return FALSE;
367}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000368} // namespace {}
369
370TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700371 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000372 {
373 HttpFetcherTestDelegate delegate;
374 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800375 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000376 fetcher->set_delegate(&delegate);
377
Jay Srinivasan43488792012-06-19 00:25:31 -0700378 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
379 fetcher->GetSystemState()->GetConnectionManager());
380 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
381 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetWifi), Return(true)));
382 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetWifi))
383 .WillRepeatedly(Return(true));
384 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetWifi))
385 .WillRepeatedly(Return(flimflam::kTypeWifi));
386
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800387 scoped_ptr<HttpServer> server(this->test_.CreateServer());
388 ASSERT_TRUE(server->started_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000389
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800390 StartTransferArgs start_xfer_args = {fetcher.get(), this->test_.SmallUrl()};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000391
392 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000393 g_main_loop_run(loop);
394 }
395 g_main_loop_unref(loop);
396}
397
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700398TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700399 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700400 {
401 HttpFetcherTestDelegate delegate;
402 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800403 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700404 fetcher->set_delegate(&delegate);
405
Jay Srinivasan43488792012-06-19 00:25:31 -0700406 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
407 fetcher->GetSystemState()->GetConnectionManager());
408 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
409 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetEthernet), Return(true)));
410 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetEthernet))
411 .WillRepeatedly(Return(true));
412 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetEthernet))
413 .WillRepeatedly(Return(flimflam::kTypeEthernet));
414
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800415 scoped_ptr<HttpServer> server(this->test_.CreateServer());
416 ASSERT_TRUE(server->started_);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700417
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800418 StartTransferArgs start_xfer_args = {fetcher.get(), this->test_.BigUrl()};
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700419
420 g_timeout_add(0, StartTransfer, &start_xfer_args);
421 g_main_loop_run(loop);
422 }
423 g_main_loop_unref(loop);
424}
425
Gilad Arnold48085ba2011-11-16 09:36:08 -0800426// Issue #9648: when server returns an error HTTP response, the fetcher needs to
427// terminate transfer prematurely, rather than try to process the error payload.
428TYPED_TEST(HttpFetcherTest, ErrorTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800429 if (this->test_.IsMock() || this->test_.IsMulti())
Gilad Arnold48085ba2011-11-16 09:36:08 -0800430 return;
431 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
432 {
433 HttpFetcherTestDelegate delegate;
434 delegate.loop_ = loop;
435
436 // Delegate should expect an error response.
437 delegate.is_expect_error_ = true;
438
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800439 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800440 fetcher->set_delegate(&delegate);
441
Jay Srinivasan43488792012-06-19 00:25:31 -0700442 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
443 fetcher->GetSystemState()->GetConnectionManager());
444 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
445 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetWimax), Return(true)));
446 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetWimax))
447 .WillRepeatedly(Return(true));
448 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetWimax))
449 .WillRepeatedly(Return(flimflam::kTypeWimax));
450
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800451 scoped_ptr<HttpServer> server(this->test_.CreateServer());
452 ASSERT_TRUE(server->started_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800453
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800454 StartTransferArgs start_xfer_args = {
455 fetcher.get(),
456 this->test_.ErrorUrl()
457 };
Gilad Arnold48085ba2011-11-16 09:36:08 -0800458
459 g_timeout_add(0, StartTransfer, &start_xfer_args);
460 g_main_loop_run(loop);
461
462 // Make sure that no bytes were received.
463 CHECK_EQ(delegate.times_received_bytes_called_, 0);
Mike Frysinger0f9547d2012-02-16 12:11:37 -0500464 CHECK_EQ(fetcher->GetBytesDownloaded(), static_cast<size_t>(0));
Gilad Arnold48085ba2011-11-16 09:36:08 -0800465
466 // Make sure that transfer completion was signaled once, and no termination
467 // was signaled.
468 CHECK_EQ(delegate.times_transfer_complete_called_, 1);
469 CHECK_EQ(delegate.times_transfer_terminated_called_, 0);
470 }
471 g_main_loop_unref(loop);
472}
473
rspangler@google.com49fdf182009-10-10 00:57:34 +0000474namespace {
475class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
476 public:
477 virtual void ReceivedBytes(HttpFetcher* fetcher,
478 const char* bytes, int length) {
479 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000480 memset(str, 0, length + 1);
481 memcpy(str, bytes, length);
482 CHECK(!paused_);
483 paused_ = true;
484 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000485 }
486 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
487 g_main_loop_quit(loop_);
488 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800489 virtual void TransferTerminated(HttpFetcher* fetcher) {
490 ADD_FAILURE();
491 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000492 void Unpause() {
493 CHECK(paused_);
494 paused_ = false;
495 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000496 }
497 bool paused_;
498 HttpFetcher* fetcher_;
499 GMainLoop* loop_;
500};
501
502gboolean UnpausingTimeoutCallback(gpointer data) {
503 PausingHttpFetcherTestDelegate *delegate =
504 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
505 if (delegate->paused_)
506 delegate->Unpause();
507 return TRUE;
508}
509} // namespace {}
510
511TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700512 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000513 {
514 PausingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800515 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000516 delegate.paused_ = false;
517 delegate.loop_ = loop;
518 delegate.fetcher_ = fetcher.get();
519 fetcher->set_delegate(&delegate);
520
Jay Srinivasan43488792012-06-19 00:25:31 -0700521 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
522 fetcher->GetSystemState()->GetConnectionManager());
523 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
524 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetCellular), Return(true)));
525 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetCellular))
526 .WillRepeatedly(Return(true));
527 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetCellular))
528 .WillRepeatedly(Return(flimflam::kTypeCellular));
529
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800530 scoped_ptr<HttpServer> server(this->test_.CreateServer());
531 ASSERT_TRUE(server->started_);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800532
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800533 guint callback_id = g_timeout_add(kHttpResponseInternalServerError,
534 UnpausingTimeoutCallback, &delegate);
535 fetcher->BeginTransfer(this->test_.BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000536
537 g_main_loop_run(loop);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800538 g_source_remove(callback_id);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000539 }
540 g_main_loop_unref(loop);
541}
542
543namespace {
544class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
545 public:
546 virtual void ReceivedBytes(HttpFetcher* fetcher,
547 const char* bytes, int length) {}
548 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800549 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000550 g_main_loop_quit(loop_);
551 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800552 virtual void TransferTerminated(HttpFetcher* fetcher) {
553 EXPECT_EQ(fetcher, fetcher_.get());
554 EXPECT_FALSE(once_);
555 EXPECT_TRUE(callback_once_);
556 callback_once_ = false;
557 // |fetcher| can be destroyed during this callback.
558 fetcher_.reset(NULL);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800559 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000560 void TerminateTransfer() {
561 CHECK(once_);
562 once_ = false;
563 fetcher_->TerminateTransfer();
564 }
565 void EndLoop() {
566 g_main_loop_quit(loop_);
567 }
568 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800569 bool callback_once_;
570 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000571 GMainLoop* loop_;
572};
573
574gboolean AbortingTimeoutCallback(gpointer data) {
575 AbortingHttpFetcherTestDelegate *delegate =
576 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
577 if (delegate->once_) {
578 delegate->TerminateTransfer();
579 return TRUE;
580 } else {
581 delegate->EndLoop();
582 return FALSE;
583 }
584}
585} // namespace {}
586
587TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700588 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000589 {
590 AbortingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800591 delegate.fetcher_.reset(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000592 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800593 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000594 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800595 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000596
Jay Srinivasan43488792012-06-19 00:25:31 -0700597 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
598 delegate.fetcher_->GetSystemState()->GetConnectionManager());
599 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
600 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetWifi), Return(true)));
601 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetWifi))
602 .WillRepeatedly(Return(true));
603 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetWifi))
604 .WillRepeatedly(Return(flimflam::kTypeWifi));
605
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800606 scoped_ptr<HttpServer> server(this->test_.CreateServer());
607 this->test_.IgnoreServerAborting(server.get());
608 ASSERT_TRUE(server->started_);
609
rspangler@google.com49fdf182009-10-10 00:57:34 +0000610 GSource* timeout_source_;
611 timeout_source_ = g_timeout_source_new(0); // ms
612 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
613 NULL);
614 g_source_attach(timeout_source_, NULL);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800615 delegate.fetcher_->BeginTransfer(this->test_.BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000616
617 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800618 CHECK(!delegate.once_);
619 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000620 g_source_destroy(timeout_source_);
621 }
622 g_main_loop_unref(loop);
623}
624
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000625namespace {
626class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
627 public:
628 virtual void ReceivedBytes(HttpFetcher* fetcher,
629 const char* bytes, int length) {
630 data.append(bytes, length);
631 }
632 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700633 EXPECT_TRUE(successful);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800634 EXPECT_EQ(kHttpResponsePartialContent, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000635 g_main_loop_quit(loop_);
636 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800637 virtual void TransferTerminated(HttpFetcher* fetcher) {
638 ADD_FAILURE();
639 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000640 string data;
641 GMainLoop* loop_;
642};
643} // namespace {}
644
645TYPED_TEST(HttpFetcherTest, FlakyTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800646 if (this->test_.IsMock())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000647 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700648 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000649 {
650 FlakyHttpFetcherTestDelegate delegate;
651 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800652 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000653 fetcher->set_delegate(&delegate);
654
Jay Srinivasan43488792012-06-19 00:25:31 -0700655 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
656 fetcher->GetSystemState()->GetConnectionManager());
657 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
658 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetWifi), Return(true)));
659 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetWifi))
660 .WillRepeatedly(Return(true));
661 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetWifi))
662 .WillRepeatedly(Return(flimflam::kTypeWifi));
663
664
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800665 scoped_ptr<HttpServer> server(this->test_.CreateServer());
666 ASSERT_TRUE(server->started_);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000667
668 StartTransferArgs start_xfer_args = {
669 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800670 LocalServerUrlForPath(StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
671 kFlakyTruncateLength,
672 kFlakySleepEvery,
673 kFlakySleepSecs))
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000674 };
675
676 g_timeout_add(0, StartTransfer, &start_xfer_args);
677 g_main_loop_run(loop);
678
679 // verify the data we get back
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800680 ASSERT_EQ(kBigLength, delegate.data.size());
681 for (int i = 0; i < kBigLength; i += 10) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000682 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
683 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
684 }
685 }
686 g_main_loop_unref(loop);
687}
688
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700689namespace {
690class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
691 public:
692 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
693 virtual void ReceivedBytes(HttpFetcher* fetcher,
694 const char* bytes, int length) {
695 if (server_) {
696 LOG(INFO) << "Stopping server";
697 delete server_;
698 LOG(INFO) << "server stopped";
699 server_ = NULL;
700 }
701 }
702 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
703 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700704 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700705 g_main_loop_quit(loop_);
706 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800707 virtual void TransferTerminated(HttpFetcher* fetcher) {
708 ADD_FAILURE();
709 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700710 GMainLoop* loop_;
711 PythonHttpServer* server_;
712};
713} // namespace {}
714
715
716TYPED_TEST(HttpFetcherTest, FailureTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800717 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700718 return;
719 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
720 {
721 FailureHttpFetcherTestDelegate delegate;
722 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800723 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700724 fetcher->set_delegate(&delegate);
725
Jay Srinivasan43488792012-06-19 00:25:31 -0700726 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
727 fetcher->GetSystemState()->GetConnectionManager());
728 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
729 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetEthernet), Return(true)));
730 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetEthernet))
731 .WillRepeatedly(Return(true));
732 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetEthernet))
733 .WillRepeatedly(Return(flimflam::kTypeEthernet));
734
735
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700736 StartTransferArgs start_xfer_args = {
737 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800738 LocalServerUrlForPath(this->test_.SmallUrl())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700739 };
740
741 g_timeout_add(0, StartTransfer, &start_xfer_args);
742 g_main_loop_run(loop);
743
744 // Exiting and testing happens in the delegate
745 }
746 g_main_loop_unref(loop);
747}
748
749TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800750 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700751 return;
752 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
753 {
754 FailureHttpFetcherTestDelegate delegate;
755 delegate.loop_ = loop;
756 delegate.server_ = new PythonHttpServer;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800757 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700758 fetcher->set_delegate(&delegate);
759
760 StartTransferArgs start_xfer_args = {
761 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800762 LocalServerUrlForPath(StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
763 kFlakyTruncateLength,
764 kFlakySleepEvery,
765 kFlakySleepSecs))
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700766 };
767
768 g_timeout_add(0, StartTransfer, &start_xfer_args);
769 g_main_loop_run(loop);
770
771 // Exiting and testing happens in the delegate
772 }
773 g_main_loop_unref(loop);
774}
775
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700776namespace {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800777const HttpResponseCode kRedirectCodes[] = {
778 kHttpResponseMovedPermanently, kHttpResponseFound, kHttpResponseSeeOther,
779 kHttpResponseTempRedirect
780};
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700781
782class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
783 public:
784 RedirectHttpFetcherTestDelegate(bool expected_successful)
785 : expected_successful_(expected_successful) {}
786 virtual void ReceivedBytes(HttpFetcher* fetcher,
787 const char* bytes, int length) {
788 data.append(bytes, length);
789 }
790 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
791 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700792 if (expected_successful_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800793 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
Darin Petkovcb466212010-08-26 09:40:11 -0700794 else {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800795 EXPECT_GE(fetcher->http_response_code(), kHttpResponseMovedPermanently);
796 EXPECT_LE(fetcher->http_response_code(), kHttpResponseTempRedirect);
Darin Petkovcb466212010-08-26 09:40:11 -0700797 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700798 g_main_loop_quit(loop_);
799 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800800 virtual void TransferTerminated(HttpFetcher* fetcher) {
801 ADD_FAILURE();
802 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700803 bool expected_successful_;
804 string data;
805 GMainLoop* loop_;
806};
807
808// RedirectTest takes ownership of |http_fetcher|.
809void RedirectTest(bool expected_successful,
810 const string& url,
811 HttpFetcher* http_fetcher) {
812 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
813 RedirectHttpFetcherTestDelegate delegate(expected_successful);
814 delegate.loop_ = loop;
815 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
816 fetcher->set_delegate(&delegate);
817
Jay Srinivasan43488792012-06-19 00:25:31 -0700818 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
819 fetcher->GetSystemState()->GetConnectionManager());
820 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
821 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetEthernet), Return(true)));
822 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetEthernet))
823 .WillRepeatedly(Return(true));
824 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetEthernet))
825 .WillRepeatedly(Return(flimflam::kTypeEthernet));
826
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700827 StartTransferArgs start_xfer_args =
828 { fetcher.get(), LocalServerUrlForPath(url) };
829
830 g_timeout_add(0, StartTransfer, &start_xfer_args);
831 g_main_loop_run(loop);
832 if (expected_successful) {
833 // verify the data we get back
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800834 ASSERT_EQ(kMediumLength, delegate.data.size());
835 for (int i = 0; i < kMediumLength; i += 10) {
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700836 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
837 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
838 }
839 }
840 g_main_loop_unref(loop);
841}
842} // namespace {}
843
844TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800845 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700846 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800847
848 scoped_ptr<HttpServer> server(this->test_.CreateServer());
849 ASSERT_TRUE(server->started_);
850
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700851 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800852 const string url = base::StringPrintf("/redirect/%d/download/%d",
853 kRedirectCodes[c],
854 kMediumLength);
855 RedirectTest(true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700856 }
857}
858
859TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800860 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700861 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800862
863 scoped_ptr<HttpServer> server(this->test_.CreateServer());
864 ASSERT_TRUE(server->started_);
865
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700866 string url;
867 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
868 url += base::StringPrintf("/redirect/%d",
869 kRedirectCodes[r % arraysize(kRedirectCodes)]);
870 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800871 url += base::StringPrintf("/download/%d", kMediumLength);
872 RedirectTest(true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700873}
874
875TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800876 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700877 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800878
879 scoped_ptr<HttpServer> server(this->test_.CreateServer());
880 ASSERT_TRUE(server->started_);
881
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700882 string url;
883 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
884 url += base::StringPrintf("/redirect/%d",
885 kRedirectCodes[r % arraysize(kRedirectCodes)]);
886 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800887 url += base::StringPrintf("/download/%d", kMediumLength);
888 RedirectTest(false, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700889}
890
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700891namespace {
892class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
893 public:
894 MultiHttpFetcherTestDelegate(int expected_response_code)
895 : expected_response_code_(expected_response_code) {}
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800896
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700897 virtual void ReceivedBytes(HttpFetcher* fetcher,
898 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800899 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700900 data.append(bytes, length);
901 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800902
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700903 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800904 EXPECT_EQ(fetcher, fetcher_.get());
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800905 EXPECT_EQ(expected_response_code_ != kHttpResponseUndefined, successful);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700906 if (expected_response_code_ != 0)
907 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800908 // Destroy the fetcher (because we're allowed to).
909 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700910 g_main_loop_quit(loop_);
911 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800912
Darin Petkov9ce452b2010-11-17 14:33:28 -0800913 virtual void TransferTerminated(HttpFetcher* fetcher) {
914 ADD_FAILURE();
915 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800916
Darin Petkov9ce452b2010-11-17 14:33:28 -0800917 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700918 int expected_response_code_;
919 string data;
920 GMainLoop* loop_;
921};
922
923void MultiTest(HttpFetcher* fetcher_in,
924 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800925 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700926 const string& expected_prefix,
927 off_t expected_size,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800928 HttpResponseCode expected_response_code) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700929 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
930 {
931 MultiHttpFetcherTestDelegate delegate(expected_response_code);
932 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800933 delegate.fetcher_.reset(fetcher_in);
Jay Srinivasan43488792012-06-19 00:25:31 -0700934
935 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
936 fetcher_in->GetSystemState()->GetConnectionManager());
937 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
938 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetWifi), Return(true)));
939 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetWifi))
940 .WillRepeatedly(Return(true));
941 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetWifi))
942 .WillRepeatedly(Return(flimflam::kTypeWifi));
943
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800944 MultiRangeHttpFetcher* multi_fetcher =
945 dynamic_cast<MultiRangeHttpFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700946 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800947 multi_fetcher->ClearRanges();
948 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
949 e = ranges.end(); it != e; ++it) {
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800950 std::string tmp_str = StringPrintf("%jd+", it->first);
951 if (it->second > 0) {
952 base::StringAppendF(&tmp_str, "%jd", it->second);
953 multi_fetcher->AddRange(it->first, it->second);
954 } else {
955 base::StringAppendF(&tmp_str, "?");
956 multi_fetcher->AddRange(it->first);
957 }
958 LOG(INFO) << "added range: " << tmp_str;
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800959 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700960 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800961 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700962
Darin Petkov9ce452b2010-11-17 14:33:28 -0800963 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700964
965 g_timeout_add(0, StartTransfer, &start_xfer_args);
966 g_main_loop_run(loop);
967
968 EXPECT_EQ(expected_size, delegate.data.size());
969 EXPECT_EQ(expected_prefix,
970 string(delegate.data.data(), expected_prefix.size()));
971 }
972 g_main_loop_unref(loop);
973}
974} // namespace {}
975
Darin Petkov9ce452b2010-11-17 14:33:28 -0800976TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800977 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700978 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800979
980 scoped_ptr<HttpServer> server(this->test_.CreateServer());
981 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700982
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800983 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700984 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800985 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800986 MultiTest(this->test_.NewLargeFetcher(),
987 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700988 ranges,
989 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800990 kBigLength - (99 - 25),
991 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700992}
993
994TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800995 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700996 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800997
998 scoped_ptr<HttpServer> server(this->test_.CreateServer());
999 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001000
Andrew de los Reyes819fef22010-12-17 11:33:58 -08001001 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001002 ranges.push_back(make_pair(0, 24));
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001003 MultiTest(this->test_.NewLargeFetcher(),
1004 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001005 ranges,
1006 "abcdefghijabcdefghijabcd",
1007 24,
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001008 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001009}
1010
1011TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001012 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001013 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001014
1015 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1016 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001017
Andrew de los Reyes819fef22010-12-17 11:33:58 -08001018 vector<pair<off_t, off_t> > ranges;
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001019 ranges.push_back(make_pair(kBigLength - 2, 0));
1020 ranges.push_back(make_pair(kBigLength - 3, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001021 MultiTest(this->test_.NewLargeFetcher(),
1022 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001023 ranges,
1024 "ijhij",
1025 5,
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001026 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001027}
1028
1029TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001030 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001031 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001032
1033 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1034 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001035
Andrew de los Reyes819fef22010-12-17 11:33:58 -08001036 vector<pair<off_t, off_t> > ranges;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001037 ranges.push_back(make_pair(kBigLength - 2, 4));
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001038 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -08001039 LOG(INFO) << "i = " << i;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001040 MultiTest(this->test_.NewLargeFetcher(),
1041 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001042 ranges,
1043 "ij",
1044 2,
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001045 kHttpResponseUndefined);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001046 ranges.push_back(make_pair(0, 5));
1047 }
1048}
1049
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001050// Issue #18143: when a fetch of a secondary chunk out of a chain, then it
1051// should retry with other proxies listed before giving up.
1052//
1053// (1) successful recovery: The offset fetch will fail twice but succeed with
1054// the third proxy.
1055TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetRecoverableTest) {
1056 if (!this->test_.IsMulti())
1057 return;
1058
1059 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1060 ASSERT_TRUE(server->started_);
1061
1062 vector<pair<off_t, off_t> > ranges;
1063 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001064 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001065 MultiTest(this->test_.NewLargeFetcher(3),
1066 LocalServerUrlForPath(base::StringPrintf("/error-if-offset/%d/2",
1067 kBigLength)),
1068 ranges,
1069 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
1070 kBigLength - (99 - 25),
1071 kHttpResponsePartialContent);
1072}
1073
1074// (2) unsuccessful recovery: The offset fetch will fail repeatedly. The
1075// fetcher will signal a (failed) completed transfer to the delegate.
1076TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetUnrecoverableTest) {
1077 if (!this->test_.IsMulti())
1078 return;
1079
1080 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1081 ASSERT_TRUE(server->started_);
1082
1083 vector<pair<off_t, off_t> > ranges;
1084 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001085 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001086 MultiTest(this->test_.NewLargeFetcher(2),
1087 LocalServerUrlForPath(base::StringPrintf("/error-if-offset/%d/3",
1088 kBigLength)),
1089 ranges,
1090 "abcdefghijabcdefghijabcde", // only received the first chunk
1091 25,
1092 kHttpResponseUndefined);
1093}
1094
1095
1096
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001097namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001098class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001099 public:
1100 virtual void ReceivedBytes(HttpFetcher* fetcher,
1101 const char* bytes, int length) {
1102 ADD_FAILURE();
1103 }
1104 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
1105 EXPECT_FALSE(successful);
1106 g_main_loop_quit(loop_);
1107 }
Darin Petkov9ce452b2010-11-17 14:33:28 -08001108 virtual void TransferTerminated(HttpFetcher* fetcher) {
1109 ADD_FAILURE();
1110 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001111 GMainLoop* loop_;
1112};
1113
1114} // namespace
1115
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001116TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001117 if (this->test_.IsMock() || this->test_.IsMulti())
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001118 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001119
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001120 for (int i = 0; i < 2; i++) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001121 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1122 ASSERT_TRUE(server->started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001123
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001124 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
1125 BlockedTransferTestDelegate delegate;
1126 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001127
Jay Srinivasan43488792012-06-19 00:25:31 -07001128 bool is_allowed = (i != 0);
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001129 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Jay Srinivasan43488792012-06-19 00:25:31 -07001130 MockConnectionManager* mock_cm = dynamic_cast<MockConnectionManager*>(
1131 fetcher->GetSystemState()->GetConnectionManager());
1132 EXPECT_CALL(*mock_cm, GetConnectionType(_,_))
1133 .WillRepeatedly(DoAll(SetArgumentPointee<1>(kNetWifi), Return(true)));
1134 EXPECT_CALL(*mock_cm, IsUpdateAllowedOver(kNetWifi))
1135 .WillRepeatedly(Return(is_allowed));
1136 EXPECT_CALL(*mock_cm, StringForConnectionType(kNetWifi))
1137 .WillRepeatedly(Return(flimflam::kTypeWifi));
1138
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001139 bool is_official_build = (i == 1);
Jay Srinivasan43488792012-06-19 00:25:31 -07001140 LOG(INFO) << "is_update_allowed_over_connection: " << is_allowed;
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001141 LOG(INFO) << "is_official_build: " << is_official_build;
Jay Srinivasan43488792012-06-19 00:25:31 -07001142 fetcher->SetBuildType(is_official_build);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001143 fetcher->set_delegate(&delegate);
1144
1145 StartTransferArgs start_xfer_args =
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001146 { fetcher.get(), LocalServerUrlForPath(this->test_.SmallUrl()) };
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001147
1148 g_timeout_add(0, StartTransfer, &start_xfer_args);
1149 g_main_loop_run(loop);
1150 g_main_loop_unref(loop);
1151 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001152}
1153
rspangler@google.com49fdf182009-10-10 00:57:34 +00001154} // namespace chromeos_update_engine