blob: 8170b7b1a4e8a51ef5733e1d83792bf4c3901aed [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <unistd.h>
Darin Petkov41c2fcf2010-08-25 13:14:48 -07006
adlr@google.comc98a7ed2009-12-04 18:54:03 +00007#include <string>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07008#include <utility>
adlr@google.comc98a7ed2009-12-04 18:54:03 +00009#include <vector>
Darin Petkov41c2fcf2010-08-25 13:14:48 -070010
Andrew de los Reyes45168102010-11-22 11:13:50 -080011#include <base/logging.h>
12#include <base/scoped_ptr.h>
13#include <base/string_util.h>
14#include <glib.h>
15#include <gtest/gtest.h>
16
rspangler@google.com49fdf182009-10-10 00:57:34 +000017#include "update_engine/libcurl_http_fetcher.h"
18#include "update_engine/mock_http_fetcher.h"
Andrew de los Reyes819fef22010-12-17 11:33:58 -080019#include "update_engine/multi_range_http_fetcher.h"
Andrew de los Reyes45168102010-11-22 11:13:50 -080020#include "update_engine/proxy_resolver.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000021
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070022using std::make_pair;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080023using std::pair;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000024using std::string;
25using std::vector;
26
rspangler@google.com49fdf182009-10-10 00:57:34 +000027namespace chromeos_update_engine {
28
29namespace {
Darin Petkovf67bb1f2010-11-08 16:10:26 -080030// WARNING, if you update these, you must also update test_http_server.cc.
31const char* const kServerPort = "8088";
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070032const int kBigSize = 100000;
rspangler@google.com49fdf182009-10-10 00:57:34 +000033string LocalServerUrlForPath(const string& path) {
34 return string("http://127.0.0.1:") + kServerPort + path;
35}
36}
37
38template <typename T>
39class HttpFetcherTest : public ::testing::Test {
40 public:
41 HttpFetcher* NewLargeFetcher() = 0;
42 HttpFetcher* NewSmallFetcher() = 0;
43 string BigUrl() const = 0;
44 string SmallUrl() const = 0;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000045 bool IsMock() const = 0;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070046 bool IsMulti() const = 0;
rspangler@google.com49fdf182009-10-10 00:57:34 +000047};
48
49class NullHttpServer {
50 public:
51 NullHttpServer() : started_(true) {}
52 ~NullHttpServer() {}
53 bool started_;
54};
55
56
57template <>
58class HttpFetcherTest<MockHttpFetcher> : public ::testing::Test {
59 public:
60 HttpFetcher* NewLargeFetcher() {
61 vector<char> big_data(1000000);
Andrew de los Reyes45168102010-11-22 11:13:50 -080062 return new MockHttpFetcher(
63 big_data.data(),
64 big_data.size(),
65 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
rspangler@google.com49fdf182009-10-10 00:57:34 +000066 }
67 HttpFetcher* NewSmallFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -080068 return new MockHttpFetcher(
69 "x",
70 1,
71 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
rspangler@google.com49fdf182009-10-10 00:57:34 +000072 }
73 string BigUrl() const {
74 return "unused://unused";
75 }
76 string SmallUrl() const {
77 return "unused://unused";
78 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +000079 bool IsMock() const { return true; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070080 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +000081 typedef NullHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070082 void IgnoreServerAborting(HttpServer* server) const {}
Andrew de los Reyes45168102010-11-22 11:13:50 -080083
84 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +000085};
86
87class PythonHttpServer {
88 public:
89 PythonHttpServer() {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000090 char *argv[2] = {strdup("./test_http_server"), NULL};
rspangler@google.com49fdf182009-10-10 00:57:34 +000091 GError *err;
92 started_ = false;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070093 validate_quit_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000094 if (!g_spawn_async(NULL,
95 argv,
96 NULL,
97 G_SPAWN_DO_NOT_REAP_CHILD,
98 NULL,
99 NULL,
100 &pid_,
101 &err)) {
102 return;
103 }
104 int rc = 1;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700105 int tries = 10;
106 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000107 while (0 != rc) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700108 LOG(INFO) << "running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000109 rc = system((string("wget --output-document=/dev/null ") +
110 LocalServerUrlForPath("/test")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700111 LOG(INFO) << "done running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000112 usleep(10 * 1000); // 10 ms
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700113 tries--;
114 if (tries == 0) {
115 LOG(ERROR) << "Unable to start server.";
116 started_ = false;
117 break;
118 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000119 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000120 free(argv[0]);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700121 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000122 return;
123 }
124 ~PythonHttpServer() {
125 if (!started_)
126 return;
127 // request that the server exit itself
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700128 LOG(INFO) << "running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700129 int rc = system((string("wget -t 1 --output-document=/dev/null ") +
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700130 LocalServerUrlForPath("/quitquitquit")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700131 LOG(INFO) << "done running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700132 if (validate_quit_)
133 EXPECT_EQ(0, rc);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000134 waitpid(pid_, NULL, 0);
135 }
136 GPid pid_;
137 bool started_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700138 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000139};
140
141template <>
142class HttpFetcherTest<LibcurlHttpFetcher> : public ::testing::Test {
143 public:
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700144 virtual HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes45168102010-11-22 11:13:50 -0800145 LibcurlHttpFetcher *ret = new
146 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
Darin Petkovb83371f2010-08-17 09:34:49 -0700147 // Speed up test execution.
148 ret->set_idle_seconds(1);
149 ret->set_retry_seconds(1);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700150 ret->SetConnectionAsExpensive(false);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700151 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000152 return ret;
153 }
154 HttpFetcher* NewSmallFetcher() {
155 return NewLargeFetcher();
156 }
157 string BigUrl() const {
158 return LocalServerUrlForPath("/big");
159 }
160 string SmallUrl() const {
161 return LocalServerUrlForPath("/foo");
162 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000163 bool IsMock() const { return false; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700164 bool IsMulti() const { return false; }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000165 typedef PythonHttpServer HttpServer;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700166 void IgnoreServerAborting(HttpServer* server) const {
167 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
168 pyserver->validate_quit_ = false;
169 }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800170 DirectProxyResolver proxy_resolver_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000171};
172
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700173template <>
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800174class HttpFetcherTest<MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700175 : public HttpFetcherTest<LibcurlHttpFetcher> {
176 public:
177 HttpFetcher* NewLargeFetcher() {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800178 ProxyResolver* resolver =
179 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
180 MultiRangeHTTPFetcher *ret =
181 new MultiRangeHTTPFetcher(new LibcurlHttpFetcher(resolver));
182 ret->ClearRanges();
183 ret->AddRange(0, -1);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700184 // Speed up test execution.
185 ret->set_idle_seconds(1);
186 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700187 ret->SetConnectionAsExpensive(false);
188 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700189 return ret;
190 }
191 bool IsMulti() const { return true; }
Andrew de los Reyes45168102010-11-22 11:13:50 -0800192 DirectProxyResolver proxy_resolver_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700193};
194
195typedef ::testing::Types<LibcurlHttpFetcher,
196 MockHttpFetcher,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800197 MultiRangeHTTPFetcher>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700198HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000199TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
200
201namespace {
202class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000203 public:
rspangler@google.com49fdf182009-10-10 00:57:34 +0000204 virtual void ReceivedBytes(HttpFetcher* fetcher,
205 const char* bytes, int length) {
206 char str[length + 1];
207 memset(str, 0, length + 1);
208 memcpy(str, bytes, length);
209 }
210 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkovcb466212010-08-26 09:40:11 -0700211 EXPECT_EQ(200, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000212 g_main_loop_quit(loop_);
213 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800214 virtual void TransferTerminated(HttpFetcher* fetcher) {
215 ADD_FAILURE();
216 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000217 GMainLoop* loop_;
218};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000219
220struct StartTransferArgs {
221 HttpFetcher *http_fetcher;
222 string url;
223};
224
225gboolean StartTransfer(gpointer data) {
226 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
227 args->http_fetcher->BeginTransfer(args->url);
228 return FALSE;
229}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000230} // namespace {}
231
232TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700233 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000234 {
235 HttpFetcherTestDelegate delegate;
236 delegate.loop_ = loop;
237 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
238 fetcher->set_delegate(&delegate);
239
240 typename TestFixture::HttpServer server;
241 ASSERT_TRUE(server.started_);
242
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000243 StartTransferArgs start_xfer_args = {fetcher.get(), this->SmallUrl()};
244
245 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000246 g_main_loop_run(loop);
247 }
248 g_main_loop_unref(loop);
249}
250
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700251TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700252 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700253 {
254 HttpFetcherTestDelegate delegate;
255 delegate.loop_ = loop;
256 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
257 fetcher->set_delegate(&delegate);
258
259 typename TestFixture::HttpServer server;
260 ASSERT_TRUE(server.started_);
261
262 StartTransferArgs start_xfer_args = {fetcher.get(), this->BigUrl()};
263
264 g_timeout_add(0, StartTransfer, &start_xfer_args);
265 g_main_loop_run(loop);
266 }
267 g_main_loop_unref(loop);
268}
269
rspangler@google.com49fdf182009-10-10 00:57:34 +0000270namespace {
271class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
272 public:
273 virtual void ReceivedBytes(HttpFetcher* fetcher,
274 const char* bytes, int length) {
275 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000276 memset(str, 0, length + 1);
277 memcpy(str, bytes, length);
278 CHECK(!paused_);
279 paused_ = true;
280 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000281 }
282 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
283 g_main_loop_quit(loop_);
284 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800285 virtual void TransferTerminated(HttpFetcher* fetcher) {
286 ADD_FAILURE();
287 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000288 void Unpause() {
289 CHECK(paused_);
290 paused_ = false;
291 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000292 }
293 bool paused_;
294 HttpFetcher* fetcher_;
295 GMainLoop* loop_;
296};
297
298gboolean UnpausingTimeoutCallback(gpointer data) {
299 PausingHttpFetcherTestDelegate *delegate =
300 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
301 if (delegate->paused_)
302 delegate->Unpause();
303 return TRUE;
304}
305} // namespace {}
306
307TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700308 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000309 {
310 PausingHttpFetcherTestDelegate delegate;
311 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
312 delegate.paused_ = false;
313 delegate.loop_ = loop;
314 delegate.fetcher_ = fetcher.get();
315 fetcher->set_delegate(&delegate);
316
317 typename TestFixture::HttpServer server;
318 ASSERT_TRUE(server.started_);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800319
320 guint callback_id = g_timeout_add(500, UnpausingTimeoutCallback, &delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000321 fetcher->BeginTransfer(this->BigUrl());
322
323 g_main_loop_run(loop);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800324 g_source_remove(callback_id);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000325 }
326 g_main_loop_unref(loop);
327}
328
329namespace {
330class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
331 public:
332 virtual void ReceivedBytes(HttpFetcher* fetcher,
333 const char* bytes, int length) {}
334 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800335 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000336 g_main_loop_quit(loop_);
337 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800338 virtual void TransferTerminated(HttpFetcher* fetcher) {
339 EXPECT_EQ(fetcher, fetcher_.get());
340 EXPECT_FALSE(once_);
341 EXPECT_TRUE(callback_once_);
342 callback_once_ = false;
343 // |fetcher| can be destroyed during this callback.
344 fetcher_.reset(NULL);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800345 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000346 void TerminateTransfer() {
347 CHECK(once_);
348 once_ = false;
349 fetcher_->TerminateTransfer();
350 }
351 void EndLoop() {
352 g_main_loop_quit(loop_);
353 }
354 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800355 bool callback_once_;
356 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000357 GMainLoop* loop_;
358};
359
360gboolean AbortingTimeoutCallback(gpointer data) {
361 AbortingHttpFetcherTestDelegate *delegate =
362 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
363 if (delegate->once_) {
364 delegate->TerminateTransfer();
365 return TRUE;
366 } else {
367 delegate->EndLoop();
368 return FALSE;
369 }
370}
371} // namespace {}
372
373TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700374 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000375 {
376 AbortingHttpFetcherTestDelegate delegate;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800377 delegate.fetcher_.reset(this->NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000378 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800379 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000380 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800381 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000382
383 typename TestFixture::HttpServer server;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700384 this->IgnoreServerAborting(&server);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000385 ASSERT_TRUE(server.started_);
386 GSource* timeout_source_;
387 timeout_source_ = g_timeout_source_new(0); // ms
388 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
389 NULL);
390 g_source_attach(timeout_source_, NULL);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800391 delegate.fetcher_->BeginTransfer(this->BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000392
393 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800394 CHECK(!delegate.once_);
395 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000396 g_source_destroy(timeout_source_);
397 }
398 g_main_loop_unref(loop);
399}
400
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000401namespace {
402class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
403 public:
404 virtual void ReceivedBytes(HttpFetcher* fetcher,
405 const char* bytes, int length) {
406 data.append(bytes, length);
407 }
408 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700409 EXPECT_TRUE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700410 EXPECT_EQ(206, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000411 g_main_loop_quit(loop_);
412 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800413 virtual void TransferTerminated(HttpFetcher* fetcher) {
414 ADD_FAILURE();
415 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000416 string data;
417 GMainLoop* loop_;
418};
419} // namespace {}
420
421TYPED_TEST(HttpFetcherTest, FlakyTest) {
422 if (this->IsMock())
423 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700424 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000425 {
426 FlakyHttpFetcherTestDelegate delegate;
427 delegate.loop_ = loop;
428 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
429 fetcher->set_delegate(&delegate);
430
431 typename TestFixture::HttpServer server;
432 ASSERT_TRUE(server.started_);
433
434 StartTransferArgs start_xfer_args = {
435 fetcher.get(),
436 LocalServerUrlForPath("/flaky")
437 };
438
439 g_timeout_add(0, StartTransfer, &start_xfer_args);
440 g_main_loop_run(loop);
441
442 // verify the data we get back
443 ASSERT_EQ(100000, delegate.data.size());
444 for (int i = 0; i < 100000; i += 10) {
445 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
446 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
447 }
448 }
449 g_main_loop_unref(loop);
450}
451
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700452namespace {
453class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
454 public:
455 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
456 virtual void ReceivedBytes(HttpFetcher* fetcher,
457 const char* bytes, int length) {
458 if (server_) {
459 LOG(INFO) << "Stopping server";
460 delete server_;
461 LOG(INFO) << "server stopped";
462 server_ = NULL;
463 }
464 }
465 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
466 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700467 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700468 g_main_loop_quit(loop_);
469 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800470 virtual void TransferTerminated(HttpFetcher* fetcher) {
471 ADD_FAILURE();
472 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700473 GMainLoop* loop_;
474 PythonHttpServer* server_;
475};
476} // namespace {}
477
478
479TYPED_TEST(HttpFetcherTest, FailureTest) {
480 if (this->IsMock())
481 return;
482 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
483 {
484 FailureHttpFetcherTestDelegate delegate;
485 delegate.loop_ = loop;
486 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
487 fetcher->set_delegate(&delegate);
488
489 StartTransferArgs start_xfer_args = {
490 fetcher.get(),
491 LocalServerUrlForPath(this->SmallUrl())
492 };
493
494 g_timeout_add(0, StartTransfer, &start_xfer_args);
495 g_main_loop_run(loop);
496
497 // Exiting and testing happens in the delegate
498 }
499 g_main_loop_unref(loop);
500}
501
502TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
503 if (this->IsMock())
504 return;
505 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
506 {
507 FailureHttpFetcherTestDelegate delegate;
508 delegate.loop_ = loop;
509 delegate.server_ = new PythonHttpServer;
510 scoped_ptr<HttpFetcher> fetcher(this->NewSmallFetcher());
511 fetcher->set_delegate(&delegate);
512
513 StartTransferArgs start_xfer_args = {
514 fetcher.get(),
515 LocalServerUrlForPath("/flaky")
516 };
517
518 g_timeout_add(0, StartTransfer, &start_xfer_args);
519 g_main_loop_run(loop);
520
521 // Exiting and testing happens in the delegate
522 }
523 g_main_loop_unref(loop);
524}
525
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700526namespace {
527const int kRedirectCodes[] = { 301, 302, 303, 307 };
528
529class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
530 public:
531 RedirectHttpFetcherTestDelegate(bool expected_successful)
532 : expected_successful_(expected_successful) {}
533 virtual void ReceivedBytes(HttpFetcher* fetcher,
534 const char* bytes, int length) {
535 data.append(bytes, length);
536 }
537 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
538 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700539 if (expected_successful_)
540 EXPECT_EQ(200, fetcher->http_response_code());
541 else {
542 EXPECT_GE(fetcher->http_response_code(), 301);
543 EXPECT_LE(fetcher->http_response_code(), 307);
544 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700545 g_main_loop_quit(loop_);
546 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800547 virtual void TransferTerminated(HttpFetcher* fetcher) {
548 ADD_FAILURE();
549 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700550 bool expected_successful_;
551 string data;
552 GMainLoop* loop_;
553};
554
555// RedirectTest takes ownership of |http_fetcher|.
556void RedirectTest(bool expected_successful,
557 const string& url,
558 HttpFetcher* http_fetcher) {
559 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
560 RedirectHttpFetcherTestDelegate delegate(expected_successful);
561 delegate.loop_ = loop;
562 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
563 fetcher->set_delegate(&delegate);
564
565 StartTransferArgs start_xfer_args =
566 { fetcher.get(), LocalServerUrlForPath(url) };
567
568 g_timeout_add(0, StartTransfer, &start_xfer_args);
569 g_main_loop_run(loop);
570 if (expected_successful) {
571 // verify the data we get back
572 ASSERT_EQ(1000, delegate.data.size());
573 for (int i = 0; i < 1000; i += 10) {
574 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
575 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
576 }
577 }
578 g_main_loop_unref(loop);
579}
580} // namespace {}
581
582TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
583 if (this->IsMock())
584 return;
585 typename TestFixture::HttpServer server;
586 ASSERT_TRUE(server.started_);
587 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
588 const string url = base::StringPrintf("/redirect/%d/medium",
589 kRedirectCodes[c]);
590 RedirectTest(true, url, this->NewLargeFetcher());
591 }
592}
593
594TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
595 if (this->IsMock())
596 return;
597 typename TestFixture::HttpServer server;
598 ASSERT_TRUE(server.started_);
599 string url;
600 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
601 url += base::StringPrintf("/redirect/%d",
602 kRedirectCodes[r % arraysize(kRedirectCodes)]);
603 }
604 url += "/medium";
605 RedirectTest(true, url, this->NewLargeFetcher());
606}
607
608TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
609 if (this->IsMock())
610 return;
611 typename TestFixture::HttpServer server;
612 ASSERT_TRUE(server.started_);
613 string url;
614 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
615 url += base::StringPrintf("/redirect/%d",
616 kRedirectCodes[r % arraysize(kRedirectCodes)]);
617 }
618 url += "/medium";
619 RedirectTest(false, url, this->NewLargeFetcher());
620}
621
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700622namespace {
623class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
624 public:
625 MultiHttpFetcherTestDelegate(int expected_response_code)
626 : expected_response_code_(expected_response_code) {}
627 virtual void ReceivedBytes(HttpFetcher* fetcher,
628 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800629 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700630 data.append(bytes, length);
631 }
632 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800633 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700634 EXPECT_EQ(expected_response_code_ != 0, successful);
635 if (expected_response_code_ != 0)
636 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800637 // Destroy the fetcher (because we're allowed to).
638 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700639 g_main_loop_quit(loop_);
640 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800641 virtual void TransferTerminated(HttpFetcher* fetcher) {
642 ADD_FAILURE();
643 }
644 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700645 int expected_response_code_;
646 string data;
647 GMainLoop* loop_;
648};
649
650void MultiTest(HttpFetcher* fetcher_in,
651 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800652 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700653 const string& expected_prefix,
654 off_t expected_size,
655 int expected_response_code) {
656 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
657 {
658 MultiHttpFetcherTestDelegate delegate(expected_response_code);
659 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800660 delegate.fetcher_.reset(fetcher_in);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800661 MultiRangeHTTPFetcher* multi_fetcher =
662 dynamic_cast<MultiRangeHTTPFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700663 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800664 multi_fetcher->ClearRanges();
665 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
666 e = ranges.end(); it != e; ++it) {
667 LOG(INFO) << "Adding range";
668 multi_fetcher->AddRange(it->first, it->second);
669 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700670 multi_fetcher->SetConnectionAsExpensive(false);
671 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800672 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700673
Darin Petkov9ce452b2010-11-17 14:33:28 -0800674 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700675
676 g_timeout_add(0, StartTransfer, &start_xfer_args);
677 g_main_loop_run(loop);
678
679 EXPECT_EQ(expected_size, delegate.data.size());
680 EXPECT_EQ(expected_prefix,
681 string(delegate.data.data(), expected_prefix.size()));
682 }
683 g_main_loop_unref(loop);
684}
685} // namespace {}
686
Darin Petkov9ce452b2010-11-17 14:33:28 -0800687TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700688 if (!this->IsMulti())
689 return;
690 typename TestFixture::HttpServer server;
691 ASSERT_TRUE(server.started_);
692
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800693 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700694 ranges.push_back(make_pair(0, 25));
695 ranges.push_back(make_pair(99, -1));
696 MultiTest(this->NewLargeFetcher(),
697 this->BigUrl(),
698 ranges,
699 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
700 kBigSize - (99 - 25),
701 206);
702}
703
704TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
705 if (!this->IsMulti())
706 return;
707 typename TestFixture::HttpServer server;
708 ASSERT_TRUE(server.started_);
709
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800710 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700711 ranges.push_back(make_pair(0, 24));
712 MultiTest(this->NewLargeFetcher(),
713 this->BigUrl(),
714 ranges,
715 "abcdefghijabcdefghijabcd",
716 24,
717 200);
718}
719
720TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
721 if (!this->IsMulti())
722 return;
723 typename TestFixture::HttpServer server;
724 ASSERT_TRUE(server.started_);
725
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800726 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700727 ranges.push_back(make_pair(kBigSize - 2, -1));
728 ranges.push_back(make_pair(kBigSize - 3, -1));
729 MultiTest(this->NewLargeFetcher(),
730 this->BigUrl(),
731 ranges,
732 "ijhij",
733 5,
734 206);
735}
736
737TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
738 if (!this->IsMulti())
739 return;
740 typename TestFixture::HttpServer server;
741 ASSERT_TRUE(server.started_);
742
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800743 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700744 ranges.push_back(make_pair(kBigSize - 2, 4));
745 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800746 LOG(INFO) << "i = " << i;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700747 MultiTest(this->NewLargeFetcher(),
748 this->BigUrl(),
749 ranges,
750 "ij",
751 2,
752 0);
753 ranges.push_back(make_pair(0, 5));
754 }
755}
756
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700757namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700758class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700759 public:
760 virtual void ReceivedBytes(HttpFetcher* fetcher,
761 const char* bytes, int length) {
762 ADD_FAILURE();
763 }
764 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
765 EXPECT_FALSE(successful);
766 g_main_loop_quit(loop_);
767 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800768 virtual void TransferTerminated(HttpFetcher* fetcher) {
769 ADD_FAILURE();
770 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700771 GMainLoop* loop_;
772};
773
774} // namespace
775
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700776TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700777 if (this->IsMock() || this->IsMulti())
778 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700779
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700780 for (int i = 0; i < 2; i++) {
781 typename TestFixture::HttpServer server;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700782
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700783 ASSERT_TRUE(server.started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700784
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700785 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
786 BlockedTransferTestDelegate delegate;
787 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700788
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700789 scoped_ptr<HttpFetcher> fetcher(this->NewLargeFetcher());
790 LibcurlHttpFetcher* curl_fetcher =
791 dynamic_cast<LibcurlHttpFetcher*>(fetcher.get());
792 bool is_expensive_connection = (i == 0);
793 bool is_official_build = (i == 1);
794 LOG(INFO) << "is_expensive_connection: " << is_expensive_connection;
795 LOG(INFO) << "is_official_build: " << is_official_build;
796 curl_fetcher->SetConnectionAsExpensive(is_expensive_connection);
797 curl_fetcher->SetBuildType(is_official_build);
798 fetcher->set_delegate(&delegate);
799
800 StartTransferArgs start_xfer_args =
801 { fetcher.get(), LocalServerUrlForPath(this->SmallUrl()) };
802
803 g_timeout_add(0, StartTransfer, &start_xfer_args);
804 g_main_loop_run(loop);
805 g_main_loop_unref(loop);
806 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700807}
808
rspangler@google.com49fdf182009-10-10 00:57:34 +0000809} // namespace chromeos_update_engine