blob: ccda0b67e8096a4354ebcdb1cf6b111e216e3fb1 [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
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>
12#include <base/scoped_ptr.h>
13#include <base/string_util.h>
14#include <glib.h>
15#include <gtest/gtest.h>
16
rspangler@google.com49fdf182009-10-10 00:57:34 +000017#include "update_engine/libcurl_http_fetcher.h"
18#include "update_engine/mock_http_fetcher.h"
Andrew de los Reyes819fef22010-12-17 11:33:58 -080019#include "update_engine/multi_range_http_fetcher.h"
Andrew de los Reyes45168102010-11-22 11:13:50 -080020#include "update_engine/proxy_resolver.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000021
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070022using std::make_pair;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080023using std::pair;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000024using std::string;
25using std::vector;
26
rspangler@google.com49fdf182009-10-10 00:57:34 +000027namespace chromeos_update_engine {
28
29namespace {
Darin Petkovf67bb1f2010-11-08 16:10:26 -080030// WARNING, if you update these, you must also update test_http_server.cc.
31const char* const kServerPort = "8088";
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070032const int kBigSize = 100000;
rspangler@google.com49fdf182009-10-10 00:57:34 +000033string LocalServerUrlForPath(const string& path) {
34 return string("http://127.0.0.1:") + kServerPort + path;
35}
36}
37
38template <typename T>
39class HttpFetcherTest : public ::testing::Test {
40 public:
41 HttpFetcher* NewLargeFetcher() = 0;
42 HttpFetcher* NewSmallFetcher() = 0;
43 string BigUrl() const = 0;
44 string SmallUrl() const = 0;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000045 bool IsMock() const = 0;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070046 bool IsMulti() const = 0;
rspangler@google.com49fdf182009-10-10 00:57:34 +000047};
48
49class NullHttpServer {
50 public:
51 NullHttpServer() : started_(true) {}
52 ~NullHttpServer() {}
53 bool started_;
54};
55
56
57template <>
58class HttpFetcherTest<MockHttpFetcher> : public ::testing::Test {
59 public:
60 HttpFetcher* NewLargeFetcher() {
61 vector<char> big_data(1000000);
Andrew de los Reyes45168102010-11-22 11:13:50 -080062 return new MockHttpFetcher(
63 big_data.data(),
64 big_data.size(),
65 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
rspangler@google.com49fdf182009-10-10 00:57:34 +000066 }
67 HttpFetcher* NewSmallFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -080068 return new MockHttpFetcher(
69 "x",
70 1,
71 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
rspangler@google.com49fdf182009-10-10 00:57:34 +000072 }
73 string BigUrl() const {
74 return "unused://unused";
75 }
76 string SmallUrl() const {
77 return "unused://unused";
78 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +000079 bool IsMock() const { return true; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070080 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +000081 typedef NullHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070082 void IgnoreServerAborting(HttpServer* server) const {}
Andrew de los Reyes45168102010-11-22 11:13:50 -080083
84 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +000085};
86
87class PythonHttpServer {
88 public:
89 PythonHttpServer() {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000090 char *argv[2] = {strdup("./test_http_server"), NULL};
rspangler@google.com49fdf182009-10-10 00:57:34 +000091 GError *err;
92 started_ = false;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070093 validate_quit_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000094 if (!g_spawn_async(NULL,
95 argv,
96 NULL,
97 G_SPAWN_DO_NOT_REAP_CHILD,
98 NULL,
99 NULL,
100 &pid_,
101 &err)) {
102 return;
103 }
104 int rc = 1;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700105 int tries = 10;
106 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000107 while (0 != rc) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700108 LOG(INFO) << "running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000109 rc = system((string("wget --output-document=/dev/null ") +
110 LocalServerUrlForPath("/test")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700111 LOG(INFO) << "done running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000112 usleep(10 * 1000); // 10 ms
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700113 tries--;
114 if (tries == 0) {
115 LOG(ERROR) << "Unable to start server.";
116 started_ = false;
117 break;
118 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000119 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000120 free(argv[0]);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700121 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000122 return;
123 }
124 ~PythonHttpServer() {
125 if (!started_)
126 return;
127 // request that the server exit itself
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700128 LOG(INFO) << "running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700129 int rc = system((string("wget -t 1 --output-document=/dev/null ") +
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700130 LocalServerUrlForPath("/quitquitquit")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700131 LOG(INFO) << "done running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700132 if (validate_quit_)
133 EXPECT_EQ(0, rc);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000134 waitpid(pid_, NULL, 0);
135 }
136 GPid pid_;
137 bool started_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700138 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000139};
140
141template <>
142class HttpFetcherTest<LibcurlHttpFetcher> : public ::testing::Test {
143 public:
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700144 virtual HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -0800145 LibcurlHttpFetcher *ret = new
146 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
Darin Petkovb83371f2010-08-17 09:34:49 -0700147 // Speed up test execution.
148 ret->set_idle_seconds(1);
149 ret->set_retry_seconds(1);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700150 ret->SetConnectionAsExpensive(false);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700151 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000152 return ret;
153 }
154 HttpFetcher* NewSmallFetcher() {
155 return NewLargeFetcher();
156 }
157 string BigUrl() const {
158 return LocalServerUrlForPath("/big");
159 }
160 string SmallUrl() const {
161 return LocalServerUrlForPath("/foo");
162 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000163 bool IsMock() const { return false; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700164 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000165 typedef PythonHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700166 void IgnoreServerAborting(HttpServer* server) const {
167 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
168 pyserver->validate_quit_ = false;
169 }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800170 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000171};
172
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700173template <>
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800174class HttpFetcherTest<MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700175 : public HttpFetcherTest<LibcurlHttpFetcher> {
176 public:
177 HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800178 ProxyResolver* resolver =
179 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
180 MultiRangeHTTPFetcher *ret =
181 new MultiRangeHTTPFetcher(new LibcurlHttpFetcher(resolver));
182 ret->ClearRanges();
183 ret->AddRange(0, -1);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700184 // Speed up test execution.
185 ret->set_idle_seconds(1);
186 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700187 ret->SetConnectionAsExpensive(false);
188 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700189 return ret;
190 }
191 bool IsMulti() const { return true; }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800192 DirectProxyResolver proxy_resolver_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700193};
194
195typedef ::testing::Types<LibcurlHttpFetcher,
196 MockHttpFetcher,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800197 MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700198HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000199TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
200
201namespace {
202class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000203 public:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000204 virtual void ReceivedBytes(HttpFetcher* fetcher,
205 const char* bytes, int length) {
206 char str[length + 1];
207 memset(str, 0, length + 1);
208 memcpy(str, bytes, length);
209 }
210 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkovcb466212010-08-26 09:40:11 -0700211 EXPECT_EQ(200, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000212 g_main_loop_quit(loop_);
213 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800214 virtual void TransferTerminated(HttpFetcher* fetcher) {
215 ADD_FAILURE();
216 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000217 GMainLoop* loop_;
218};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000219
220struct StartTransferArgs {
221 HttpFetcher *http_fetcher;
222 string url;
223};
224
225gboolean StartTransfer(gpointer data) {
226 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
227 args->http_fetcher->BeginTransfer(args->url);
228 return FALSE;
229}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000230} // namespace {}
231
232TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700233 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000234 {
235 HttpFetcherTestDelegate delegate;
236 delegate.loop_ = loop;
237 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
238 fetcher->set_delegate(&delegate);
239
240 typename TestFixture::HttpServer server;
241 ASSERT_TRUE(server.started_);
242
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000243 StartTransferArgs start_xfer_args = {fetcher.get(), this->SmallUrl()};
244
245 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000246 g_main_loop_run(loop);
247 }
248 g_main_loop_unref(loop);
249}
250
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700251TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700252 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700253 {
254 HttpFetcherTestDelegate delegate;
255 delegate.loop_ = loop;
256 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
257 fetcher->set_delegate(&delegate);
258
259 typename TestFixture::HttpServer server;
260 ASSERT_TRUE(server.started_);
261
262 StartTransferArgs start_xfer_args = {fetcher.get(), this->BigUrl()};
263
264 g_timeout_add(0, StartTransfer, &start_xfer_args);
265 g_main_loop_run(loop);
266 }
267 g_main_loop_unref(loop);
268}
269
rspangler@google.com49fdf182009-10-10 00:57:34 +0000270namespace {
271class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
272 public:
273 virtual void ReceivedBytes(HttpFetcher* fetcher,
274 const char* bytes, int length) {
275 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000276 memset(str, 0, length + 1);
277 memcpy(str, bytes, length);
278 CHECK(!paused_);
279 paused_ = true;
280 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000281 }
282 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
283 g_main_loop_quit(loop_);
284 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800285 virtual void TransferTerminated(HttpFetcher* fetcher) {
286 ADD_FAILURE();
287 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000288 void Unpause() {
289 CHECK(paused_);
290 paused_ = false;
291 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000292 }
293 bool paused_;
294 HttpFetcher* fetcher_;
295 GMainLoop* loop_;
296};
297
298gboolean UnpausingTimeoutCallback(gpointer data) {
299 PausingHttpFetcherTestDelegate *delegate =
300 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
301 if (delegate->paused_)
302 delegate->Unpause();
303 return TRUE;
304}
305} // namespace {}
306
307TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700308 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000309 {
310 PausingHttpFetcherTestDelegate delegate;
311 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
312 delegate.paused_ = false;
313 delegate.loop_ = loop;
314 delegate.fetcher_ = fetcher.get();
315 fetcher->set_delegate(&delegate);
316
317 typename TestFixture::HttpServer server;
318 ASSERT_TRUE(server.started_);
319 GSource* timeout_source_;
320 timeout_source_ = g_timeout_source_new(0); // ms
321 g_source_set_callback(timeout_source_, UnpausingTimeoutCallback, &delegate,
322 NULL);
323 g_source_attach(timeout_source_, NULL);
324 fetcher->BeginTransfer(this->BigUrl());
325
326 g_main_loop_run(loop);
327 g_source_destroy(timeout_source_);
328 }
329 g_main_loop_unref(loop);
330}
331
332namespace {
333class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
334 public:
335 virtual void ReceivedBytes(HttpFetcher* fetcher,
336 const char* bytes, int length) {}
337 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800338 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000339 g_main_loop_quit(loop_);
340 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800341 virtual void TransferTerminated(HttpFetcher* fetcher) {
342 EXPECT_EQ(fetcher, fetcher_.get());
343 EXPECT_FALSE(once_);
344 EXPECT_TRUE(callback_once_);
345 callback_once_ = false;
346 // |fetcher| can be destroyed during this callback.
347 fetcher_.reset(NULL);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800348 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000349 void TerminateTransfer() {
350 CHECK(once_);
351 once_ = false;
352 fetcher_->TerminateTransfer();
353 }
354 void EndLoop() {
355 g_main_loop_quit(loop_);
356 }
357 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800358 bool callback_once_;
359 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000360 GMainLoop* loop_;
361};
362
363gboolean AbortingTimeoutCallback(gpointer data) {
364 AbortingHttpFetcherTestDelegate *delegate =
365 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
366 if (delegate->once_) {
367 delegate->TerminateTransfer();
368 return TRUE;
369 } else {
370 delegate->EndLoop();
371 return FALSE;
372 }
373}
374} // namespace {}
375
376TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700377 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000378 {
379 AbortingHttpFetcherTestDelegate delegate;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800380 delegate.fetcher_.reset(this->NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000381 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800382 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000383 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800384 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000385
386 typename TestFixture::HttpServer server;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700387 this->IgnoreServerAborting(&server);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000388 ASSERT_TRUE(server.started_);
389 GSource* timeout_source_;
390 timeout_source_ = g_timeout_source_new(0); // ms
391 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
392 NULL);
393 g_source_attach(timeout_source_, NULL);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800394 delegate.fetcher_->BeginTransfer(this->BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000395
396 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800397 CHECK(!delegate.once_);
398 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000399 g_source_destroy(timeout_source_);
400 }
401 g_main_loop_unref(loop);
402}
403
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000404namespace {
405class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
406 public:
407 virtual void ReceivedBytes(HttpFetcher* fetcher,
408 const char* bytes, int length) {
409 data.append(bytes, length);
410 }
411 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700412 EXPECT_TRUE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700413 EXPECT_EQ(206, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000414 g_main_loop_quit(loop_);
415 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800416 virtual void TransferTerminated(HttpFetcher* fetcher) {
417 ADD_FAILURE();
418 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000419 string data;
420 GMainLoop* loop_;
421};
422} // namespace {}
423
424TYPED_TEST(HttpFetcherTest, FlakyTest) {
425 if (this->IsMock())
426 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700427 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000428 {
429 FlakyHttpFetcherTestDelegate delegate;
430 delegate.loop_ = loop;
431 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
432 fetcher->set_delegate(&delegate);
433
434 typename TestFixture::HttpServer server;
435 ASSERT_TRUE(server.started_);
436
437 StartTransferArgs start_xfer_args = {
438 fetcher.get(),
439 LocalServerUrlForPath("/flaky")
440 };
441
442 g_timeout_add(0, StartTransfer, &start_xfer_args);
443 g_main_loop_run(loop);
444
445 // verify the data we get back
446 ASSERT_EQ(100000, delegate.data.size());
447 for (int i = 0; i < 100000; i += 10) {
448 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
449 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
450 }
451 }
452 g_main_loop_unref(loop);
453}
454
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700455namespace {
456class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
457 public:
458 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
459 virtual void ReceivedBytes(HttpFetcher* fetcher,
460 const char* bytes, int length) {
461 if (server_) {
462 LOG(INFO) << "Stopping server";
463 delete server_;
464 LOG(INFO) << "server stopped";
465 server_ = NULL;
466 }
467 }
468 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
469 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700470 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700471 g_main_loop_quit(loop_);
472 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800473 virtual void TransferTerminated(HttpFetcher* fetcher) {
474 ADD_FAILURE();
475 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700476 GMainLoop* loop_;
477 PythonHttpServer* server_;
478};
479} // namespace {}
480
481
482TYPED_TEST(HttpFetcherTest, FailureTest) {
483 if (this->IsMock())
484 return;
485 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
486 {
487 FailureHttpFetcherTestDelegate delegate;
488 delegate.loop_ = loop;
489 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
490 fetcher->set_delegate(&delegate);
491
492 StartTransferArgs start_xfer_args = {
493 fetcher.get(),
494 LocalServerUrlForPath(this->SmallUrl())
495 };
496
497 g_timeout_add(0, StartTransfer, &start_xfer_args);
498 g_main_loop_run(loop);
499
500 // Exiting and testing happens in the delegate
501 }
502 g_main_loop_unref(loop);
503}
504
505TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
506 if (this->IsMock())
507 return;
508 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
509 {
510 FailureHttpFetcherTestDelegate delegate;
511 delegate.loop_ = loop;
512 delegate.server_ = new PythonHttpServer;
513 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
514 fetcher->set_delegate(&delegate);
515
516 StartTransferArgs start_xfer_args = {
517 fetcher.get(),
518 LocalServerUrlForPath("/flaky")
519 };
520
521 g_timeout_add(0, StartTransfer, &start_xfer_args);
522 g_main_loop_run(loop);
523
524 // Exiting and testing happens in the delegate
525 }
526 g_main_loop_unref(loop);
527}
528
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700529namespace {
530const int kRedirectCodes[] = { 301, 302, 303, 307 };
531
532class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
533 public:
534 RedirectHttpFetcherTestDelegate(bool expected_successful)
535 : expected_successful_(expected_successful) {}
536 virtual void ReceivedBytes(HttpFetcher* fetcher,
537 const char* bytes, int length) {
538 data.append(bytes, length);
539 }
540 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
541 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700542 if (expected_successful_)
543 EXPECT_EQ(200, fetcher->http_response_code());
544 else {
545 EXPECT_GE(fetcher->http_response_code(), 301);
546 EXPECT_LE(fetcher->http_response_code(), 307);
547 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700548 g_main_loop_quit(loop_);
549 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800550 virtual void TransferTerminated(HttpFetcher* fetcher) {
551 ADD_FAILURE();
552 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700553 bool expected_successful_;
554 string data;
555 GMainLoop* loop_;
556};
557
558// RedirectTest takes ownership of |http_fetcher|.
559void RedirectTest(bool expected_successful,
560 const string& url,
561 HttpFetcher* http_fetcher) {
562 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
563 RedirectHttpFetcherTestDelegate delegate(expected_successful);
564 delegate.loop_ = loop;
565 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
566 fetcher->set_delegate(&delegate);
567
568 StartTransferArgs start_xfer_args =
569 { fetcher.get(), LocalServerUrlForPath(url) };
570
571 g_timeout_add(0, StartTransfer, &start_xfer_args);
572 g_main_loop_run(loop);
573 if (expected_successful) {
574 // verify the data we get back
575 ASSERT_EQ(1000, delegate.data.size());
576 for (int i = 0; i < 1000; i += 10) {
577 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
578 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
579 }
580 }
581 g_main_loop_unref(loop);
582}
583} // namespace {}
584
585TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
586 if (this->IsMock())
587 return;
588 typename TestFixture::HttpServer server;
589 ASSERT_TRUE(server.started_);
590 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
591 const string url = base::StringPrintf("/redirect/%d/medium",
592 kRedirectCodes[c]);
593 RedirectTest(true, url, this->NewLargeFetcher());
594 }
595}
596
597TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
598 if (this->IsMock())
599 return;
600 typename TestFixture::HttpServer server;
601 ASSERT_TRUE(server.started_);
602 string url;
603 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
604 url += base::StringPrintf("/redirect/%d",
605 kRedirectCodes[r % arraysize(kRedirectCodes)]);
606 }
607 url += "/medium";
608 RedirectTest(true, url, this->NewLargeFetcher());
609}
610
611TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
612 if (this->IsMock())
613 return;
614 typename TestFixture::HttpServer server;
615 ASSERT_TRUE(server.started_);
616 string url;
617 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
618 url += base::StringPrintf("/redirect/%d",
619 kRedirectCodes[r % arraysize(kRedirectCodes)]);
620 }
621 url += "/medium";
622 RedirectTest(false, url, this->NewLargeFetcher());
623}
624
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700625namespace {
626class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
627 public:
628 MultiHttpFetcherTestDelegate(int expected_response_code)
629 : expected_response_code_(expected_response_code) {}
630 virtual void ReceivedBytes(HttpFetcher* fetcher,
631 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800632 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700633 data.append(bytes, length);
634 }
635 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800636 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700637 EXPECT_EQ(expected_response_code_ != 0, successful);
638 if (expected_response_code_ != 0)
639 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800640 // Destroy the fetcher (because we're allowed to).
641 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700642 g_main_loop_quit(loop_);
643 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800644 virtual void TransferTerminated(HttpFetcher* fetcher) {
645 ADD_FAILURE();
646 }
647 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700648 int expected_response_code_;
649 string data;
650 GMainLoop* loop_;
651};
652
653void MultiTest(HttpFetcher* fetcher_in,
654 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800655 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700656 const string& expected_prefix,
657 off_t expected_size,
658 int expected_response_code) {
659 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
660 {
661 MultiHttpFetcherTestDelegate delegate(expected_response_code);
662 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800663 delegate.fetcher_.reset(fetcher_in);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800664 MultiRangeHTTPFetcher* multi_fetcher =
665 dynamic_cast<MultiRangeHTTPFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700666 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800667 multi_fetcher->ClearRanges();
668 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
669 e = ranges.end(); it != e; ++it) {
670 LOG(INFO) << "Adding range";
671 multi_fetcher->AddRange(it->first, it->second);
672 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700673 multi_fetcher->SetConnectionAsExpensive(false);
674 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800675 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700676
Darin Petkov9ce452b2010-11-17 14:33:28 -0800677 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700678
679 g_timeout_add(0, StartTransfer, &start_xfer_args);
680 g_main_loop_run(loop);
681
682 EXPECT_EQ(expected_size, delegate.data.size());
683 EXPECT_EQ(expected_prefix,
684 string(delegate.data.data(), expected_prefix.size()));
685 }
686 g_main_loop_unref(loop);
687}
688} // namespace {}
689
Darin Petkov9ce452b2010-11-17 14:33:28 -0800690TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700691 if (!this->IsMulti())
692 return;
693 typename TestFixture::HttpServer server;
694 ASSERT_TRUE(server.started_);
695
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800696 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700697 ranges.push_back(make_pair(0, 25));
698 ranges.push_back(make_pair(99, -1));
699 MultiTest(this->NewLargeFetcher(),
700 this->BigUrl(),
701 ranges,
702 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
703 kBigSize - (99 - 25),
704 206);
705}
706
707TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
708 if (!this->IsMulti())
709 return;
710 typename TestFixture::HttpServer server;
711 ASSERT_TRUE(server.started_);
712
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800713 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700714 ranges.push_back(make_pair(0, 24));
715 MultiTest(this->NewLargeFetcher(),
716 this->BigUrl(),
717 ranges,
718 "abcdefghijabcdefghijabcd",
719 24,
720 200);
721}
722
723TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
724 if (!this->IsMulti())
725 return;
726 typename TestFixture::HttpServer server;
727 ASSERT_TRUE(server.started_);
728
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800729 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700730 ranges.push_back(make_pair(kBigSize - 2, -1));
731 ranges.push_back(make_pair(kBigSize - 3, -1));
732 MultiTest(this->NewLargeFetcher(),
733 this->BigUrl(),
734 ranges,
735 "ijhij",
736 5,
737 206);
738}
739
740TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
741 if (!this->IsMulti())
742 return;
743 typename TestFixture::HttpServer server;
744 ASSERT_TRUE(server.started_);
745
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800746 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700747 ranges.push_back(make_pair(kBigSize - 2, 4));
748 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800749 LOG(INFO) << "i = " << i;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700750 MultiTest(this->NewLargeFetcher(),
751 this->BigUrl(),
752 ranges,
753 "ij",
754 2,
755 0);
756 ranges.push_back(make_pair(0, 5));
757 }
758}
759
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700760namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700761class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700762 public:
763 virtual void ReceivedBytes(HttpFetcher* fetcher,
764 const char* bytes, int length) {
765 ADD_FAILURE();
766 }
767 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
768 EXPECT_FALSE(successful);
769 g_main_loop_quit(loop_);
770 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800771 virtual void TransferTerminated(HttpFetcher* fetcher) {
772 ADD_FAILURE();
773 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700774 GMainLoop* loop_;
775};
776
777} // namespace
778
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700779TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700780 if (this->IsMock() || this->IsMulti())
781 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700782
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700783 for (int i = 0; i < 2; i++) {
784 typename TestFixture::HttpServer server;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700785
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700786 ASSERT_TRUE(server.started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700787
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700788 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
789 BlockedTransferTestDelegate delegate;
790 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700791
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700792 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
793 LibcurlHttpFetcher* curl_fetcher =
794 dynamic_cast<LibcurlHttpFetcher*>(fetcher.get());
795 bool is_expensive_connection = (i == 0);
796 bool is_official_build = (i == 1);
797 LOG(INFO) << "is_expensive_connection: " << is_expensive_connection;
798 LOG(INFO) << "is_official_build: " << is_official_build;
799 curl_fetcher->SetConnectionAsExpensive(is_expensive_connection);
800 curl_fetcher->SetBuildType(is_official_build);
801 fetcher->set_delegate(&delegate);
802
803 StartTransferArgs start_xfer_args =
804 { fetcher.get(), LocalServerUrlForPath(this->SmallUrl()) };
805
806 g_timeout_add(0, StartTransfer, &start_xfer_args);
807 g_main_loop_run(loop);
808 g_main_loop_unref(loop);
809 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700810}
811
rspangler@google.com49fdf182009-10-10 00:57:34 +0000812} // namespace chromeos_update_engine