blob: 66552ff796ec4f2a17e520a40ed97f5b6e9e2c65 [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";
Josh Horwich2d4e1c52011-08-22 11:58:02 -0700113 if (0 != rc) {
114 if (timeout > kMaxSleep) {
115 LOG(ERROR) << "Unable to start server.";
116 started_ = false;
117 break;
118 }
119 if (timeout < (1000 * 1000)) // sub 1-second sleep, use usleep
120 usleep(static_cast<useconds_t>(timeout));
121 else
122 sleep(static_cast<unsigned int>(timeout / (1000 * 1000)));
123 timeout *= 2;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700124 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000125 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000126 free(argv[0]);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700127 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000128 return;
129 }
130 ~PythonHttpServer() {
131 if (!started_)
132 return;
133 // request that the server exit itself
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700134 LOG(INFO) << "running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700135 int rc = system((string("wget -t 1 --output-document=/dev/null ") +
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700136 LocalServerUrlForPath("/quitquitquit")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700137 LOG(INFO) << "done running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700138 if (validate_quit_)
139 EXPECT_EQ(0, rc);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000140 waitpid(pid_, NULL, 0);
141 }
142 GPid pid_;
143 bool started_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700144 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000145};
146
147template <>
148class HttpFetcherTest<LibcurlHttpFetcher> : public ::testing::Test {
149 public:
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700150 virtual HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -0800151 LibcurlHttpFetcher *ret = new
152 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
Darin Petkovb83371f2010-08-17 09:34:49 -0700153 // Speed up test execution.
154 ret->set_idle_seconds(1);
155 ret->set_retry_seconds(1);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700156 ret->SetConnectionAsExpensive(false);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700157 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000158 return ret;
159 }
160 HttpFetcher* NewSmallFetcher() {
161 return NewLargeFetcher();
162 }
163 string BigUrl() const {
164 return LocalServerUrlForPath("/big");
165 }
166 string SmallUrl() const {
167 return LocalServerUrlForPath("/foo");
168 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000169 bool IsMock() const { return false; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700170 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000171 typedef PythonHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700172 void IgnoreServerAborting(HttpServer* server) const {
173 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
174 pyserver->validate_quit_ = false;
175 }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800176 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000177};
178
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700179template <>
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800180class HttpFetcherTest<MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700181 : public HttpFetcherTest<LibcurlHttpFetcher> {
182 public:
183 HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800184 ProxyResolver* resolver =
185 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
186 MultiRangeHTTPFetcher *ret =
187 new MultiRangeHTTPFetcher(new LibcurlHttpFetcher(resolver));
188 ret->ClearRanges();
189 ret->AddRange(0, -1);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700190 // Speed up test execution.
191 ret->set_idle_seconds(1);
192 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700193 ret->SetConnectionAsExpensive(false);
194 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700195 return ret;
196 }
197 bool IsMulti() const { return true; }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800198 DirectProxyResolver proxy_resolver_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700199};
200
201typedef ::testing::Types<LibcurlHttpFetcher,
202 MockHttpFetcher,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800203 MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700204HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000205TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
206
207namespace {
208class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000209 public:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000210 virtual void ReceivedBytes(HttpFetcher* fetcher,
211 const char* bytes, int length) {
212 char str[length + 1];
213 memset(str, 0, length + 1);
214 memcpy(str, bytes, length);
215 }
216 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkovcb466212010-08-26 09:40:11 -0700217 EXPECT_EQ(200, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000218 g_main_loop_quit(loop_);
219 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800220 virtual void TransferTerminated(HttpFetcher* fetcher) {
221 ADD_FAILURE();
222 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000223 GMainLoop* loop_;
224};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000225
226struct StartTransferArgs {
227 HttpFetcher *http_fetcher;
228 string url;
229};
230
231gboolean StartTransfer(gpointer data) {
232 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
233 args->http_fetcher->BeginTransfer(args->url);
234 return FALSE;
235}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000236} // namespace {}
237
238TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700239 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000240 {
241 HttpFetcherTestDelegate delegate;
242 delegate.loop_ = loop;
243 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
244 fetcher->set_delegate(&delegate);
245
246 typename TestFixture::HttpServer server;
247 ASSERT_TRUE(server.started_);
248
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000249 StartTransferArgs start_xfer_args = {fetcher.get(), this->SmallUrl()};
250
251 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000252 g_main_loop_run(loop);
253 }
254 g_main_loop_unref(loop);
255}
256
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700257TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700258 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700259 {
260 HttpFetcherTestDelegate delegate;
261 delegate.loop_ = loop;
262 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
263 fetcher->set_delegate(&delegate);
264
265 typename TestFixture::HttpServer server;
266 ASSERT_TRUE(server.started_);
267
268 StartTransferArgs start_xfer_args = {fetcher.get(), this->BigUrl()};
269
270 g_timeout_add(0, StartTransfer, &start_xfer_args);
271 g_main_loop_run(loop);
272 }
273 g_main_loop_unref(loop);
274}
275
rspangler@google.com49fdf182009-10-10 00:57:34 +0000276namespace {
277class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
278 public:
279 virtual void ReceivedBytes(HttpFetcher* fetcher,
280 const char* bytes, int length) {
281 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000282 memset(str, 0, length + 1);
283 memcpy(str, bytes, length);
284 CHECK(!paused_);
285 paused_ = true;
286 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000287 }
288 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
289 g_main_loop_quit(loop_);
290 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800291 virtual void TransferTerminated(HttpFetcher* fetcher) {
292 ADD_FAILURE();
293 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000294 void Unpause() {
295 CHECK(paused_);
296 paused_ = false;
297 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000298 }
299 bool paused_;
300 HttpFetcher* fetcher_;
301 GMainLoop* loop_;
302};
303
304gboolean UnpausingTimeoutCallback(gpointer data) {
305 PausingHttpFetcherTestDelegate *delegate =
306 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
307 if (delegate->paused_)
308 delegate->Unpause();
309 return TRUE;
310}
311} // namespace {}
312
313TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700314 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000315 {
316 PausingHttpFetcherTestDelegate delegate;
317 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
318 delegate.paused_ = false;
319 delegate.loop_ = loop;
320 delegate.fetcher_ = fetcher.get();
321 fetcher->set_delegate(&delegate);
322
323 typename TestFixture::HttpServer server;
324 ASSERT_TRUE(server.started_);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800325
326 guint callback_id = g_timeout_add(500, UnpausingTimeoutCallback, &delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000327 fetcher->BeginTransfer(this->BigUrl());
328
329 g_main_loop_run(loop);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800330 g_source_remove(callback_id);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000331 }
332 g_main_loop_unref(loop);
333}
334
335namespace {
336class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
337 public:
338 virtual void ReceivedBytes(HttpFetcher* fetcher,
339 const char* bytes, int length) {}
340 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800341 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000342 g_main_loop_quit(loop_);
343 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800344 virtual void TransferTerminated(HttpFetcher* fetcher) {
345 EXPECT_EQ(fetcher, fetcher_.get());
346 EXPECT_FALSE(once_);
347 EXPECT_TRUE(callback_once_);
348 callback_once_ = false;
349 // |fetcher| can be destroyed during this callback.
350 fetcher_.reset(NULL);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800351 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000352 void TerminateTransfer() {
353 CHECK(once_);
354 once_ = false;
355 fetcher_->TerminateTransfer();
356 }
357 void EndLoop() {
358 g_main_loop_quit(loop_);
359 }
360 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800361 bool callback_once_;
362 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000363 GMainLoop* loop_;
364};
365
366gboolean AbortingTimeoutCallback(gpointer data) {
367 AbortingHttpFetcherTestDelegate *delegate =
368 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
369 if (delegate->once_) {
370 delegate->TerminateTransfer();
371 return TRUE;
372 } else {
373 delegate->EndLoop();
374 return FALSE;
375 }
376}
377} // namespace {}
378
379TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700380 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000381 {
382 AbortingHttpFetcherTestDelegate delegate;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800383 delegate.fetcher_.reset(this->NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000384 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800385 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000386 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800387 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000388
389 typename TestFixture::HttpServer server;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700390 this->IgnoreServerAborting(&server);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000391 ASSERT_TRUE(server.started_);
392 GSource* timeout_source_;
393 timeout_source_ = g_timeout_source_new(0); // ms
394 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
395 NULL);
396 g_source_attach(timeout_source_, NULL);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800397 delegate.fetcher_->BeginTransfer(this->BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000398
399 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800400 CHECK(!delegate.once_);
401 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000402 g_source_destroy(timeout_source_);
403 }
404 g_main_loop_unref(loop);
405}
406
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000407namespace {
408class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
409 public:
410 virtual void ReceivedBytes(HttpFetcher* fetcher,
411 const char* bytes, int length) {
412 data.append(bytes, length);
413 }
414 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700415 EXPECT_TRUE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700416 EXPECT_EQ(206, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000417 g_main_loop_quit(loop_);
418 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800419 virtual void TransferTerminated(HttpFetcher* fetcher) {
420 ADD_FAILURE();
421 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000422 string data;
423 GMainLoop* loop_;
424};
425} // namespace {}
426
427TYPED_TEST(HttpFetcherTest, FlakyTest) {
428 if (this->IsMock())
429 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700430 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000431 {
432 FlakyHttpFetcherTestDelegate delegate;
433 delegate.loop_ = loop;
434 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
435 fetcher->set_delegate(&delegate);
436
437 typename TestFixture::HttpServer server;
438 ASSERT_TRUE(server.started_);
439
440 StartTransferArgs start_xfer_args = {
441 fetcher.get(),
442 LocalServerUrlForPath("/flaky")
443 };
444
445 g_timeout_add(0, StartTransfer, &start_xfer_args);
446 g_main_loop_run(loop);
447
448 // verify the data we get back
449 ASSERT_EQ(100000, delegate.data.size());
450 for (int i = 0; i < 100000; i += 10) {
451 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
452 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
453 }
454 }
455 g_main_loop_unref(loop);
456}
457
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700458namespace {
459class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
460 public:
461 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
462 virtual void ReceivedBytes(HttpFetcher* fetcher,
463 const char* bytes, int length) {
464 if (server_) {
465 LOG(INFO) << "Stopping server";
466 delete server_;
467 LOG(INFO) << "server stopped";
468 server_ = NULL;
469 }
470 }
471 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
472 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700473 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700474 g_main_loop_quit(loop_);
475 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800476 virtual void TransferTerminated(HttpFetcher* fetcher) {
477 ADD_FAILURE();
478 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700479 GMainLoop* loop_;
480 PythonHttpServer* server_;
481};
482} // namespace {}
483
484
485TYPED_TEST(HttpFetcherTest, FailureTest) {
486 if (this->IsMock())
487 return;
488 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
489 {
490 FailureHttpFetcherTestDelegate delegate;
491 delegate.loop_ = loop;
492 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
493 fetcher->set_delegate(&delegate);
494
495 StartTransferArgs start_xfer_args = {
496 fetcher.get(),
497 LocalServerUrlForPath(this->SmallUrl())
498 };
499
500 g_timeout_add(0, StartTransfer, &start_xfer_args);
501 g_main_loop_run(loop);
502
503 // Exiting and testing happens in the delegate
504 }
505 g_main_loop_unref(loop);
506}
507
508TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
509 if (this->IsMock())
510 return;
511 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
512 {
513 FailureHttpFetcherTestDelegate delegate;
514 delegate.loop_ = loop;
515 delegate.server_ = new PythonHttpServer;
516 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
517 fetcher->set_delegate(&delegate);
518
519 StartTransferArgs start_xfer_args = {
520 fetcher.get(),
521 LocalServerUrlForPath("/flaky")
522 };
523
524 g_timeout_add(0, StartTransfer, &start_xfer_args);
525 g_main_loop_run(loop);
526
527 // Exiting and testing happens in the delegate
528 }
529 g_main_loop_unref(loop);
530}
531
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700532namespace {
533const int kRedirectCodes[] = { 301, 302, 303, 307 };
534
535class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
536 public:
537 RedirectHttpFetcherTestDelegate(bool expected_successful)
538 : expected_successful_(expected_successful) {}
539 virtual void ReceivedBytes(HttpFetcher* fetcher,
540 const char* bytes, int length) {
541 data.append(bytes, length);
542 }
543 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
544 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700545 if (expected_successful_)
546 EXPECT_EQ(200, fetcher->http_response_code());
547 else {
548 EXPECT_GE(fetcher->http_response_code(), 301);
549 EXPECT_LE(fetcher->http_response_code(), 307);
550 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700551 g_main_loop_quit(loop_);
552 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800553 virtual void TransferTerminated(HttpFetcher* fetcher) {
554 ADD_FAILURE();
555 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700556 bool expected_successful_;
557 string data;
558 GMainLoop* loop_;
559};
560
561// RedirectTest takes ownership of |http_fetcher|.
562void RedirectTest(bool expected_successful,
563 const string& url,
564 HttpFetcher* http_fetcher) {
565 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
566 RedirectHttpFetcherTestDelegate delegate(expected_successful);
567 delegate.loop_ = loop;
568 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
569 fetcher->set_delegate(&delegate);
570
571 StartTransferArgs start_xfer_args =
572 { fetcher.get(), LocalServerUrlForPath(url) };
573
574 g_timeout_add(0, StartTransfer, &start_xfer_args);
575 g_main_loop_run(loop);
576 if (expected_successful) {
577 // verify the data we get back
578 ASSERT_EQ(1000, delegate.data.size());
579 for (int i = 0; i < 1000; i += 10) {
580 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
581 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
582 }
583 }
584 g_main_loop_unref(loop);
585}
586} // namespace {}
587
588TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
589 if (this->IsMock())
590 return;
591 typename TestFixture::HttpServer server;
592 ASSERT_TRUE(server.started_);
593 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
594 const string url = base::StringPrintf("/redirect/%d/medium",
595 kRedirectCodes[c]);
596 RedirectTest(true, url, this->NewLargeFetcher());
597 }
598}
599
600TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
601 if (this->IsMock())
602 return;
603 typename TestFixture::HttpServer server;
604 ASSERT_TRUE(server.started_);
605 string url;
606 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
607 url += base::StringPrintf("/redirect/%d",
608 kRedirectCodes[r % arraysize(kRedirectCodes)]);
609 }
610 url += "/medium";
611 RedirectTest(true, url, this->NewLargeFetcher());
612}
613
614TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
615 if (this->IsMock())
616 return;
617 typename TestFixture::HttpServer server;
618 ASSERT_TRUE(server.started_);
619 string url;
620 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
621 url += base::StringPrintf("/redirect/%d",
622 kRedirectCodes[r % arraysize(kRedirectCodes)]);
623 }
624 url += "/medium";
625 RedirectTest(false, url, this->NewLargeFetcher());
626}
627
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700628namespace {
629class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
630 public:
631 MultiHttpFetcherTestDelegate(int expected_response_code)
632 : expected_response_code_(expected_response_code) {}
633 virtual void ReceivedBytes(HttpFetcher* fetcher,
634 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800635 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700636 data.append(bytes, length);
637 }
638 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800639 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700640 EXPECT_EQ(expected_response_code_ != 0, successful);
641 if (expected_response_code_ != 0)
642 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800643 // Destroy the fetcher (because we're allowed to).
644 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700645 g_main_loop_quit(loop_);
646 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800647 virtual void TransferTerminated(HttpFetcher* fetcher) {
648 ADD_FAILURE();
649 }
650 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700651 int expected_response_code_;
652 string data;
653 GMainLoop* loop_;
654};
655
656void MultiTest(HttpFetcher* fetcher_in,
657 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800658 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700659 const string& expected_prefix,
660 off_t expected_size,
661 int expected_response_code) {
662 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
663 {
664 MultiHttpFetcherTestDelegate delegate(expected_response_code);
665 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800666 delegate.fetcher_.reset(fetcher_in);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800667 MultiRangeHTTPFetcher* multi_fetcher =
668 dynamic_cast<MultiRangeHTTPFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700669 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800670 multi_fetcher->ClearRanges();
671 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
672 e = ranges.end(); it != e; ++it) {
673 LOG(INFO) << "Adding range";
674 multi_fetcher->AddRange(it->first, it->second);
675 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700676 multi_fetcher->SetConnectionAsExpensive(false);
677 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800678 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700679
Darin Petkov9ce452b2010-11-17 14:33:28 -0800680 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700681
682 g_timeout_add(0, StartTransfer, &start_xfer_args);
683 g_main_loop_run(loop);
684
685 EXPECT_EQ(expected_size, delegate.data.size());
686 EXPECT_EQ(expected_prefix,
687 string(delegate.data.data(), expected_prefix.size()));
688 }
689 g_main_loop_unref(loop);
690}
691} // namespace {}
692
Darin Petkov9ce452b2010-11-17 14:33:28 -0800693TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700694 if (!this->IsMulti())
695 return;
696 typename TestFixture::HttpServer server;
697 ASSERT_TRUE(server.started_);
698
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800699 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700700 ranges.push_back(make_pair(0, 25));
701 ranges.push_back(make_pair(99, -1));
702 MultiTest(this->NewLargeFetcher(),
703 this->BigUrl(),
704 ranges,
705 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
706 kBigSize - (99 - 25),
707 206);
708}
709
710TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
711 if (!this->IsMulti())
712 return;
713 typename TestFixture::HttpServer server;
714 ASSERT_TRUE(server.started_);
715
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800716 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700717 ranges.push_back(make_pair(0, 24));
718 MultiTest(this->NewLargeFetcher(),
719 this->BigUrl(),
720 ranges,
721 "abcdefghijabcdefghijabcd",
722 24,
723 200);
724}
725
726TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
727 if (!this->IsMulti())
728 return;
729 typename TestFixture::HttpServer server;
730 ASSERT_TRUE(server.started_);
731
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800732 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700733 ranges.push_back(make_pair(kBigSize - 2, -1));
734 ranges.push_back(make_pair(kBigSize - 3, -1));
735 MultiTest(this->NewLargeFetcher(),
736 this->BigUrl(),
737 ranges,
738 "ijhij",
739 5,
740 206);
741}
742
743TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
744 if (!this->IsMulti())
745 return;
746 typename TestFixture::HttpServer server;
747 ASSERT_TRUE(server.started_);
748
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800749 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700750 ranges.push_back(make_pair(kBigSize - 2, 4));
751 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800752 LOG(INFO) << "i = " << i;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700753 MultiTest(this->NewLargeFetcher(),
754 this->BigUrl(),
755 ranges,
756 "ij",
757 2,
758 0);
759 ranges.push_back(make_pair(0, 5));
760 }
761}
762
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700763namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700764class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700765 public:
766 virtual void ReceivedBytes(HttpFetcher* fetcher,
767 const char* bytes, int length) {
768 ADD_FAILURE();
769 }
770 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
771 EXPECT_FALSE(successful);
772 g_main_loop_quit(loop_);
773 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800774 virtual void TransferTerminated(HttpFetcher* fetcher) {
775 ADD_FAILURE();
776 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700777 GMainLoop* loop_;
778};
779
780} // namespace
781
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700782TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700783 if (this->IsMock() || this->IsMulti())
784 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700785
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700786 for (int i = 0; i < 2; i++) {
787 typename TestFixture::HttpServer server;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700788
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700789 ASSERT_TRUE(server.started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700790
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700791 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
792 BlockedTransferTestDelegate delegate;
793 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700794
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700795 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
796 LibcurlHttpFetcher* curl_fetcher =
797 dynamic_cast<LibcurlHttpFetcher*>(fetcher.get());
798 bool is_expensive_connection = (i == 0);
799 bool is_official_build = (i == 1);
800 LOG(INFO) << "is_expensive_connection: " << is_expensive_connection;
801 LOG(INFO) << "is_official_build: " << is_official_build;
802 curl_fetcher->SetConnectionAsExpensive(is_expensive_connection);
803 curl_fetcher->SetBuildType(is_official_build);
804 fetcher->set_delegate(&delegate);
805
806 StartTransferArgs start_xfer_args =
807 { fetcher.get(), LocalServerUrlForPath(this->SmallUrl()) };
808
809 g_timeout_add(0, StartTransfer, &start_xfer_args);
810 g_main_loop_run(loop);
811 g_main_loop_unref(loop);
812 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700813}
814
rspangler@google.com49fdf182009-10-10 00:57:34 +0000815} // namespace chromeos_update_engine