blob: 5377cd37fe324331e9284704825b11a4718745d7 [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>
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>
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 Reyese7dcc2a2011-08-19 10:50:37 -0700105 const uint64_t kMaxSleep = 60UL * 60UL * 1000UL * 1000UL; // 60 min
106 uint64_t timeout = 15 * 1000; // 15 ms
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700107 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000108 while (0 != rc) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700109 LOG(INFO) << "running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000110 rc = system((string("wget --output-document=/dev/null ") +
111 LocalServerUrlForPath("/test")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700112 LOG(INFO) << "done running wget to start";
Andrew de los Reyese7dcc2a2011-08-19 10:50:37 -0700113 if (timeout < (1000 * 1000)) // sub 1-second sleep, use usleep
114 usleep(static_cast<useconds_t>(timeout));
115 else
116 sleep(static_cast<unsigned int>(timeout / (1000 * 1000)));
117 timeout *= 2;
118 if (timeout > kMaxSleep) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700119 LOG(ERROR) << "Unable to start server.";
120 started_ = false;
121 break;
122 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000123 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000124 free(argv[0]);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700125 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000126 return;
127 }
128 ~PythonHttpServer() {
129 if (!started_)
130 return;
131 // request that the server exit itself
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700132 LOG(INFO) << "running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700133 int rc = system((string("wget -t 1 --output-document=/dev/null ") +
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700134 LocalServerUrlForPath("/quitquitquit")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700135 LOG(INFO) << "done running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700136 if (validate_quit_)
137 EXPECT_EQ(0, rc);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000138 waitpid(pid_, NULL, 0);
139 }
140 GPid pid_;
141 bool started_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700142 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000143};
144
145template <>
146class HttpFetcherTest<LibcurlHttpFetcher> : public ::testing::Test {
147 public:
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700148 virtual HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -0800149 LibcurlHttpFetcher *ret = new
150 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
Darin Petkovb83371f2010-08-17 09:34:49 -0700151 // Speed up test execution.
152 ret->set_idle_seconds(1);
153 ret->set_retry_seconds(1);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700154 ret->SetConnectionAsExpensive(false);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700155 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000156 return ret;
157 }
158 HttpFetcher* NewSmallFetcher() {
159 return NewLargeFetcher();
160 }
161 string BigUrl() const {
162 return LocalServerUrlForPath("/big");
163 }
164 string SmallUrl() const {
165 return LocalServerUrlForPath("/foo");
166 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000167 bool IsMock() const { return false; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700168 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000169 typedef PythonHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700170 void IgnoreServerAborting(HttpServer* server) const {
171 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
172 pyserver->validate_quit_ = false;
173 }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800174 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000175};
176
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700177template <>
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800178class HttpFetcherTest<MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700179 : public HttpFetcherTest<LibcurlHttpFetcher> {
180 public:
181 HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800182 ProxyResolver* resolver =
183 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
184 MultiRangeHTTPFetcher *ret =
185 new MultiRangeHTTPFetcher(new LibcurlHttpFetcher(resolver));
186 ret->ClearRanges();
187 ret->AddRange(0, -1);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700188 // Speed up test execution.
189 ret->set_idle_seconds(1);
190 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700191 ret->SetConnectionAsExpensive(false);
192 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700193 return ret;
194 }
195 bool IsMulti() const { return true; }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800196 DirectProxyResolver proxy_resolver_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700197};
198
199typedef ::testing::Types<LibcurlHttpFetcher,
200 MockHttpFetcher,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800201 MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700202HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000203TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
204
205namespace {
206class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000207 public:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000208 virtual void ReceivedBytes(HttpFetcher* fetcher,
209 const char* bytes, int length) {
210 char str[length + 1];
211 memset(str, 0, length + 1);
212 memcpy(str, bytes, length);
213 }
214 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkovcb466212010-08-26 09:40:11 -0700215 EXPECT_EQ(200, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000216 g_main_loop_quit(loop_);
217 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800218 virtual void TransferTerminated(HttpFetcher* fetcher) {
219 ADD_FAILURE();
220 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000221 GMainLoop* loop_;
222};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000223
224struct StartTransferArgs {
225 HttpFetcher *http_fetcher;
226 string url;
227};
228
229gboolean StartTransfer(gpointer data) {
230 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
231 args->http_fetcher->BeginTransfer(args->url);
232 return FALSE;
233}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000234} // namespace {}
235
236TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700237 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000238 {
239 HttpFetcherTestDelegate delegate;
240 delegate.loop_ = loop;
241 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
242 fetcher->set_delegate(&delegate);
243
244 typename TestFixture::HttpServer server;
245 ASSERT_TRUE(server.started_);
246
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000247 StartTransferArgs start_xfer_args = {fetcher.get(), this->SmallUrl()};
248
249 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000250 g_main_loop_run(loop);
251 }
252 g_main_loop_unref(loop);
253}
254
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700255TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700256 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700257 {
258 HttpFetcherTestDelegate delegate;
259 delegate.loop_ = loop;
260 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
261 fetcher->set_delegate(&delegate);
262
263 typename TestFixture::HttpServer server;
264 ASSERT_TRUE(server.started_);
265
266 StartTransferArgs start_xfer_args = {fetcher.get(), this->BigUrl()};
267
268 g_timeout_add(0, StartTransfer, &start_xfer_args);
269 g_main_loop_run(loop);
270 }
271 g_main_loop_unref(loop);
272}
273
rspangler@google.com49fdf182009-10-10 00:57:34 +0000274namespace {
275class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
276 public:
277 virtual void ReceivedBytes(HttpFetcher* fetcher,
278 const char* bytes, int length) {
279 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000280 memset(str, 0, length + 1);
281 memcpy(str, bytes, length);
282 CHECK(!paused_);
283 paused_ = true;
284 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000285 }
286 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
287 g_main_loop_quit(loop_);
288 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800289 virtual void TransferTerminated(HttpFetcher* fetcher) {
290 ADD_FAILURE();
291 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000292 void Unpause() {
293 CHECK(paused_);
294 paused_ = false;
295 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000296 }
297 bool paused_;
298 HttpFetcher* fetcher_;
299 GMainLoop* loop_;
300};
301
302gboolean UnpausingTimeoutCallback(gpointer data) {
303 PausingHttpFetcherTestDelegate *delegate =
304 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
305 if (delegate->paused_)
306 delegate->Unpause();
307 return TRUE;
308}
309} // namespace {}
310
311TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700312 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000313 {
314 PausingHttpFetcherTestDelegate delegate;
315 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
316 delegate.paused_ = false;
317 delegate.loop_ = loop;
318 delegate.fetcher_ = fetcher.get();
319 fetcher->set_delegate(&delegate);
320
321 typename TestFixture::HttpServer server;
322 ASSERT_TRUE(server.started_);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800323
324 guint callback_id = g_timeout_add(500, UnpausingTimeoutCallback, &delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000325 fetcher->BeginTransfer(this->BigUrl());
326
327 g_main_loop_run(loop);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800328 g_source_remove(callback_id);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000329 }
330 g_main_loop_unref(loop);
331}
332
333namespace {
334class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
335 public:
336 virtual void ReceivedBytes(HttpFetcher* fetcher,
337 const char* bytes, int length) {}
338 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800339 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000340 g_main_loop_quit(loop_);
341 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800342 virtual void TransferTerminated(HttpFetcher* fetcher) {
343 EXPECT_EQ(fetcher, fetcher_.get());
344 EXPECT_FALSE(once_);
345 EXPECT_TRUE(callback_once_);
346 callback_once_ = false;
347 // |fetcher| can be destroyed during this callback.
348 fetcher_.reset(NULL);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800349 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000350 void TerminateTransfer() {
351 CHECK(once_);
352 once_ = false;
353 fetcher_->TerminateTransfer();
354 }
355 void EndLoop() {
356 g_main_loop_quit(loop_);
357 }
358 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800359 bool callback_once_;
360 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000361 GMainLoop* loop_;
362};
363
364gboolean AbortingTimeoutCallback(gpointer data) {
365 AbortingHttpFetcherTestDelegate *delegate =
366 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
367 if (delegate->once_) {
368 delegate->TerminateTransfer();
369 return TRUE;
370 } else {
371 delegate->EndLoop();
372 return FALSE;
373 }
374}
375} // namespace {}
376
377TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700378 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000379 {
380 AbortingHttpFetcherTestDelegate delegate;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800381 delegate.fetcher_.reset(this->NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000382 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800383 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000384 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800385 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000386
387 typename TestFixture::HttpServer server;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700388 this->IgnoreServerAborting(&server);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000389 ASSERT_TRUE(server.started_);
390 GSource* timeout_source_;
391 timeout_source_ = g_timeout_source_new(0); // ms
392 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
393 NULL);
394 g_source_attach(timeout_source_, NULL);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800395 delegate.fetcher_->BeginTransfer(this->BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000396
397 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800398 CHECK(!delegate.once_);
399 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000400 g_source_destroy(timeout_source_);
401 }
402 g_main_loop_unref(loop);
403}
404
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000405namespace {
406class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
407 public:
408 virtual void ReceivedBytes(HttpFetcher* fetcher,
409 const char* bytes, int length) {
410 data.append(bytes, length);
411 }
412 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700413 EXPECT_TRUE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700414 EXPECT_EQ(206, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000415 g_main_loop_quit(loop_);
416 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800417 virtual void TransferTerminated(HttpFetcher* fetcher) {
418 ADD_FAILURE();
419 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000420 string data;
421 GMainLoop* loop_;
422};
423} // namespace {}
424
425TYPED_TEST(HttpFetcherTest, FlakyTest) {
426 if (this->IsMock())
427 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700428 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000429 {
430 FlakyHttpFetcherTestDelegate delegate;
431 delegate.loop_ = loop;
432 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
433 fetcher->set_delegate(&delegate);
434
435 typename TestFixture::HttpServer server;
436 ASSERT_TRUE(server.started_);
437
438 StartTransferArgs start_xfer_args = {
439 fetcher.get(),
440 LocalServerUrlForPath("/flaky")
441 };
442
443 g_timeout_add(0, StartTransfer, &start_xfer_args);
444 g_main_loop_run(loop);
445
446 // verify the data we get back
447 ASSERT_EQ(100000, delegate.data.size());
448 for (int i = 0; i < 100000; i += 10) {
449 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
450 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
451 }
452 }
453 g_main_loop_unref(loop);
454}
455
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700456namespace {
457class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
458 public:
459 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
460 virtual void ReceivedBytes(HttpFetcher* fetcher,
461 const char* bytes, int length) {
462 if (server_) {
463 LOG(INFO) << "Stopping server";
464 delete server_;
465 LOG(INFO) << "server stopped";
466 server_ = NULL;
467 }
468 }
469 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
470 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700471 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700472 g_main_loop_quit(loop_);
473 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800474 virtual void TransferTerminated(HttpFetcher* fetcher) {
475 ADD_FAILURE();
476 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700477 GMainLoop* loop_;
478 PythonHttpServer* server_;
479};
480} // namespace {}
481
482
483TYPED_TEST(HttpFetcherTest, FailureTest) {
484 if (this->IsMock())
485 return;
486 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
487 {
488 FailureHttpFetcherTestDelegate delegate;
489 delegate.loop_ = loop;
490 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
491 fetcher->set_delegate(&delegate);
492
493 StartTransferArgs start_xfer_args = {
494 fetcher.get(),
495 LocalServerUrlForPath(this->SmallUrl())
496 };
497
498 g_timeout_add(0, StartTransfer, &start_xfer_args);
499 g_main_loop_run(loop);
500
501 // Exiting and testing happens in the delegate
502 }
503 g_main_loop_unref(loop);
504}
505
506TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
507 if (this->IsMock())
508 return;
509 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
510 {
511 FailureHttpFetcherTestDelegate delegate;
512 delegate.loop_ = loop;
513 delegate.server_ = new PythonHttpServer;
514 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
515 fetcher->set_delegate(&delegate);
516
517 StartTransferArgs start_xfer_args = {
518 fetcher.get(),
519 LocalServerUrlForPath("/flaky")
520 };
521
522 g_timeout_add(0, StartTransfer, &start_xfer_args);
523 g_main_loop_run(loop);
524
525 // Exiting and testing happens in the delegate
526 }
527 g_main_loop_unref(loop);
528}
529
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700530namespace {
531const int kRedirectCodes[] = { 301, 302, 303, 307 };
532
533class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
534 public:
535 RedirectHttpFetcherTestDelegate(bool expected_successful)
536 : expected_successful_(expected_successful) {}
537 virtual void ReceivedBytes(HttpFetcher* fetcher,
538 const char* bytes, int length) {
539 data.append(bytes, length);
540 }
541 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
542 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700543 if (expected_successful_)
544 EXPECT_EQ(200, fetcher->http_response_code());
545 else {
546 EXPECT_GE(fetcher->http_response_code(), 301);
547 EXPECT_LE(fetcher->http_response_code(), 307);
548 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700549 g_main_loop_quit(loop_);
550 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800551 virtual void TransferTerminated(HttpFetcher* fetcher) {
552 ADD_FAILURE();
553 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700554 bool expected_successful_;
555 string data;
556 GMainLoop* loop_;
557};
558
559// RedirectTest takes ownership of |http_fetcher|.
560void RedirectTest(bool expected_successful,
561 const string& url,
562 HttpFetcher* http_fetcher) {
563 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
564 RedirectHttpFetcherTestDelegate delegate(expected_successful);
565 delegate.loop_ = loop;
566 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
567 fetcher->set_delegate(&delegate);
568
569 StartTransferArgs start_xfer_args =
570 { fetcher.get(), LocalServerUrlForPath(url) };
571
572 g_timeout_add(0, StartTransfer, &start_xfer_args);
573 g_main_loop_run(loop);
574 if (expected_successful) {
575 // verify the data we get back
576 ASSERT_EQ(1000, delegate.data.size());
577 for (int i = 0; i < 1000; i += 10) {
578 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
579 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
580 }
581 }
582 g_main_loop_unref(loop);
583}
584} // namespace {}
585
586TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
587 if (this->IsMock())
588 return;
589 typename TestFixture::HttpServer server;
590 ASSERT_TRUE(server.started_);
591 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
592 const string url = base::StringPrintf("/redirect/%d/medium",
593 kRedirectCodes[c]);
594 RedirectTest(true, url, this->NewLargeFetcher());
595 }
596}
597
598TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
599 if (this->IsMock())
600 return;
601 typename TestFixture::HttpServer server;
602 ASSERT_TRUE(server.started_);
603 string url;
604 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
605 url += base::StringPrintf("/redirect/%d",
606 kRedirectCodes[r % arraysize(kRedirectCodes)]);
607 }
608 url += "/medium";
609 RedirectTest(true, url, this->NewLargeFetcher());
610}
611
612TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
613 if (this->IsMock())
614 return;
615 typename TestFixture::HttpServer server;
616 ASSERT_TRUE(server.started_);
617 string url;
618 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
619 url += base::StringPrintf("/redirect/%d",
620 kRedirectCodes[r % arraysize(kRedirectCodes)]);
621 }
622 url += "/medium";
623 RedirectTest(false, url, this->NewLargeFetcher());
624}
625
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700626namespace {
627class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
628 public:
629 MultiHttpFetcherTestDelegate(int expected_response_code)
630 : expected_response_code_(expected_response_code) {}
631 virtual void ReceivedBytes(HttpFetcher* fetcher,
632 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800633 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700634 data.append(bytes, length);
635 }
636 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800637 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700638 EXPECT_EQ(expected_response_code_ != 0, successful);
639 if (expected_response_code_ != 0)
640 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800641 // Destroy the fetcher (because we're allowed to).
642 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700643 g_main_loop_quit(loop_);
644 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800645 virtual void TransferTerminated(HttpFetcher* fetcher) {
646 ADD_FAILURE();
647 }
648 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700649 int expected_response_code_;
650 string data;
651 GMainLoop* loop_;
652};
653
654void MultiTest(HttpFetcher* fetcher_in,
655 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800656 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700657 const string& expected_prefix,
658 off_t expected_size,
659 int expected_response_code) {
660 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
661 {
662 MultiHttpFetcherTestDelegate delegate(expected_response_code);
663 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800664 delegate.fetcher_.reset(fetcher_in);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800665 MultiRangeHTTPFetcher* multi_fetcher =
666 dynamic_cast<MultiRangeHTTPFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700667 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800668 multi_fetcher->ClearRanges();
669 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
670 e = ranges.end(); it != e; ++it) {
671 LOG(INFO) << "Adding range";
672 multi_fetcher->AddRange(it->first, it->second);
673 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700674 multi_fetcher->SetConnectionAsExpensive(false);
675 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800676 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700677
Darin Petkov9ce452b2010-11-17 14:33:28 -0800678 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700679
680 g_timeout_add(0, StartTransfer, &start_xfer_args);
681 g_main_loop_run(loop);
682
683 EXPECT_EQ(expected_size, delegate.data.size());
684 EXPECT_EQ(expected_prefix,
685 string(delegate.data.data(), expected_prefix.size()));
686 }
687 g_main_loop_unref(loop);
688}
689} // namespace {}
690
Darin Petkov9ce452b2010-11-17 14:33:28 -0800691TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700692 if (!this->IsMulti())
693 return;
694 typename TestFixture::HttpServer server;
695 ASSERT_TRUE(server.started_);
696
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800697 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700698 ranges.push_back(make_pair(0, 25));
699 ranges.push_back(make_pair(99, -1));
700 MultiTest(this->NewLargeFetcher(),
701 this->BigUrl(),
702 ranges,
703 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
704 kBigSize - (99 - 25),
705 206);
706}
707
708TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
709 if (!this->IsMulti())
710 return;
711 typename TestFixture::HttpServer server;
712 ASSERT_TRUE(server.started_);
713
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800714 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700715 ranges.push_back(make_pair(0, 24));
716 MultiTest(this->NewLargeFetcher(),
717 this->BigUrl(),
718 ranges,
719 "abcdefghijabcdefghijabcd",
720 24,
721 200);
722}
723
724TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
725 if (!this->IsMulti())
726 return;
727 typename TestFixture::HttpServer server;
728 ASSERT_TRUE(server.started_);
729
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800730 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700731 ranges.push_back(make_pair(kBigSize - 2, -1));
732 ranges.push_back(make_pair(kBigSize - 3, -1));
733 MultiTest(this->NewLargeFetcher(),
734 this->BigUrl(),
735 ranges,
736 "ijhij",
737 5,
738 206);
739}
740
741TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
742 if (!this->IsMulti())
743 return;
744 typename TestFixture::HttpServer server;
745 ASSERT_TRUE(server.started_);
746
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800747 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700748 ranges.push_back(make_pair(kBigSize - 2, 4));
749 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800750 LOG(INFO) << "i = " << i;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700751 MultiTest(this->NewLargeFetcher(),
752 this->BigUrl(),
753 ranges,
754 "ij",
755 2,
756 0);
757 ranges.push_back(make_pair(0, 5));
758 }
759}
760
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700761namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700762class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700763 public:
764 virtual void ReceivedBytes(HttpFetcher* fetcher,
765 const char* bytes, int length) {
766 ADD_FAILURE();
767 }
768 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
769 EXPECT_FALSE(successful);
770 g_main_loop_quit(loop_);
771 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800772 virtual void TransferTerminated(HttpFetcher* fetcher) {
773 ADD_FAILURE();
774 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700775 GMainLoop* loop_;
776};
777
778} // namespace
779
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700780TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700781 if (this->IsMock() || this->IsMulti())
782 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700783
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700784 for (int i = 0; i < 2; i++) {
785 typename TestFixture::HttpServer server;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700786
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700787 ASSERT_TRUE(server.started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700788
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700789 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
790 BlockedTransferTestDelegate delegate;
791 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700792
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700793 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
794 LibcurlHttpFetcher* curl_fetcher =
795 dynamic_cast<LibcurlHttpFetcher*>(fetcher.get());
796 bool is_expensive_connection = (i == 0);
797 bool is_official_build = (i == 1);
798 LOG(INFO) << "is_expensive_connection: " << is_expensive_connection;
799 LOG(INFO) << "is_official_build: " << is_official_build;
800 curl_fetcher->SetConnectionAsExpensive(is_expensive_connection);
801 curl_fetcher->SetBuildType(is_official_build);
802 fetcher->set_delegate(&delegate);
803
804 StartTransferArgs start_xfer_args =
805 { fetcher.get(), LocalServerUrlForPath(this->SmallUrl()) };
806
807 g_timeout_add(0, StartTransfer, &start_xfer_args);
808 g_main_loop_run(loop);
809 g_main_loop_unref(loop);
810 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700811}
812
rspangler@google.com49fdf182009-10-10 00:57:34 +0000813} // namespace chromeos_update_engine