blob: a42bb3b64e2f4c68dc6fff18913f4ff5408fbb3a [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 Reyes3fd5d302010-10-07 20:07:18 -070019#include "update_engine/multi_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;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000023using std::string;
24using std::vector;
25
rspangler@google.com49fdf182009-10-10 00:57:34 +000026namespace chromeos_update_engine {
27
28namespace {
Darin Petkovf67bb1f2010-11-08 16:10:26 -080029// WARNING, if you update these, you must also update test_http_server.cc.
30const char* const kServerPort = "8088";
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070031const int kBigSize = 100000;
rspangler@google.com49fdf182009-10-10 00:57:34 +000032string LocalServerUrlForPath(const string& path) {
33 return string("http://127.0.0.1:") + kServerPort + path;
34}
35}
36
37template <typename T>
38class HttpFetcherTest : public ::testing::Test {
39 public:
40 HttpFetcher* NewLargeFetcher() = 0;
41 HttpFetcher* NewSmallFetcher() = 0;
42 string BigUrl() const = 0;
43 string SmallUrl() const = 0;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000044 bool IsMock() const = 0;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070045 bool IsMulti() const = 0;
rspangler@google.com49fdf182009-10-10 00:57:34 +000046};
47
48class NullHttpServer {
49 public:
50 NullHttpServer() : started_(true) {}
51 ~NullHttpServer() {}
52 bool started_;
53};
54
55
56template <>
57class HttpFetcherTest<MockHttpFetcher> : public ::testing::Test {
58 public:
59 HttpFetcher* NewLargeFetcher() {
60 vector<char> big_data(1000000);
Andrew de los Reyes45168102010-11-22 11:13:50 -080061 return new MockHttpFetcher(
62 big_data.data(),
63 big_data.size(),
64 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
rspangler@google.com49fdf182009-10-10 00:57:34 +000065 }
66 HttpFetcher* NewSmallFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -080067 return new MockHttpFetcher(
68 "x",
69 1,
70 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
rspangler@google.com49fdf182009-10-10 00:57:34 +000071 }
72 string BigUrl() const {
73 return "unused://unused";
74 }
75 string SmallUrl() const {
76 return "unused://unused";
77 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +000078 bool IsMock() const { return true; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070079 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +000080 typedef NullHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070081 void IgnoreServerAborting(HttpServer* server) const {}
Andrew de los Reyes45168102010-11-22 11:13:50 -080082
83 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +000084};
85
86class PythonHttpServer {
87 public:
88 PythonHttpServer() {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000089 char *argv[2] = {strdup("./test_http_server"), NULL};
rspangler@google.com49fdf182009-10-10 00:57:34 +000090 GError *err;
91 started_ = false;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070092 validate_quit_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000093 if (!g_spawn_async(NULL,
94 argv,
95 NULL,
96 G_SPAWN_DO_NOT_REAP_CHILD,
97 NULL,
98 NULL,
99 &pid_,
100 &err)) {
101 return;
102 }
103 int rc = 1;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700104 int tries = 10;
105 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000106 while (0 != rc) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700107 LOG(INFO) << "running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000108 rc = system((string("wget --output-document=/dev/null ") +
109 LocalServerUrlForPath("/test")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700110 LOG(INFO) << "done running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000111 usleep(10 * 1000); // 10 ms
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700112 tries--;
113 if (tries == 0) {
114 LOG(ERROR) << "Unable to start server.";
115 started_ = false;
116 break;
117 }
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 return;
122 }
123 ~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 }
135 GPid pid_;
136 bool started_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700137 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000138};
139
140template <>
141class HttpFetcherTest<LibcurlHttpFetcher> : public ::testing::Test {
142 public:
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700143 virtual HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -0800144 LibcurlHttpFetcher *ret = new
145 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
Darin Petkovb83371f2010-08-17 09:34:49 -0700146 // Speed up test execution.
147 ret->set_idle_seconds(1);
148 ret->set_retry_seconds(1);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700149 ret->SetConnectionAsExpensive(false);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700150 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000151 return ret;
152 }
153 HttpFetcher* NewSmallFetcher() {
154 return NewLargeFetcher();
155 }
156 string BigUrl() const {
157 return LocalServerUrlForPath("/big");
158 }
159 string SmallUrl() const {
160 return LocalServerUrlForPath("/foo");
161 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000162 bool IsMock() const { return false; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700163 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000164 typedef PythonHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700165 void IgnoreServerAborting(HttpServer* server) const {
166 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
167 pyserver->validate_quit_ = false;
168 }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800169 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000170};
171
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700172template <>
173class HttpFetcherTest<MultiHttpFetcher<LibcurlHttpFetcher> >
174 : public HttpFetcherTest<LibcurlHttpFetcher> {
175 public:
176 HttpFetcher* NewLargeFetcher() {
177 MultiHttpFetcher<LibcurlHttpFetcher> *ret =
Andrew de los Reyes45168102010-11-22 11:13:50 -0800178 new MultiHttpFetcher<LibcurlHttpFetcher>(
179 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700180 MultiHttpFetcher<LibcurlHttpFetcher>::RangesVect
181 ranges(1, make_pair(0, -1));
182 ret->set_ranges(ranges);
183 // Speed up test execution.
184 ret->set_idle_seconds(1);
185 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700186 ret->SetConnectionAsExpensive(false);
187 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700188 return ret;
189 }
190 bool IsMulti() const { return true; }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800191 DirectProxyResolver proxy_resolver_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700192};
193
194typedef ::testing::Types<LibcurlHttpFetcher,
195 MockHttpFetcher,
196 MultiHttpFetcher<LibcurlHttpFetcher> >
197HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000198TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
199
200namespace {
201class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000202 public:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000203 virtual void ReceivedBytes(HttpFetcher* fetcher,
204 const char* bytes, int length) {
205 char str[length + 1];
206 memset(str, 0, length + 1);
207 memcpy(str, bytes, length);
208 }
209 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkovcb466212010-08-26 09:40:11 -0700210 EXPECT_EQ(200, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000211 g_main_loop_quit(loop_);
212 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800213 virtual void TransferTerminated(HttpFetcher* fetcher) {
214 ADD_FAILURE();
215 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000216 GMainLoop* loop_;
217};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000218
219struct StartTransferArgs {
220 HttpFetcher *http_fetcher;
221 string url;
222};
223
224gboolean StartTransfer(gpointer data) {
225 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
226 args->http_fetcher->BeginTransfer(args->url);
227 return FALSE;
228}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000229} // namespace {}
230
231TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700232 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000233 {
234 HttpFetcherTestDelegate delegate;
235 delegate.loop_ = loop;
236 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
237 fetcher->set_delegate(&delegate);
238
239 typename TestFixture::HttpServer server;
240 ASSERT_TRUE(server.started_);
241
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000242 StartTransferArgs start_xfer_args = {fetcher.get(), this->SmallUrl()};
243
244 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000245 g_main_loop_run(loop);
246 }
247 g_main_loop_unref(loop);
248}
249
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700250TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700251 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700252 {
253 HttpFetcherTestDelegate delegate;
254 delegate.loop_ = loop;
255 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
256 fetcher->set_delegate(&delegate);
257
258 typename TestFixture::HttpServer server;
259 ASSERT_TRUE(server.started_);
260
261 StartTransferArgs start_xfer_args = {fetcher.get(), this->BigUrl()};
262
263 g_timeout_add(0, StartTransfer, &start_xfer_args);
264 g_main_loop_run(loop);
265 }
266 g_main_loop_unref(loop);
267}
268
rspangler@google.com49fdf182009-10-10 00:57:34 +0000269namespace {
270class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
271 public:
272 virtual void ReceivedBytes(HttpFetcher* fetcher,
273 const char* bytes, int length) {
274 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000275 memset(str, 0, length + 1);
276 memcpy(str, bytes, length);
277 CHECK(!paused_);
278 paused_ = true;
279 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000280 }
281 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
282 g_main_loop_quit(loop_);
283 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800284 virtual void TransferTerminated(HttpFetcher* fetcher) {
285 ADD_FAILURE();
286 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000287 void Unpause() {
288 CHECK(paused_);
289 paused_ = false;
290 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000291 }
292 bool paused_;
293 HttpFetcher* fetcher_;
294 GMainLoop* loop_;
295};
296
297gboolean UnpausingTimeoutCallback(gpointer data) {
298 PausingHttpFetcherTestDelegate *delegate =
299 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
300 if (delegate->paused_)
301 delegate->Unpause();
302 return TRUE;
303}
304} // namespace {}
305
306TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700307 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000308 {
309 PausingHttpFetcherTestDelegate delegate;
310 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
311 delegate.paused_ = false;
312 delegate.loop_ = loop;
313 delegate.fetcher_ = fetcher.get();
314 fetcher->set_delegate(&delegate);
315
316 typename TestFixture::HttpServer server;
317 ASSERT_TRUE(server.started_);
318 GSource* timeout_source_;
319 timeout_source_ = g_timeout_source_new(0); // ms
320 g_source_set_callback(timeout_source_, UnpausingTimeoutCallback, &delegate,
321 NULL);
322 g_source_attach(timeout_source_, NULL);
323 fetcher->BeginTransfer(this->BigUrl());
324
325 g_main_loop_run(loop);
326 g_source_destroy(timeout_source_);
327 }
328 g_main_loop_unref(loop);
329}
330
331namespace {
332class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
333 public:
334 virtual void ReceivedBytes(HttpFetcher* fetcher,
335 const char* bytes, int length) {}
336 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800337 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000338 g_main_loop_quit(loop_);
339 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800340 virtual void TransferTerminated(HttpFetcher* fetcher) {
341 EXPECT_EQ(fetcher, fetcher_.get());
342 EXPECT_FALSE(once_);
343 EXPECT_TRUE(callback_once_);
344 callback_once_ = false;
345 // |fetcher| can be destroyed during this callback.
346 fetcher_.reset(NULL);
347 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000348 void TerminateTransfer() {
349 CHECK(once_);
350 once_ = false;
351 fetcher_->TerminateTransfer();
352 }
353 void EndLoop() {
354 g_main_loop_quit(loop_);
355 }
356 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800357 bool callback_once_;
358 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000359 GMainLoop* loop_;
360};
361
362gboolean AbortingTimeoutCallback(gpointer data) {
363 AbortingHttpFetcherTestDelegate *delegate =
364 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
365 if (delegate->once_) {
366 delegate->TerminateTransfer();
367 return TRUE;
368 } else {
369 delegate->EndLoop();
370 return FALSE;
371 }
372}
373} // namespace {}
374
375TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700376 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000377 {
378 AbortingHttpFetcherTestDelegate delegate;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800379 delegate.fetcher_.reset(this->NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000380 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800381 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000382 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800383 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000384
385 typename TestFixture::HttpServer server;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700386 this->IgnoreServerAborting(&server);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000387 ASSERT_TRUE(server.started_);
388 GSource* timeout_source_;
389 timeout_source_ = g_timeout_source_new(0); // ms
390 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
391 NULL);
392 g_source_attach(timeout_source_, NULL);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800393 delegate.fetcher_->BeginTransfer(this->BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000394
395 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800396 CHECK(!delegate.once_);
397 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000398 g_source_destroy(timeout_source_);
399 }
400 g_main_loop_unref(loop);
401}
402
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000403namespace {
404class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
405 public:
406 virtual void ReceivedBytes(HttpFetcher* fetcher,
407 const char* bytes, int length) {
408 data.append(bytes, length);
409 }
410 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700411 EXPECT_TRUE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700412 EXPECT_EQ(206, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000413 g_main_loop_quit(loop_);
414 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800415 virtual void TransferTerminated(HttpFetcher* fetcher) {
416 ADD_FAILURE();
417 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000418 string data;
419 GMainLoop* loop_;
420};
421} // namespace {}
422
423TYPED_TEST(HttpFetcherTest, FlakyTest) {
424 if (this->IsMock())
425 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700426 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000427 {
428 FlakyHttpFetcherTestDelegate delegate;
429 delegate.loop_ = loop;
430 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
431 fetcher->set_delegate(&delegate);
432
433 typename TestFixture::HttpServer server;
434 ASSERT_TRUE(server.started_);
435
436 StartTransferArgs start_xfer_args = {
437 fetcher.get(),
438 LocalServerUrlForPath("/flaky")
439 };
440
441 g_timeout_add(0, StartTransfer, &start_xfer_args);
442 g_main_loop_run(loop);
443
444 // verify the data we get back
445 ASSERT_EQ(100000, delegate.data.size());
446 for (int i = 0; i < 100000; i += 10) {
447 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
448 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
449 }
450 }
451 g_main_loop_unref(loop);
452}
453
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700454namespace {
455class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
456 public:
457 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
458 virtual void ReceivedBytes(HttpFetcher* fetcher,
459 const char* bytes, int length) {
460 if (server_) {
461 LOG(INFO) << "Stopping server";
462 delete server_;
463 LOG(INFO) << "server stopped";
464 server_ = NULL;
465 }
466 }
467 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
468 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700469 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700470 g_main_loop_quit(loop_);
471 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800472 virtual void TransferTerminated(HttpFetcher* fetcher) {
473 ADD_FAILURE();
474 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700475 GMainLoop* loop_;
476 PythonHttpServer* server_;
477};
478} // namespace {}
479
480
481TYPED_TEST(HttpFetcherTest, FailureTest) {
482 if (this->IsMock())
483 return;
484 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
485 {
486 FailureHttpFetcherTestDelegate delegate;
487 delegate.loop_ = loop;
488 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
489 fetcher->set_delegate(&delegate);
490
491 StartTransferArgs start_xfer_args = {
492 fetcher.get(),
493 LocalServerUrlForPath(this->SmallUrl())
494 };
495
496 g_timeout_add(0, StartTransfer, &start_xfer_args);
497 g_main_loop_run(loop);
498
499 // Exiting and testing happens in the delegate
500 }
501 g_main_loop_unref(loop);
502}
503
504TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
505 if (this->IsMock())
506 return;
507 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
508 {
509 FailureHttpFetcherTestDelegate delegate;
510 delegate.loop_ = loop;
511 delegate.server_ = new PythonHttpServer;
512 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
513 fetcher->set_delegate(&delegate);
514
515 StartTransferArgs start_xfer_args = {
516 fetcher.get(),
517 LocalServerUrlForPath("/flaky")
518 };
519
520 g_timeout_add(0, StartTransfer, &start_xfer_args);
521 g_main_loop_run(loop);
522
523 // Exiting and testing happens in the delegate
524 }
525 g_main_loop_unref(loop);
526}
527
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700528namespace {
529const int kRedirectCodes[] = { 301, 302, 303, 307 };
530
531class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
532 public:
533 RedirectHttpFetcherTestDelegate(bool expected_successful)
534 : expected_successful_(expected_successful) {}
535 virtual void ReceivedBytes(HttpFetcher* fetcher,
536 const char* bytes, int length) {
537 data.append(bytes, length);
538 }
539 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
540 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700541 if (expected_successful_)
542 EXPECT_EQ(200, fetcher->http_response_code());
543 else {
544 EXPECT_GE(fetcher->http_response_code(), 301);
545 EXPECT_LE(fetcher->http_response_code(), 307);
546 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700547 g_main_loop_quit(loop_);
548 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800549 virtual void TransferTerminated(HttpFetcher* fetcher) {
550 ADD_FAILURE();
551 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700552 bool expected_successful_;
553 string data;
554 GMainLoop* loop_;
555};
556
557// RedirectTest takes ownership of |http_fetcher|.
558void RedirectTest(bool expected_successful,
559 const string& url,
560 HttpFetcher* http_fetcher) {
561 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
562 RedirectHttpFetcherTestDelegate delegate(expected_successful);
563 delegate.loop_ = loop;
564 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
565 fetcher->set_delegate(&delegate);
566
567 StartTransferArgs start_xfer_args =
568 { fetcher.get(), LocalServerUrlForPath(url) };
569
570 g_timeout_add(0, StartTransfer, &start_xfer_args);
571 g_main_loop_run(loop);
572 if (expected_successful) {
573 // verify the data we get back
574 ASSERT_EQ(1000, delegate.data.size());
575 for (int i = 0; i < 1000; i += 10) {
576 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
577 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
578 }
579 }
580 g_main_loop_unref(loop);
581}
582} // namespace {}
583
584TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
585 if (this->IsMock())
586 return;
587 typename TestFixture::HttpServer server;
588 ASSERT_TRUE(server.started_);
589 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
590 const string url = base::StringPrintf("/redirect/%d/medium",
591 kRedirectCodes[c]);
592 RedirectTest(true, url, this->NewLargeFetcher());
593 }
594}
595
596TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
597 if (this->IsMock())
598 return;
599 typename TestFixture::HttpServer server;
600 ASSERT_TRUE(server.started_);
601 string url;
602 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
603 url += base::StringPrintf("/redirect/%d",
604 kRedirectCodes[r % arraysize(kRedirectCodes)]);
605 }
606 url += "/medium";
607 RedirectTest(true, url, this->NewLargeFetcher());
608}
609
610TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
611 if (this->IsMock())
612 return;
613 typename TestFixture::HttpServer server;
614 ASSERT_TRUE(server.started_);
615 string url;
616 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
617 url += base::StringPrintf("/redirect/%d",
618 kRedirectCodes[r % arraysize(kRedirectCodes)]);
619 }
620 url += "/medium";
621 RedirectTest(false, url, this->NewLargeFetcher());
622}
623
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700624namespace {
625class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
626 public:
627 MultiHttpFetcherTestDelegate(int expected_response_code)
628 : expected_response_code_(expected_response_code) {}
629 virtual void ReceivedBytes(HttpFetcher* fetcher,
630 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800631 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700632 data.append(bytes, length);
633 }
634 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800635 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700636 EXPECT_EQ(expected_response_code_ != 0, successful);
637 if (expected_response_code_ != 0)
638 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800639 // Destroy the fetcher (because we're allowed to).
640 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700641 g_main_loop_quit(loop_);
642 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800643 virtual void TransferTerminated(HttpFetcher* fetcher) {
644 ADD_FAILURE();
645 }
646 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700647 int expected_response_code_;
648 string data;
649 GMainLoop* loop_;
650};
651
652void MultiTest(HttpFetcher* fetcher_in,
653 const string& url,
654 const MultiHttpFetcher<LibcurlHttpFetcher>::RangesVect& ranges,
655 const string& expected_prefix,
656 off_t expected_size,
657 int expected_response_code) {
658 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
659 {
660 MultiHttpFetcherTestDelegate delegate(expected_response_code);
661 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800662 delegate.fetcher_.reset(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700663 MultiHttpFetcher<LibcurlHttpFetcher>* multi_fetcher =
Darin Petkov9ce452b2010-11-17 14:33:28 -0800664 dynamic_cast<MultiHttpFetcher<LibcurlHttpFetcher>*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700665 ASSERT_TRUE(multi_fetcher);
666 multi_fetcher->set_ranges(ranges);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700667 multi_fetcher->SetConnectionAsExpensive(false);
668 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800669 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700670
Darin Petkov9ce452b2010-11-17 14:33:28 -0800671 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700672
673 g_timeout_add(0, StartTransfer, &start_xfer_args);
674 g_main_loop_run(loop);
675
676 EXPECT_EQ(expected_size, delegate.data.size());
677 EXPECT_EQ(expected_prefix,
678 string(delegate.data.data(), expected_prefix.size()));
679 }
680 g_main_loop_unref(loop);
681}
682} // namespace {}
683
Darin Petkov9ce452b2010-11-17 14:33:28 -0800684TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700685 if (!this->IsMulti())
686 return;
687 typename TestFixture::HttpServer server;
688 ASSERT_TRUE(server.started_);
689
690 MultiHttpFetcher<LibcurlHttpFetcher>::RangesVect ranges;
691 ranges.push_back(make_pair(0, 25));
692 ranges.push_back(make_pair(99, -1));
693 MultiTest(this->NewLargeFetcher(),
694 this->BigUrl(),
695 ranges,
696 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
697 kBigSize - (99 - 25),
698 206);
699}
700
701TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
702 if (!this->IsMulti())
703 return;
704 typename TestFixture::HttpServer server;
705 ASSERT_TRUE(server.started_);
706
707 MultiHttpFetcher<LibcurlHttpFetcher>::RangesVect ranges;
708 ranges.push_back(make_pair(0, 24));
709 MultiTest(this->NewLargeFetcher(),
710 this->BigUrl(),
711 ranges,
712 "abcdefghijabcdefghijabcd",
713 24,
714 200);
715}
716
717TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
718 if (!this->IsMulti())
719 return;
720 typename TestFixture::HttpServer server;
721 ASSERT_TRUE(server.started_);
722
723 MultiHttpFetcher<LibcurlHttpFetcher>::RangesVect ranges;
724 ranges.push_back(make_pair(kBigSize - 2, -1));
725 ranges.push_back(make_pair(kBigSize - 3, -1));
726 MultiTest(this->NewLargeFetcher(),
727 this->BigUrl(),
728 ranges,
729 "ijhij",
730 5,
731 206);
732}
733
734TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
735 if (!this->IsMulti())
736 return;
737 typename TestFixture::HttpServer server;
738 ASSERT_TRUE(server.started_);
739
740 MultiHttpFetcher<LibcurlHttpFetcher>::RangesVect ranges;
741 ranges.push_back(make_pair(kBigSize - 2, 4));
742 for (int i = 0; i < 2; ++i) {
743 MultiTest(this->NewLargeFetcher(),
744 this->BigUrl(),
745 ranges,
746 "ij",
747 2,
748 0);
749 ranges.push_back(make_pair(0, 5));
750 }
751}
752
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700753namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700754class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700755 public:
756 virtual void ReceivedBytes(HttpFetcher* fetcher,
757 const char* bytes, int length) {
758 ADD_FAILURE();
759 }
760 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
761 EXPECT_FALSE(successful);
762 g_main_loop_quit(loop_);
763 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800764 virtual void TransferTerminated(HttpFetcher* fetcher) {
765 ADD_FAILURE();
766 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700767 GMainLoop* loop_;
768};
769
770} // namespace
771
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700772TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700773 if (this->IsMock() || this->IsMulti())
774 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700775
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700776 for (int i = 0; i < 2; i++) {
777 typename TestFixture::HttpServer server;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700778
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700779 ASSERT_TRUE(server.started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700780
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700781 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
782 BlockedTransferTestDelegate delegate;
783 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700784
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700785 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
786 LibcurlHttpFetcher* curl_fetcher =
787 dynamic_cast<LibcurlHttpFetcher*>(fetcher.get());
788 bool is_expensive_connection = (i == 0);
789 bool is_official_build = (i == 1);
790 LOG(INFO) << "is_expensive_connection: " << is_expensive_connection;
791 LOG(INFO) << "is_official_build: " << is_official_build;
792 curl_fetcher->SetConnectionAsExpensive(is_expensive_connection);
793 curl_fetcher->SetBuildType(is_official_build);
794 fetcher->set_delegate(&delegate);
795
796 StartTransferArgs start_xfer_args =
797 { fetcher.get(), LocalServerUrlForPath(this->SmallUrl()) };
798
799 g_timeout_add(0, StartTransfer, &start_xfer_args);
800 g_main_loop_run(loop);
801 g_main_loop_unref(loop);
802 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700803}
804
rspangler@google.com49fdf182009-10-10 00:57:34 +0000805} // namespace chromeos_update_engine