blob: 2aabfd9d27e76186c179ed6595ae733eebdf8906 [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;
Gilad Arnold48085ba2011-11-16 09:36:08 -080045 string ErrorUrl() const = 0;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000046 bool IsMock() const = 0;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070047 bool IsMulti() const = 0;
rspangler@google.com49fdf182009-10-10 00:57:34 +000048};
49
50class NullHttpServer {
51 public:
52 NullHttpServer() : started_(true) {}
53 ~NullHttpServer() {}
54 bool started_;
55};
56
57
58template <>
59class HttpFetcherTest<MockHttpFetcher> : public ::testing::Test {
60 public:
61 HttpFetcher* NewLargeFetcher() {
62 vector<char> big_data(1000000);
Andrew de los Reyes45168102010-11-22 11:13:50 -080063 return new MockHttpFetcher(
64 big_data.data(),
65 big_data.size(),
66 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
rspangler@google.com49fdf182009-10-10 00:57:34 +000067 }
68 HttpFetcher* NewSmallFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -080069 return new MockHttpFetcher(
70 "x",
71 1,
72 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
rspangler@google.com49fdf182009-10-10 00:57:34 +000073 }
74 string BigUrl() const {
75 return "unused://unused";
76 }
77 string SmallUrl() const {
78 return "unused://unused";
79 }
Gilad Arnold48085ba2011-11-16 09:36:08 -080080 string ErrorUrl() const {
81 return "unused://unused";
82 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +000083 bool IsMock() const { return true; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070084 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +000085 typedef NullHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070086 void IgnoreServerAborting(HttpServer* server) const {}
Andrew de los Reyes45168102010-11-22 11:13:50 -080087
88 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +000089};
90
91class PythonHttpServer {
92 public:
93 PythonHttpServer() {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000094 char *argv[2] = {strdup("./test_http_server"), NULL};
rspangler@google.com49fdf182009-10-10 00:57:34 +000095 GError *err;
96 started_ = false;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070097 validate_quit_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000098 if (!g_spawn_async(NULL,
99 argv,
100 NULL,
101 G_SPAWN_DO_NOT_REAP_CHILD,
102 NULL,
103 NULL,
104 &pid_,
105 &err)) {
106 return;
107 }
108 int rc = 1;
Andrew de los Reyese7dcc2a2011-08-19 10:50:37 -0700109 const uint64_t kMaxSleep = 60UL * 60UL * 1000UL * 1000UL; // 60 min
110 uint64_t timeout = 15 * 1000; // 15 ms
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700111 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000112 while (0 != rc) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700113 LOG(INFO) << "running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000114 rc = system((string("wget --output-document=/dev/null ") +
115 LocalServerUrlForPath("/test")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700116 LOG(INFO) << "done running wget to start";
Josh Horwich2d4e1c52011-08-22 11:58:02 -0700117 if (0 != rc) {
118 if (timeout > kMaxSleep) {
119 LOG(ERROR) << "Unable to start server.";
120 started_ = false;
121 break;
122 }
123 if (timeout < (1000 * 1000)) // sub 1-second sleep, use usleep
124 usleep(static_cast<useconds_t>(timeout));
125 else
126 sleep(static_cast<unsigned int>(timeout / (1000 * 1000)));
127 timeout *= 2;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700128 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000129 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000130 free(argv[0]);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700131 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000132 return;
133 }
134 ~PythonHttpServer() {
135 if (!started_)
136 return;
137 // request that the server exit itself
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700138 LOG(INFO) << "running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700139 int rc = system((string("wget -t 1 --output-document=/dev/null ") +
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700140 LocalServerUrlForPath("/quitquitquit")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700141 LOG(INFO) << "done running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700142 if (validate_quit_)
143 EXPECT_EQ(0, rc);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000144 waitpid(pid_, NULL, 0);
145 }
146 GPid pid_;
147 bool started_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700148 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000149};
150
151template <>
152class HttpFetcherTest<LibcurlHttpFetcher> : public ::testing::Test {
153 public:
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700154 virtual HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -0800155 LibcurlHttpFetcher *ret = new
156 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
Darin Petkovb83371f2010-08-17 09:34:49 -0700157 // Speed up test execution.
158 ret->set_idle_seconds(1);
159 ret->set_retry_seconds(1);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700160 ret->SetConnectionAsExpensive(false);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700161 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000162 return ret;
163 }
164 HttpFetcher* NewSmallFetcher() {
165 return NewLargeFetcher();
166 }
167 string BigUrl() const {
168 return LocalServerUrlForPath("/big");
169 }
170 string SmallUrl() const {
171 return LocalServerUrlForPath("/foo");
172 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800173 string ErrorUrl() const {
174 return LocalServerUrlForPath("/error");
175 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000176 bool IsMock() const { return false; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700177 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000178 typedef PythonHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700179 void IgnoreServerAborting(HttpServer* server) const {
180 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
181 pyserver->validate_quit_ = false;
182 }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800183 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000184};
185
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700186template <>
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800187class HttpFetcherTest<MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700188 : public HttpFetcherTest<LibcurlHttpFetcher> {
189 public:
190 HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800191 ProxyResolver* resolver =
192 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
193 MultiRangeHTTPFetcher *ret =
194 new MultiRangeHTTPFetcher(new LibcurlHttpFetcher(resolver));
195 ret->ClearRanges();
196 ret->AddRange(0, -1);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700197 // Speed up test execution.
198 ret->set_idle_seconds(1);
199 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700200 ret->SetConnectionAsExpensive(false);
201 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700202 return ret;
203 }
204 bool IsMulti() const { return true; }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800205 DirectProxyResolver proxy_resolver_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700206};
207
208typedef ::testing::Types<LibcurlHttpFetcher,
209 MockHttpFetcher,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800210 MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700211HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000212TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
213
214namespace {
215class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000216 public:
Gilad Arnold48085ba2011-11-16 09:36:08 -0800217 HttpFetcherTestDelegate(void) :
218 is_expect_error_(false), times_transfer_complete_called_(0),
219 times_transfer_terminated_called_(0), times_received_bytes_called_(0) {}
220
rspangler@google.com49fdf182009-10-10 00:57:34 +0000221 virtual void ReceivedBytes(HttpFetcher* fetcher,
222 const char* bytes, int length) {
223 char str[length + 1];
224 memset(str, 0, length + 1);
225 memcpy(str, bytes, length);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800226
227 // Update counters
228 times_received_bytes_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000229 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800230
rspangler@google.com49fdf182009-10-10 00:57:34 +0000231 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800232 if (is_expect_error_)
233 EXPECT_EQ(404, fetcher->http_response_code());
234 else
235 EXPECT_EQ(200, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000236 g_main_loop_quit(loop_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800237
238 // Update counter
239 times_transfer_complete_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000240 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800241
Darin Petkov9ce452b2010-11-17 14:33:28 -0800242 virtual void TransferTerminated(HttpFetcher* fetcher) {
243 ADD_FAILURE();
Gilad Arnold48085ba2011-11-16 09:36:08 -0800244 times_transfer_terminated_called_++;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800245 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800246
rspangler@google.com49fdf182009-10-10 00:57:34 +0000247 GMainLoop* loop_;
Gilad Arnold48085ba2011-11-16 09:36:08 -0800248
249 // Are we expecting an error response? (default: no)
250 bool is_expect_error_;
251
252 // Counters for callback invocations.
253 int times_transfer_complete_called_;
254 int times_transfer_terminated_called_;
255 int times_received_bytes_called_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000256};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000257
258struct StartTransferArgs {
259 HttpFetcher *http_fetcher;
260 string url;
261};
262
263gboolean StartTransfer(gpointer data) {
264 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
265 args->http_fetcher->BeginTransfer(args->url);
266 return FALSE;
267}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000268} // namespace {}
269
270TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700271 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000272 {
273 HttpFetcherTestDelegate delegate;
274 delegate.loop_ = loop;
275 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
276 fetcher->set_delegate(&delegate);
277
278 typename TestFixture::HttpServer server;
279 ASSERT_TRUE(server.started_);
280
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000281 StartTransferArgs start_xfer_args = {fetcher.get(), this->SmallUrl()};
282
283 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000284 g_main_loop_run(loop);
285 }
286 g_main_loop_unref(loop);
287}
288
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700289TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700290 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700291 {
292 HttpFetcherTestDelegate delegate;
293 delegate.loop_ = loop;
294 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
295 fetcher->set_delegate(&delegate);
296
297 typename TestFixture::HttpServer server;
298 ASSERT_TRUE(server.started_);
299
300 StartTransferArgs start_xfer_args = {fetcher.get(), this->BigUrl()};
301
302 g_timeout_add(0, StartTransfer, &start_xfer_args);
303 g_main_loop_run(loop);
304 }
305 g_main_loop_unref(loop);
306}
307
Gilad Arnold48085ba2011-11-16 09:36:08 -0800308// Issue #9648: when server returns an error HTTP response, the fetcher needs to
309// terminate transfer prematurely, rather than try to process the error payload.
310TYPED_TEST(HttpFetcherTest, ErrorTest) {
311 if (this->IsMock() || this->IsMulti())
312 return;
313 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
314 {
315 HttpFetcherTestDelegate delegate;
316 delegate.loop_ = loop;
317
318 // Delegate should expect an error response.
319 delegate.is_expect_error_ = true;
320
321 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
322 fetcher->set_delegate(&delegate);
323
324 typename TestFixture::HttpServer server;
325 ASSERT_TRUE(server.started_);
326
327 StartTransferArgs start_xfer_args = {fetcher.get(), this->ErrorUrl()};
328
329 g_timeout_add(0, StartTransfer, &start_xfer_args);
330 g_main_loop_run(loop);
331
332 // Make sure that no bytes were received.
333 CHECK_EQ(delegate.times_received_bytes_called_, 0);
334 CHECK_EQ(fetcher->GetBytesDownloaded(), 0);
335
336 // Make sure that transfer completion was signaled once, and no termination
337 // was signaled.
338 CHECK_EQ(delegate.times_transfer_complete_called_, 1);
339 CHECK_EQ(delegate.times_transfer_terminated_called_, 0);
340 }
341 g_main_loop_unref(loop);
342}
343
344
rspangler@google.com49fdf182009-10-10 00:57:34 +0000345namespace {
346class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
347 public:
348 virtual void ReceivedBytes(HttpFetcher* fetcher,
349 const char* bytes, int length) {
350 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000351 memset(str, 0, length + 1);
352 memcpy(str, bytes, length);
353 CHECK(!paused_);
354 paused_ = true;
355 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000356 }
357 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
358 g_main_loop_quit(loop_);
359 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800360 virtual void TransferTerminated(HttpFetcher* fetcher) {
361 ADD_FAILURE();
362 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000363 void Unpause() {
364 CHECK(paused_);
365 paused_ = false;
366 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000367 }
368 bool paused_;
369 HttpFetcher* fetcher_;
370 GMainLoop* loop_;
371};
372
373gboolean UnpausingTimeoutCallback(gpointer data) {
374 PausingHttpFetcherTestDelegate *delegate =
375 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
376 if (delegate->paused_)
377 delegate->Unpause();
378 return TRUE;
379}
380} // namespace {}
381
382TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700383 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000384 {
385 PausingHttpFetcherTestDelegate delegate;
386 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
387 delegate.paused_ = false;
388 delegate.loop_ = loop;
389 delegate.fetcher_ = fetcher.get();
390 fetcher->set_delegate(&delegate);
391
392 typename TestFixture::HttpServer server;
393 ASSERT_TRUE(server.started_);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800394
395 guint callback_id = g_timeout_add(500, UnpausingTimeoutCallback, &delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000396 fetcher->BeginTransfer(this->BigUrl());
397
398 g_main_loop_run(loop);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800399 g_source_remove(callback_id);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000400 }
401 g_main_loop_unref(loop);
402}
403
404namespace {
405class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
406 public:
407 virtual void ReceivedBytes(HttpFetcher* fetcher,
408 const char* bytes, int length) {}
409 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800410 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000411 g_main_loop_quit(loop_);
412 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800413 virtual void TransferTerminated(HttpFetcher* fetcher) {
414 EXPECT_EQ(fetcher, fetcher_.get());
415 EXPECT_FALSE(once_);
416 EXPECT_TRUE(callback_once_);
417 callback_once_ = false;
418 // |fetcher| can be destroyed during this callback.
419 fetcher_.reset(NULL);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800420 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000421 void TerminateTransfer() {
422 CHECK(once_);
423 once_ = false;
424 fetcher_->TerminateTransfer();
425 }
426 void EndLoop() {
427 g_main_loop_quit(loop_);
428 }
429 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800430 bool callback_once_;
431 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000432 GMainLoop* loop_;
433};
434
435gboolean AbortingTimeoutCallback(gpointer data) {
436 AbortingHttpFetcherTestDelegate *delegate =
437 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
438 if (delegate->once_) {
439 delegate->TerminateTransfer();
440 return TRUE;
441 } else {
442 delegate->EndLoop();
443 return FALSE;
444 }
445}
446} // namespace {}
447
448TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700449 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000450 {
451 AbortingHttpFetcherTestDelegate delegate;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800452 delegate.fetcher_.reset(this->NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000453 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800454 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000455 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800456 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000457
458 typename TestFixture::HttpServer server;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700459 this->IgnoreServerAborting(&server);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000460 ASSERT_TRUE(server.started_);
461 GSource* timeout_source_;
462 timeout_source_ = g_timeout_source_new(0); // ms
463 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
464 NULL);
465 g_source_attach(timeout_source_, NULL);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800466 delegate.fetcher_->BeginTransfer(this->BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000467
468 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800469 CHECK(!delegate.once_);
470 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000471 g_source_destroy(timeout_source_);
472 }
473 g_main_loop_unref(loop);
474}
475
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000476namespace {
477class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
478 public:
479 virtual void ReceivedBytes(HttpFetcher* fetcher,
480 const char* bytes, int length) {
481 data.append(bytes, length);
482 }
483 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700484 EXPECT_TRUE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700485 EXPECT_EQ(206, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000486 g_main_loop_quit(loop_);
487 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800488 virtual void TransferTerminated(HttpFetcher* fetcher) {
489 ADD_FAILURE();
490 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000491 string data;
492 GMainLoop* loop_;
493};
494} // namespace {}
495
496TYPED_TEST(HttpFetcherTest, FlakyTest) {
497 if (this->IsMock())
498 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700499 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000500 {
501 FlakyHttpFetcherTestDelegate delegate;
502 delegate.loop_ = loop;
503 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
504 fetcher->set_delegate(&delegate);
505
506 typename TestFixture::HttpServer server;
507 ASSERT_TRUE(server.started_);
508
509 StartTransferArgs start_xfer_args = {
510 fetcher.get(),
511 LocalServerUrlForPath("/flaky")
512 };
513
514 g_timeout_add(0, StartTransfer, &start_xfer_args);
515 g_main_loop_run(loop);
516
517 // verify the data we get back
518 ASSERT_EQ(100000, delegate.data.size());
519 for (int i = 0; i < 100000; i += 10) {
520 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
521 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
522 }
523 }
524 g_main_loop_unref(loop);
525}
526
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700527namespace {
528class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
529 public:
530 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
531 virtual void ReceivedBytes(HttpFetcher* fetcher,
532 const char* bytes, int length) {
533 if (server_) {
534 LOG(INFO) << "Stopping server";
535 delete server_;
536 LOG(INFO) << "server stopped";
537 server_ = NULL;
538 }
539 }
540 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
541 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700542 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700543 g_main_loop_quit(loop_);
544 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800545 virtual void TransferTerminated(HttpFetcher* fetcher) {
546 ADD_FAILURE();
547 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700548 GMainLoop* loop_;
549 PythonHttpServer* server_;
550};
551} // namespace {}
552
553
554TYPED_TEST(HttpFetcherTest, FailureTest) {
555 if (this->IsMock())
556 return;
557 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
558 {
559 FailureHttpFetcherTestDelegate delegate;
560 delegate.loop_ = loop;
561 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
562 fetcher->set_delegate(&delegate);
563
564 StartTransferArgs start_xfer_args = {
565 fetcher.get(),
566 LocalServerUrlForPath(this->SmallUrl())
567 };
568
569 g_timeout_add(0, StartTransfer, &start_xfer_args);
570 g_main_loop_run(loop);
571
572 // Exiting and testing happens in the delegate
573 }
574 g_main_loop_unref(loop);
575}
576
577TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
578 if (this->IsMock())
579 return;
580 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
581 {
582 FailureHttpFetcherTestDelegate delegate;
583 delegate.loop_ = loop;
584 delegate.server_ = new PythonHttpServer;
585 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
586 fetcher->set_delegate(&delegate);
587
588 StartTransferArgs start_xfer_args = {
589 fetcher.get(),
590 LocalServerUrlForPath("/flaky")
591 };
592
593 g_timeout_add(0, StartTransfer, &start_xfer_args);
594 g_main_loop_run(loop);
595
596 // Exiting and testing happens in the delegate
597 }
598 g_main_loop_unref(loop);
599}
600
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700601namespace {
602const int kRedirectCodes[] = { 301, 302, 303, 307 };
603
604class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
605 public:
606 RedirectHttpFetcherTestDelegate(bool expected_successful)
607 : expected_successful_(expected_successful) {}
608 virtual void ReceivedBytes(HttpFetcher* fetcher,
609 const char* bytes, int length) {
610 data.append(bytes, length);
611 }
612 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
613 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700614 if (expected_successful_)
615 EXPECT_EQ(200, fetcher->http_response_code());
616 else {
617 EXPECT_GE(fetcher->http_response_code(), 301);
618 EXPECT_LE(fetcher->http_response_code(), 307);
619 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700620 g_main_loop_quit(loop_);
621 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800622 virtual void TransferTerminated(HttpFetcher* fetcher) {
623 ADD_FAILURE();
624 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700625 bool expected_successful_;
626 string data;
627 GMainLoop* loop_;
628};
629
630// RedirectTest takes ownership of |http_fetcher|.
631void RedirectTest(bool expected_successful,
632 const string& url,
633 HttpFetcher* http_fetcher) {
634 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
635 RedirectHttpFetcherTestDelegate delegate(expected_successful);
636 delegate.loop_ = loop;
637 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
638 fetcher->set_delegate(&delegate);
639
640 StartTransferArgs start_xfer_args =
641 { fetcher.get(), LocalServerUrlForPath(url) };
642
643 g_timeout_add(0, StartTransfer, &start_xfer_args);
644 g_main_loop_run(loop);
645 if (expected_successful) {
646 // verify the data we get back
647 ASSERT_EQ(1000, delegate.data.size());
648 for (int i = 0; i < 1000; i += 10) {
649 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
650 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
651 }
652 }
653 g_main_loop_unref(loop);
654}
655} // namespace {}
656
657TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
658 if (this->IsMock())
659 return;
660 typename TestFixture::HttpServer server;
661 ASSERT_TRUE(server.started_);
662 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
663 const string url = base::StringPrintf("/redirect/%d/medium",
664 kRedirectCodes[c]);
665 RedirectTest(true, url, this->NewLargeFetcher());
666 }
667}
668
669TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
670 if (this->IsMock())
671 return;
672 typename TestFixture::HttpServer server;
673 ASSERT_TRUE(server.started_);
674 string url;
675 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
676 url += base::StringPrintf("/redirect/%d",
677 kRedirectCodes[r % arraysize(kRedirectCodes)]);
678 }
679 url += "/medium";
680 RedirectTest(true, url, this->NewLargeFetcher());
681}
682
683TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
684 if (this->IsMock())
685 return;
686 typename TestFixture::HttpServer server;
687 ASSERT_TRUE(server.started_);
688 string url;
689 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
690 url += base::StringPrintf("/redirect/%d",
691 kRedirectCodes[r % arraysize(kRedirectCodes)]);
692 }
693 url += "/medium";
694 RedirectTest(false, url, this->NewLargeFetcher());
695}
696
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700697namespace {
698class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
699 public:
700 MultiHttpFetcherTestDelegate(int expected_response_code)
701 : expected_response_code_(expected_response_code) {}
702 virtual void ReceivedBytes(HttpFetcher* fetcher,
703 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800704 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700705 data.append(bytes, length);
706 }
707 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800708 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700709 EXPECT_EQ(expected_response_code_ != 0, successful);
710 if (expected_response_code_ != 0)
711 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800712 // Destroy the fetcher (because we're allowed to).
713 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700714 g_main_loop_quit(loop_);
715 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800716 virtual void TransferTerminated(HttpFetcher* fetcher) {
717 ADD_FAILURE();
718 }
719 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700720 int expected_response_code_;
721 string data;
722 GMainLoop* loop_;
723};
724
725void MultiTest(HttpFetcher* fetcher_in,
726 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800727 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700728 const string& expected_prefix,
729 off_t expected_size,
730 int expected_response_code) {
731 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
732 {
733 MultiHttpFetcherTestDelegate delegate(expected_response_code);
734 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800735 delegate.fetcher_.reset(fetcher_in);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800736 MultiRangeHTTPFetcher* multi_fetcher =
737 dynamic_cast<MultiRangeHTTPFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700738 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800739 multi_fetcher->ClearRanges();
740 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
741 e = ranges.end(); it != e; ++it) {
742 LOG(INFO) << "Adding range";
743 multi_fetcher->AddRange(it->first, it->second);
744 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700745 multi_fetcher->SetConnectionAsExpensive(false);
746 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800747 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700748
Darin Petkov9ce452b2010-11-17 14:33:28 -0800749 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700750
751 g_timeout_add(0, StartTransfer, &start_xfer_args);
752 g_main_loop_run(loop);
753
754 EXPECT_EQ(expected_size, delegate.data.size());
755 EXPECT_EQ(expected_prefix,
756 string(delegate.data.data(), expected_prefix.size()));
757 }
758 g_main_loop_unref(loop);
759}
760} // namespace {}
761
Darin Petkov9ce452b2010-11-17 14:33:28 -0800762TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700763 if (!this->IsMulti())
764 return;
765 typename TestFixture::HttpServer server;
766 ASSERT_TRUE(server.started_);
767
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800768 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700769 ranges.push_back(make_pair(0, 25));
770 ranges.push_back(make_pair(99, -1));
771 MultiTest(this->NewLargeFetcher(),
772 this->BigUrl(),
773 ranges,
774 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
775 kBigSize - (99 - 25),
776 206);
777}
778
779TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
780 if (!this->IsMulti())
781 return;
782 typename TestFixture::HttpServer server;
783 ASSERT_TRUE(server.started_);
784
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800785 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700786 ranges.push_back(make_pair(0, 24));
787 MultiTest(this->NewLargeFetcher(),
788 this->BigUrl(),
789 ranges,
790 "abcdefghijabcdefghijabcd",
791 24,
792 200);
793}
794
795TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
796 if (!this->IsMulti())
797 return;
798 typename TestFixture::HttpServer server;
799 ASSERT_TRUE(server.started_);
800
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800801 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700802 ranges.push_back(make_pair(kBigSize - 2, -1));
803 ranges.push_back(make_pair(kBigSize - 3, -1));
804 MultiTest(this->NewLargeFetcher(),
805 this->BigUrl(),
806 ranges,
807 "ijhij",
808 5,
809 206);
810}
811
812TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
813 if (!this->IsMulti())
814 return;
815 typename TestFixture::HttpServer server;
816 ASSERT_TRUE(server.started_);
817
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800818 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700819 ranges.push_back(make_pair(kBigSize - 2, 4));
820 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800821 LOG(INFO) << "i = " << i;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700822 MultiTest(this->NewLargeFetcher(),
823 this->BigUrl(),
824 ranges,
825 "ij",
826 2,
827 0);
828 ranges.push_back(make_pair(0, 5));
829 }
830}
831
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700832namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700833class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700834 public:
835 virtual void ReceivedBytes(HttpFetcher* fetcher,
836 const char* bytes, int length) {
837 ADD_FAILURE();
838 }
839 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
840 EXPECT_FALSE(successful);
841 g_main_loop_quit(loop_);
842 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800843 virtual void TransferTerminated(HttpFetcher* fetcher) {
844 ADD_FAILURE();
845 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700846 GMainLoop* loop_;
847};
848
849} // namespace
850
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700851TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700852 if (this->IsMock() || this->IsMulti())
853 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700854
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700855 for (int i = 0; i < 2; i++) {
856 typename TestFixture::HttpServer server;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700857
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700858 ASSERT_TRUE(server.started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700859
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700860 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
861 BlockedTransferTestDelegate delegate;
862 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700863
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700864 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
865 LibcurlHttpFetcher* curl_fetcher =
866 dynamic_cast<LibcurlHttpFetcher*>(fetcher.get());
867 bool is_expensive_connection = (i == 0);
868 bool is_official_build = (i == 1);
869 LOG(INFO) << "is_expensive_connection: " << is_expensive_connection;
870 LOG(INFO) << "is_official_build: " << is_official_build;
871 curl_fetcher->SetConnectionAsExpensive(is_expensive_connection);
872 curl_fetcher->SetBuildType(is_official_build);
873 fetcher->set_delegate(&delegate);
874
875 StartTransferArgs start_xfer_args =
876 { fetcher.get(), LocalServerUrlForPath(this->SmallUrl()) };
877
878 g_timeout_add(0, StartTransfer, &start_xfer_args);
879 g_main_loop_run(loop);
880 g_main_loop_unref(loop);
881 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700882}
883
rspangler@google.com49fdf182009-10-10 00:57:34 +0000884} // namespace chromeos_update_engine