blob: 0ba1179e2e4455e0c03c4cc18069ec78e3796f75 [file] [log] [blame]
Mike Frysinger8155d082012-04-06 15:23:18 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
rspangler@google.com49fdf182009-10-10 00:57:34 +00002// 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>
Mike Frysinger8155d082012-04-06 15:23:18 -040014#include <base/stringprintf.h>
Andrew de los Reyes45168102010-11-22 11:13:50 -080015#include <glib.h>
16#include <gtest/gtest.h>
17
Gilad Arnold9bedeb52011-11-17 16:19:57 -080018#include "update_engine/http_common.h"
19#include "update_engine/http_fetcher_unittest.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000020#include "update_engine/libcurl_http_fetcher.h"
21#include "update_engine/mock_http_fetcher.h"
Andrew de los Reyes819fef22010-12-17 11:33:58 -080022#include "update_engine/multi_range_http_fetcher.h"
Andrew de los Reyes45168102010-11-22 11:13:50 -080023#include "update_engine/proxy_resolver.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000024
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070025using std::make_pair;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080026using std::pair;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000027using std::string;
28using std::vector;
29
Gilad Arnold9bedeb52011-11-17 16:19:57 -080030namespace {
31
32const int kBigLength = 100000;
33const int kMediumLength = 1000;
Gilad Arnold34bf1ee2012-02-09 16:16:02 -080034const int kFlakyTruncateLength = 29000;
35const int kFlakySleepEvery = 3;
Gilad Arnold9bedeb52011-11-17 16:19:57 -080036const int kFlakySleepSecs = 10;
37
38} // namespace
39
rspangler@google.com49fdf182009-10-10 00:57:34 +000040namespace chromeos_update_engine {
41
Gilad Arnold9bedeb52011-11-17 16:19:57 -080042static const char *kUnusedUrl = "unused://unused";
43
44static inline string LocalServerUrlForPath(const string& path) {
45 return (string("http://127.0.0.1:") + base::StringPrintf("%d", kServerPort) + path);
rspangler@google.com49fdf182009-10-10 00:57:34 +000046}
47
rspangler@google.com49fdf182009-10-10 00:57:34 +000048
Gilad Arnold9bedeb52011-11-17 16:19:57 -080049//
50// Class hierarchy for HTTP server implementations.
51//
52
53class HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000054 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080055 // This makes it an abstract class (dirty but works).
56 virtual ~HttpServer() = 0;
57
rspangler@google.com49fdf182009-10-10 00:57:34 +000058 bool started_;
59};
60
Gilad Arnold9bedeb52011-11-17 16:19:57 -080061HttpServer::~HttpServer() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000062
Gilad Arnold9bedeb52011-11-17 16:19:57 -080063
64class NullHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000065 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080066 NullHttpServer() {
67 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000068 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000069};
70
Gilad Arnold9bedeb52011-11-17 16:19:57 -080071
72class PythonHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000073 public:
74 PythonHttpServer() {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000075 char *argv[2] = {strdup("./test_http_server"), NULL};
rspangler@google.com49fdf182009-10-10 00:57:34 +000076 GError *err;
77 started_ = false;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070078 validate_quit_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000079 if (!g_spawn_async(NULL,
80 argv,
81 NULL,
82 G_SPAWN_DO_NOT_REAP_CHILD,
83 NULL,
84 NULL,
85 &pid_,
86 &err)) {
87 return;
88 }
89 int rc = 1;
Andrew de los Reyese7dcc2a2011-08-19 10:50:37 -070090 const uint64_t kMaxSleep = 60UL * 60UL * 1000UL * 1000UL; // 60 min
91 uint64_t timeout = 15 * 1000; // 15 ms
Andrew de los Reyes3270f742010-07-15 22:28:14 -070092 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000093 while (0 != rc) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -070094 LOG(INFO) << "running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +000095 rc = system((string("wget --output-document=/dev/null ") +
96 LocalServerUrlForPath("/test")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -070097 LOG(INFO) << "done running wget to start";
Josh Horwich2d4e1c52011-08-22 11:58:02 -070098 if (0 != rc) {
99 if (timeout > kMaxSleep) {
100 LOG(ERROR) << "Unable to start server.";
101 started_ = false;
102 break;
103 }
104 if (timeout < (1000 * 1000)) // sub 1-second sleep, use usleep
105 usleep(static_cast<useconds_t>(timeout));
106 else
107 sleep(static_cast<unsigned int>(timeout / (1000 * 1000)));
108 timeout *= 2;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700109 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000110 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000111 free(argv[0]);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700112 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000113 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800114
rspangler@google.com49fdf182009-10-10 00:57:34 +0000115 ~PythonHttpServer() {
116 if (!started_)
117 return;
118 // request that the server exit itself
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700119 LOG(INFO) << "running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700120 int rc = system((string("wget -t 1 --output-document=/dev/null ") +
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700121 LocalServerUrlForPath("/quitquitquit")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700122 LOG(INFO) << "done running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700123 if (validate_quit_)
124 EXPECT_EQ(0, rc);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000125 waitpid(pid_, NULL, 0);
126 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800127
rspangler@google.com49fdf182009-10-10 00:57:34 +0000128 GPid pid_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700129 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000130};
131
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800132
133
134//
135// Class hierarchy for HTTP fetcher test wrappers.
136//
137
138class AnyHttpFetcherTest {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000139 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800140 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) = 0;
141 HttpFetcher* NewLargeFetcher() {
142 return NewLargeFetcher(1);
143 }
144
145 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) = 0;
146 HttpFetcher* NewSmallFetcher() {
147 return NewSmallFetcher(1);
148 }
149
150 virtual string BigUrl() const { return kUnusedUrl; }
151 virtual string SmallUrl() const { return kUnusedUrl; }
152 virtual string ErrorUrl() const { return kUnusedUrl; }
153
154 virtual bool IsMock() const = 0;
155 virtual bool IsMulti() const = 0;
156
157 virtual void IgnoreServerAborting(HttpServer* server) const {}
158
159 virtual HttpServer *CreateServer() = 0;
160
161 protected:
162 DirectProxyResolver proxy_resolver_;
163};
164
165class MockHttpFetcherTest : public AnyHttpFetcherTest {
166 public:
167 // Necessary to unhide the definition in the base class.
168 using AnyHttpFetcherTest::NewLargeFetcher;
169 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
170 vector<char> big_data(1000000);
171 CHECK(num_proxies > 0);
172 proxy_resolver_.set_num_proxies(num_proxies);
173 return new MockHttpFetcher(
174 big_data.data(),
175 big_data.size(),
176 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
177 }
178
179 // Necessary to unhide the definition in the base class.
180 using AnyHttpFetcherTest::NewSmallFetcher;
181 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
182 CHECK(num_proxies > 0);
183 proxy_resolver_.set_num_proxies(num_proxies);
184 return new MockHttpFetcher(
185 "x",
186 1,
187 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
188 }
189
190 virtual bool IsMock() const { return true; }
191 virtual bool IsMulti() const { return false; }
192
193 virtual HttpServer *CreateServer() {
194 return new NullHttpServer;
195 }
196};
197
198class LibcurlHttpFetcherTest : public AnyHttpFetcherTest {
199 public:
200 // Necessary to unhide the definition in the base class.
201 using AnyHttpFetcherTest::NewLargeFetcher;
202 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
203 CHECK(num_proxies > 0);
204 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes45168102010-11-22 11:13:50 -0800205 LibcurlHttpFetcher *ret = new
206 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
Darin Petkovb83371f2010-08-17 09:34:49 -0700207 // Speed up test execution.
208 ret->set_idle_seconds(1);
209 ret->set_retry_seconds(1);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700210 ret->SetConnectionAsExpensive(false);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700211 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000212 return ret;
213 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800214
215 // Necessary to unhide the definition in the base class.
216 using AnyHttpFetcherTest::NewSmallFetcher;
217 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
218 return NewLargeFetcher(num_proxies);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000219 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800220
221 virtual string BigUrl() const {
222 return LocalServerUrlForPath(base::StringPrintf("/download/%d",
223 kBigLength));
rspangler@google.com49fdf182009-10-10 00:57:34 +0000224 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800225 virtual string SmallUrl() const {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000226 return LocalServerUrlForPath("/foo");
227 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800228 virtual string ErrorUrl() const {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800229 return LocalServerUrlForPath("/error");
230 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800231
232 virtual bool IsMock() const { return false; }
233 virtual bool IsMulti() const { return false; }
234
235 virtual void IgnoreServerAborting(HttpServer* server) const {
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700236 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
237 pyserver->validate_quit_ = false;
238 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800239
240 virtual HttpServer *CreateServer() {
241 return new PythonHttpServer;
242 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000243};
244
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800245class MultiRangeHttpFetcherTest : public LibcurlHttpFetcherTest {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700246 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800247 // Necessary to unhide the definition in the base class.
248 using AnyHttpFetcherTest::NewLargeFetcher;
249 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
250 CHECK(num_proxies > 0);
251 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800252 ProxyResolver* resolver =
253 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800254 MultiRangeHttpFetcher *ret =
255 new MultiRangeHttpFetcher(new LibcurlHttpFetcher(resolver));
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800256 ret->ClearRanges();
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800257 ret->AddRange(0);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700258 // Speed up test execution.
259 ret->set_idle_seconds(1);
260 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700261 ret->SetConnectionAsExpensive(false);
262 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700263 return ret;
264 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800265
266 // Necessary to unhide the definition in the base class.
267 using AnyHttpFetcherTest::NewSmallFetcher;
268 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
269 return NewLargeFetcher(num_proxies);
270 }
271
272 virtual bool IsMulti() const { return true; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700273};
274
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800275
276//
277// Infrastructure for type tests of HTTP fetcher.
278// See: http://code.google.com/p/googletest/wiki/AdvancedGuide#Typed_Tests
279//
280
281// Fixture class template. We use an explicit constraint to guarantee that it
282// can only be instantiated with an AnyHttpFetcherTest type, see:
283// http://www2.research.att.com/~bs/bs_faq2.html#constraints
284template <typename T>
285class HttpFetcherTest : public ::testing::Test {
286 public:
287 T test_;
288
289 private:
290 static void TypeConstraint(T *a) {
291 AnyHttpFetcherTest *b = a;
292 }
293};
294
295// Test case types list.
296typedef ::testing::Types<LibcurlHttpFetcherTest,
297 MockHttpFetcherTest,
298 MultiRangeHttpFetcherTest> HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000299TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
300
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800301
rspangler@google.com49fdf182009-10-10 00:57:34 +0000302namespace {
303class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000304 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800305 HttpFetcherTestDelegate() :
Gilad Arnold48085ba2011-11-16 09:36:08 -0800306 is_expect_error_(false), times_transfer_complete_called_(0),
307 times_transfer_terminated_called_(0), times_received_bytes_called_(0) {}
308
rspangler@google.com49fdf182009-10-10 00:57:34 +0000309 virtual void ReceivedBytes(HttpFetcher* fetcher,
310 const char* bytes, int length) {
311 char str[length + 1];
312 memset(str, 0, length + 1);
313 memcpy(str, bytes, length);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800314
315 // Update counters
316 times_received_bytes_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000317 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800318
rspangler@google.com49fdf182009-10-10 00:57:34 +0000319 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800320 if (is_expect_error_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800321 EXPECT_EQ(kHttpResponseNotFound, fetcher->http_response_code());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800322 else
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800323 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000324 g_main_loop_quit(loop_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800325
326 // Update counter
327 times_transfer_complete_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000328 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800329
Darin Petkov9ce452b2010-11-17 14:33:28 -0800330 virtual void TransferTerminated(HttpFetcher* fetcher) {
331 ADD_FAILURE();
Gilad Arnold48085ba2011-11-16 09:36:08 -0800332 times_transfer_terminated_called_++;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800333 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800334
rspangler@google.com49fdf182009-10-10 00:57:34 +0000335 GMainLoop* loop_;
Gilad Arnold48085ba2011-11-16 09:36:08 -0800336
337 // Are we expecting an error response? (default: no)
338 bool is_expect_error_;
339
340 // Counters for callback invocations.
341 int times_transfer_complete_called_;
342 int times_transfer_terminated_called_;
343 int times_received_bytes_called_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000344};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000345
346struct StartTransferArgs {
347 HttpFetcher *http_fetcher;
348 string url;
349};
350
351gboolean StartTransfer(gpointer data) {
352 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
353 args->http_fetcher->BeginTransfer(args->url);
354 return FALSE;
355}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000356} // namespace {}
357
358TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700359 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000360 {
361 HttpFetcherTestDelegate delegate;
362 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800363 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000364 fetcher->set_delegate(&delegate);
365
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800366 scoped_ptr<HttpServer> server(this->test_.CreateServer());
367 ASSERT_TRUE(server->started_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000368
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800369 StartTransferArgs start_xfer_args = {fetcher.get(), this->test_.SmallUrl()};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000370
371 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000372 g_main_loop_run(loop);
373 }
374 g_main_loop_unref(loop);
375}
376
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700377TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700378 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700379 {
380 HttpFetcherTestDelegate delegate;
381 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800382 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700383 fetcher->set_delegate(&delegate);
384
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800385 scoped_ptr<HttpServer> server(this->test_.CreateServer());
386 ASSERT_TRUE(server->started_);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700387
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800388 StartTransferArgs start_xfer_args = {fetcher.get(), this->test_.BigUrl()};
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700389
390 g_timeout_add(0, StartTransfer, &start_xfer_args);
391 g_main_loop_run(loop);
392 }
393 g_main_loop_unref(loop);
394}
395
Gilad Arnold48085ba2011-11-16 09:36:08 -0800396// Issue #9648: when server returns an error HTTP response, the fetcher needs to
397// terminate transfer prematurely, rather than try to process the error payload.
398TYPED_TEST(HttpFetcherTest, ErrorTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800399 if (this->test_.IsMock() || this->test_.IsMulti())
Gilad Arnold48085ba2011-11-16 09:36:08 -0800400 return;
401 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
402 {
403 HttpFetcherTestDelegate delegate;
404 delegate.loop_ = loop;
405
406 // Delegate should expect an error response.
407 delegate.is_expect_error_ = true;
408
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800409 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800410 fetcher->set_delegate(&delegate);
411
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800412 scoped_ptr<HttpServer> server(this->test_.CreateServer());
413 ASSERT_TRUE(server->started_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800414
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800415 StartTransferArgs start_xfer_args = {
416 fetcher.get(),
417 this->test_.ErrorUrl()
418 };
Gilad Arnold48085ba2011-11-16 09:36:08 -0800419
420 g_timeout_add(0, StartTransfer, &start_xfer_args);
421 g_main_loop_run(loop);
422
423 // Make sure that no bytes were received.
424 CHECK_EQ(delegate.times_received_bytes_called_, 0);
Mike Frysinger0f9547d2012-02-16 12:11:37 -0500425 CHECK_EQ(fetcher->GetBytesDownloaded(), static_cast<size_t>(0));
Gilad Arnold48085ba2011-11-16 09:36:08 -0800426
427 // Make sure that transfer completion was signaled once, and no termination
428 // was signaled.
429 CHECK_EQ(delegate.times_transfer_complete_called_, 1);
430 CHECK_EQ(delegate.times_transfer_terminated_called_, 0);
431 }
432 g_main_loop_unref(loop);
433}
434
rspangler@google.com49fdf182009-10-10 00:57:34 +0000435namespace {
436class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
437 public:
438 virtual void ReceivedBytes(HttpFetcher* fetcher,
439 const char* bytes, int length) {
440 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000441 memset(str, 0, length + 1);
442 memcpy(str, bytes, length);
443 CHECK(!paused_);
444 paused_ = true;
445 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000446 }
447 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
448 g_main_loop_quit(loop_);
449 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800450 virtual void TransferTerminated(HttpFetcher* fetcher) {
451 ADD_FAILURE();
452 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000453 void Unpause() {
454 CHECK(paused_);
455 paused_ = false;
456 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000457 }
458 bool paused_;
459 HttpFetcher* fetcher_;
460 GMainLoop* loop_;
461};
462
463gboolean UnpausingTimeoutCallback(gpointer data) {
464 PausingHttpFetcherTestDelegate *delegate =
465 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
466 if (delegate->paused_)
467 delegate->Unpause();
468 return TRUE;
469}
470} // namespace {}
471
472TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700473 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000474 {
475 PausingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800476 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000477 delegate.paused_ = false;
478 delegate.loop_ = loop;
479 delegate.fetcher_ = fetcher.get();
480 fetcher->set_delegate(&delegate);
481
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800482 scoped_ptr<HttpServer> server(this->test_.CreateServer());
483 ASSERT_TRUE(server->started_);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800484
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800485 guint callback_id = g_timeout_add(kHttpResponseInternalServerError,
486 UnpausingTimeoutCallback, &delegate);
487 fetcher->BeginTransfer(this->test_.BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000488
489 g_main_loop_run(loop);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800490 g_source_remove(callback_id);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000491 }
492 g_main_loop_unref(loop);
493}
494
495namespace {
496class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
497 public:
498 virtual void ReceivedBytes(HttpFetcher* fetcher,
499 const char* bytes, int length) {}
500 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800501 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000502 g_main_loop_quit(loop_);
503 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800504 virtual void TransferTerminated(HttpFetcher* fetcher) {
505 EXPECT_EQ(fetcher, fetcher_.get());
506 EXPECT_FALSE(once_);
507 EXPECT_TRUE(callback_once_);
508 callback_once_ = false;
509 // |fetcher| can be destroyed during this callback.
510 fetcher_.reset(NULL);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800511 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000512 void TerminateTransfer() {
513 CHECK(once_);
514 once_ = false;
515 fetcher_->TerminateTransfer();
516 }
517 void EndLoop() {
518 g_main_loop_quit(loop_);
519 }
520 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800521 bool callback_once_;
522 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000523 GMainLoop* loop_;
524};
525
526gboolean AbortingTimeoutCallback(gpointer data) {
527 AbortingHttpFetcherTestDelegate *delegate =
528 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
529 if (delegate->once_) {
530 delegate->TerminateTransfer();
531 return TRUE;
532 } else {
533 delegate->EndLoop();
534 return FALSE;
535 }
536}
537} // namespace {}
538
539TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700540 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000541 {
542 AbortingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800543 delegate.fetcher_.reset(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000544 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800545 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000546 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800547 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000548
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800549 scoped_ptr<HttpServer> server(this->test_.CreateServer());
550 this->test_.IgnoreServerAborting(server.get());
551 ASSERT_TRUE(server->started_);
552
rspangler@google.com49fdf182009-10-10 00:57:34 +0000553 GSource* timeout_source_;
554 timeout_source_ = g_timeout_source_new(0); // ms
555 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
556 NULL);
557 g_source_attach(timeout_source_, NULL);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800558 delegate.fetcher_->BeginTransfer(this->test_.BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000559
560 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800561 CHECK(!delegate.once_);
562 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000563 g_source_destroy(timeout_source_);
564 }
565 g_main_loop_unref(loop);
566}
567
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000568namespace {
569class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
570 public:
571 virtual void ReceivedBytes(HttpFetcher* fetcher,
572 const char* bytes, int length) {
573 data.append(bytes, length);
574 }
575 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700576 EXPECT_TRUE(successful);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800577 EXPECT_EQ(kHttpResponsePartialContent, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000578 g_main_loop_quit(loop_);
579 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800580 virtual void TransferTerminated(HttpFetcher* fetcher) {
581 ADD_FAILURE();
582 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000583 string data;
584 GMainLoop* loop_;
585};
586} // namespace {}
587
588TYPED_TEST(HttpFetcherTest, FlakyTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800589 if (this->test_.IsMock())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000590 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700591 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000592 {
593 FlakyHttpFetcherTestDelegate delegate;
594 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800595 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000596 fetcher->set_delegate(&delegate);
597
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800598 scoped_ptr<HttpServer> server(this->test_.CreateServer());
599 ASSERT_TRUE(server->started_);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000600
601 StartTransferArgs start_xfer_args = {
602 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800603 LocalServerUrlForPath(StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
604 kFlakyTruncateLength,
605 kFlakySleepEvery,
606 kFlakySleepSecs))
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000607 };
608
609 g_timeout_add(0, StartTransfer, &start_xfer_args);
610 g_main_loop_run(loop);
611
612 // verify the data we get back
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800613 ASSERT_EQ(kBigLength, delegate.data.size());
614 for (int i = 0; i < kBigLength; i += 10) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000615 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
616 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
617 }
618 }
619 g_main_loop_unref(loop);
620}
621
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700622namespace {
623class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
624 public:
625 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
626 virtual void ReceivedBytes(HttpFetcher* fetcher,
627 const char* bytes, int length) {
628 if (server_) {
629 LOG(INFO) << "Stopping server";
630 delete server_;
631 LOG(INFO) << "server stopped";
632 server_ = NULL;
633 }
634 }
635 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
636 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700637 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700638 g_main_loop_quit(loop_);
639 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800640 virtual void TransferTerminated(HttpFetcher* fetcher) {
641 ADD_FAILURE();
642 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700643 GMainLoop* loop_;
644 PythonHttpServer* server_;
645};
646} // namespace {}
647
648
649TYPED_TEST(HttpFetcherTest, FailureTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800650 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700651 return;
652 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
653 {
654 FailureHttpFetcherTestDelegate delegate;
655 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800656 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700657 fetcher->set_delegate(&delegate);
658
659 StartTransferArgs start_xfer_args = {
660 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800661 LocalServerUrlForPath(this->test_.SmallUrl())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700662 };
663
664 g_timeout_add(0, StartTransfer, &start_xfer_args);
665 g_main_loop_run(loop);
666
667 // Exiting and testing happens in the delegate
668 }
669 g_main_loop_unref(loop);
670}
671
672TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800673 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700674 return;
675 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
676 {
677 FailureHttpFetcherTestDelegate delegate;
678 delegate.loop_ = loop;
679 delegate.server_ = new PythonHttpServer;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800680 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700681 fetcher->set_delegate(&delegate);
682
683 StartTransferArgs start_xfer_args = {
684 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800685 LocalServerUrlForPath(StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
686 kFlakyTruncateLength,
687 kFlakySleepEvery,
688 kFlakySleepSecs))
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700689 };
690
691 g_timeout_add(0, StartTransfer, &start_xfer_args);
692 g_main_loop_run(loop);
693
694 // Exiting and testing happens in the delegate
695 }
696 g_main_loop_unref(loop);
697}
698
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700699namespace {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800700const HttpResponseCode kRedirectCodes[] = {
701 kHttpResponseMovedPermanently, kHttpResponseFound, kHttpResponseSeeOther,
702 kHttpResponseTempRedirect
703};
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700704
705class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
706 public:
707 RedirectHttpFetcherTestDelegate(bool expected_successful)
708 : expected_successful_(expected_successful) {}
709 virtual void ReceivedBytes(HttpFetcher* fetcher,
710 const char* bytes, int length) {
711 data.append(bytes, length);
712 }
713 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
714 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700715 if (expected_successful_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800716 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
Darin Petkovcb466212010-08-26 09:40:11 -0700717 else {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800718 EXPECT_GE(fetcher->http_response_code(), kHttpResponseMovedPermanently);
719 EXPECT_LE(fetcher->http_response_code(), kHttpResponseTempRedirect);
Darin Petkovcb466212010-08-26 09:40:11 -0700720 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700721 g_main_loop_quit(loop_);
722 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800723 virtual void TransferTerminated(HttpFetcher* fetcher) {
724 ADD_FAILURE();
725 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700726 bool expected_successful_;
727 string data;
728 GMainLoop* loop_;
729};
730
731// RedirectTest takes ownership of |http_fetcher|.
732void RedirectTest(bool expected_successful,
733 const string& url,
734 HttpFetcher* http_fetcher) {
735 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
736 RedirectHttpFetcherTestDelegate delegate(expected_successful);
737 delegate.loop_ = loop;
738 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
739 fetcher->set_delegate(&delegate);
740
741 StartTransferArgs start_xfer_args =
742 { fetcher.get(), LocalServerUrlForPath(url) };
743
744 g_timeout_add(0, StartTransfer, &start_xfer_args);
745 g_main_loop_run(loop);
746 if (expected_successful) {
747 // verify the data we get back
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800748 ASSERT_EQ(kMediumLength, delegate.data.size());
749 for (int i = 0; i < kMediumLength; i += 10) {
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700750 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
751 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
752 }
753 }
754 g_main_loop_unref(loop);
755}
756} // namespace {}
757
758TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800759 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700760 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800761
762 scoped_ptr<HttpServer> server(this->test_.CreateServer());
763 ASSERT_TRUE(server->started_);
764
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700765 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800766 const string url = base::StringPrintf("/redirect/%d/download/%d",
767 kRedirectCodes[c],
768 kMediumLength);
769 RedirectTest(true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700770 }
771}
772
773TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800774 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700775 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800776
777 scoped_ptr<HttpServer> server(this->test_.CreateServer());
778 ASSERT_TRUE(server->started_);
779
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700780 string url;
781 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
782 url += base::StringPrintf("/redirect/%d",
783 kRedirectCodes[r % arraysize(kRedirectCodes)]);
784 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800785 url += base::StringPrintf("/download/%d", kMediumLength);
786 RedirectTest(true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700787}
788
789TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800790 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700791 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800792
793 scoped_ptr<HttpServer> server(this->test_.CreateServer());
794 ASSERT_TRUE(server->started_);
795
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700796 string url;
797 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
798 url += base::StringPrintf("/redirect/%d",
799 kRedirectCodes[r % arraysize(kRedirectCodes)]);
800 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800801 url += base::StringPrintf("/download/%d", kMediumLength);
802 RedirectTest(false, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700803}
804
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700805namespace {
806class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
807 public:
808 MultiHttpFetcherTestDelegate(int expected_response_code)
809 : expected_response_code_(expected_response_code) {}
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800810
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700811 virtual void ReceivedBytes(HttpFetcher* fetcher,
812 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800813 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700814 data.append(bytes, length);
815 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800816
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700817 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800818 EXPECT_EQ(fetcher, fetcher_.get());
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800819 EXPECT_EQ(expected_response_code_ != kHttpResponseUndefined, successful);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700820 if (expected_response_code_ != 0)
821 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800822 // Destroy the fetcher (because we're allowed to).
823 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700824 g_main_loop_quit(loop_);
825 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800826
Darin Petkov9ce452b2010-11-17 14:33:28 -0800827 virtual void TransferTerminated(HttpFetcher* fetcher) {
828 ADD_FAILURE();
829 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800830
Darin Petkov9ce452b2010-11-17 14:33:28 -0800831 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700832 int expected_response_code_;
833 string data;
834 GMainLoop* loop_;
835};
836
837void MultiTest(HttpFetcher* fetcher_in,
838 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800839 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700840 const string& expected_prefix,
841 off_t expected_size,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800842 HttpResponseCode expected_response_code) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700843 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
844 {
845 MultiHttpFetcherTestDelegate delegate(expected_response_code);
846 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800847 delegate.fetcher_.reset(fetcher_in);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800848 MultiRangeHttpFetcher* multi_fetcher =
849 dynamic_cast<MultiRangeHttpFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700850 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800851 multi_fetcher->ClearRanges();
852 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
853 e = ranges.end(); it != e; ++it) {
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800854 std::string tmp_str = StringPrintf("%jd+", it->first);
855 if (it->second > 0) {
856 base::StringAppendF(&tmp_str, "%jd", it->second);
857 multi_fetcher->AddRange(it->first, it->second);
858 } else {
859 base::StringAppendF(&tmp_str, "?");
860 multi_fetcher->AddRange(it->first);
861 }
862 LOG(INFO) << "added range: " << tmp_str;
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800863 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700864 multi_fetcher->SetConnectionAsExpensive(false);
865 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800866 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700867
Darin Petkov9ce452b2010-11-17 14:33:28 -0800868 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700869
870 g_timeout_add(0, StartTransfer, &start_xfer_args);
871 g_main_loop_run(loop);
872
873 EXPECT_EQ(expected_size, delegate.data.size());
874 EXPECT_EQ(expected_prefix,
875 string(delegate.data.data(), expected_prefix.size()));
876 }
877 g_main_loop_unref(loop);
878}
879} // namespace {}
880
Darin Petkov9ce452b2010-11-17 14:33:28 -0800881TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800882 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700883 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800884
885 scoped_ptr<HttpServer> server(this->test_.CreateServer());
886 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700887
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800888 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700889 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800890 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800891 MultiTest(this->test_.NewLargeFetcher(),
892 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700893 ranges,
894 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800895 kBigLength - (99 - 25),
896 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700897}
898
899TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800900 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700901 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800902
903 scoped_ptr<HttpServer> server(this->test_.CreateServer());
904 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700905
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800906 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700907 ranges.push_back(make_pair(0, 24));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800908 MultiTest(this->test_.NewLargeFetcher(),
909 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700910 ranges,
911 "abcdefghijabcdefghijabcd",
912 24,
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800913 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700914}
915
916TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800917 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700918 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800919
920 scoped_ptr<HttpServer> server(this->test_.CreateServer());
921 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700922
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800923 vector<pair<off_t, off_t> > ranges;
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800924 ranges.push_back(make_pair(kBigLength - 2, 0));
925 ranges.push_back(make_pair(kBigLength - 3, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800926 MultiTest(this->test_.NewLargeFetcher(),
927 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700928 ranges,
929 "ijhij",
930 5,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800931 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700932}
933
934TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800935 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700936 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800937
938 scoped_ptr<HttpServer> server(this->test_.CreateServer());
939 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700940
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800941 vector<pair<off_t, off_t> > ranges;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800942 ranges.push_back(make_pair(kBigLength - 2, 4));
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700943 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800944 LOG(INFO) << "i = " << i;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800945 MultiTest(this->test_.NewLargeFetcher(),
946 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700947 ranges,
948 "ij",
949 2,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800950 kHttpResponseUndefined);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700951 ranges.push_back(make_pair(0, 5));
952 }
953}
954
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800955// Issue #18143: when a fetch of a secondary chunk out of a chain, then it
956// should retry with other proxies listed before giving up.
957//
958// (1) successful recovery: The offset fetch will fail twice but succeed with
959// the third proxy.
960TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetRecoverableTest) {
961 if (!this->test_.IsMulti())
962 return;
963
964 scoped_ptr<HttpServer> server(this->test_.CreateServer());
965 ASSERT_TRUE(server->started_);
966
967 vector<pair<off_t, off_t> > ranges;
968 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800969 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800970 MultiTest(this->test_.NewLargeFetcher(3),
971 LocalServerUrlForPath(base::StringPrintf("/error-if-offset/%d/2",
972 kBigLength)),
973 ranges,
974 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
975 kBigLength - (99 - 25),
976 kHttpResponsePartialContent);
977}
978
979// (2) unsuccessful recovery: The offset fetch will fail repeatedly. The
980// fetcher will signal a (failed) completed transfer to the delegate.
981TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetUnrecoverableTest) {
982 if (!this->test_.IsMulti())
983 return;
984
985 scoped_ptr<HttpServer> server(this->test_.CreateServer());
986 ASSERT_TRUE(server->started_);
987
988 vector<pair<off_t, off_t> > ranges;
989 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800990 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800991 MultiTest(this->test_.NewLargeFetcher(2),
992 LocalServerUrlForPath(base::StringPrintf("/error-if-offset/%d/3",
993 kBigLength)),
994 ranges,
995 "abcdefghijabcdefghijabcde", // only received the first chunk
996 25,
997 kHttpResponseUndefined);
998}
999
1000
1001
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001002namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001003class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001004 public:
1005 virtual void ReceivedBytes(HttpFetcher* fetcher,
1006 const char* bytes, int length) {
1007 ADD_FAILURE();
1008 }
1009 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
1010 EXPECT_FALSE(successful);
1011 g_main_loop_quit(loop_);
1012 }
Darin Petkov9ce452b2010-11-17 14:33:28 -08001013 virtual void TransferTerminated(HttpFetcher* fetcher) {
1014 ADD_FAILURE();
1015 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001016 GMainLoop* loop_;
1017};
1018
1019} // namespace
1020
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001021TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001022 if (this->test_.IsMock() || this->test_.IsMulti())
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001023 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001024
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001025 for (int i = 0; i < 2; i++) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001026 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1027 ASSERT_TRUE(server->started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001028
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001029 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
1030 BlockedTransferTestDelegate delegate;
1031 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001032
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001033 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001034 LibcurlHttpFetcher* curl_fetcher =
1035 dynamic_cast<LibcurlHttpFetcher*>(fetcher.get());
1036 bool is_expensive_connection = (i == 0);
1037 bool is_official_build = (i == 1);
1038 LOG(INFO) << "is_expensive_connection: " << is_expensive_connection;
1039 LOG(INFO) << "is_official_build: " << is_official_build;
1040 curl_fetcher->SetConnectionAsExpensive(is_expensive_connection);
1041 curl_fetcher->SetBuildType(is_official_build);
1042 fetcher->set_delegate(&delegate);
1043
1044 StartTransferArgs start_xfer_args =
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001045 { fetcher.get(), LocalServerUrlForPath(this->test_.SmallUrl()) };
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001046
1047 g_timeout_add(0, StartTransfer, &start_xfer_args);
1048 g_main_loop_run(loop);
1049 g_main_loop_unref(loop);
1050 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001051}
1052
rspangler@google.com49fdf182009-10-10 00:57:34 +00001053} // namespace chromeos_update_engine