blob: 1ffba7270da5500424fc42bf373133467a094503 [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
Gilad Arnold9bedeb52011-11-17 16:19:57 -080017#include "update_engine/http_common.h"
18#include "update_engine/http_fetcher_unittest.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000019#include "update_engine/libcurl_http_fetcher.h"
20#include "update_engine/mock_http_fetcher.h"
Andrew de los Reyes819fef22010-12-17 11:33:58 -080021#include "update_engine/multi_range_http_fetcher.h"
Andrew de los Reyes45168102010-11-22 11:13:50 -080022#include "update_engine/proxy_resolver.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000023
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070024using std::make_pair;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080025using std::pair;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000026using std::string;
27using std::vector;
28
Gilad Arnold9bedeb52011-11-17 16:19:57 -080029namespace {
30
31const int kBigLength = 100000;
32const int kMediumLength = 1000;
33const int kFlakyTruncateLength = 9000;
34const int kFlakySleepEvery = 7;
35const int kFlakySleepSecs = 10;
36
37} // namespace
38
rspangler@google.com49fdf182009-10-10 00:57:34 +000039namespace chromeos_update_engine {
40
Gilad Arnold9bedeb52011-11-17 16:19:57 -080041static const char *kUnusedUrl = "unused://unused";
42
43static inline string LocalServerUrlForPath(const string& path) {
44 return (string("http://127.0.0.1:") + base::StringPrintf("%d", kServerPort) + path);
rspangler@google.com49fdf182009-10-10 00:57:34 +000045}
46
rspangler@google.com49fdf182009-10-10 00:57:34 +000047
Gilad Arnold9bedeb52011-11-17 16:19:57 -080048//
49// Class hierarchy for HTTP server implementations.
50//
51
52class HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000053 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080054 // This makes it an abstract class (dirty but works).
55 virtual ~HttpServer() = 0;
56
rspangler@google.com49fdf182009-10-10 00:57:34 +000057 bool started_;
58};
59
Gilad Arnold9bedeb52011-11-17 16:19:57 -080060HttpServer::~HttpServer() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000061
Gilad Arnold9bedeb52011-11-17 16:19:57 -080062
63class NullHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000064 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080065 NullHttpServer() {
66 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000067 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000068};
69
Gilad Arnold9bedeb52011-11-17 16:19:57 -080070
71class PythonHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000072 public:
73 PythonHttpServer() {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000074 char *argv[2] = {strdup("./test_http_server"), NULL};
rspangler@google.com49fdf182009-10-10 00:57:34 +000075 GError *err;
76 started_ = false;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070077 validate_quit_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000078 if (!g_spawn_async(NULL,
79 argv,
80 NULL,
81 G_SPAWN_DO_NOT_REAP_CHILD,
82 NULL,
83 NULL,
84 &pid_,
85 &err)) {
86 return;
87 }
88 int rc = 1;
Andrew de los Reyese7dcc2a2011-08-19 10:50:37 -070089 const uint64_t kMaxSleep = 60UL * 60UL * 1000UL * 1000UL; // 60 min
90 uint64_t timeout = 15 * 1000; // 15 ms
Andrew de los Reyes3270f742010-07-15 22:28:14 -070091 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000092 while (0 != rc) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -070093 LOG(INFO) << "running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +000094 rc = system((string("wget --output-document=/dev/null ") +
95 LocalServerUrlForPath("/test")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -070096 LOG(INFO) << "done running wget to start";
Josh Horwich2d4e1c52011-08-22 11:58:02 -070097 if (0 != rc) {
98 if (timeout > kMaxSleep) {
99 LOG(ERROR) << "Unable to start server.";
100 started_ = false;
101 break;
102 }
103 if (timeout < (1000 * 1000)) // sub 1-second sleep, use usleep
104 usleep(static_cast<useconds_t>(timeout));
105 else
106 sleep(static_cast<unsigned int>(timeout / (1000 * 1000)));
107 timeout *= 2;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700108 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000109 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000110 free(argv[0]);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700111 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000112 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800113
rspangler@google.com49fdf182009-10-10 00:57:34 +0000114 ~PythonHttpServer() {
115 if (!started_)
116 return;
117 // request that the server exit itself
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700118 LOG(INFO) << "running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700119 int rc = system((string("wget -t 1 --output-document=/dev/null ") +
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700120 LocalServerUrlForPath("/quitquitquit")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700121 LOG(INFO) << "done running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700122 if (validate_quit_)
123 EXPECT_EQ(0, rc);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000124 waitpid(pid_, NULL, 0);
125 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800126
rspangler@google.com49fdf182009-10-10 00:57:34 +0000127 GPid pid_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700128 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000129};
130
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800131
132
133//
134// Class hierarchy for HTTP fetcher test wrappers.
135//
136
137class AnyHttpFetcherTest {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000138 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800139 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) = 0;
140 HttpFetcher* NewLargeFetcher() {
141 return NewLargeFetcher(1);
142 }
143
144 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) = 0;
145 HttpFetcher* NewSmallFetcher() {
146 return NewSmallFetcher(1);
147 }
148
149 virtual string BigUrl() const { return kUnusedUrl; }
150 virtual string SmallUrl() const { return kUnusedUrl; }
151 virtual string ErrorUrl() const { return kUnusedUrl; }
152
153 virtual bool IsMock() const = 0;
154 virtual bool IsMulti() const = 0;
155
156 virtual void IgnoreServerAborting(HttpServer* server) const {}
157
158 virtual HttpServer *CreateServer() = 0;
159
160 protected:
161 DirectProxyResolver proxy_resolver_;
162};
163
164class MockHttpFetcherTest : public AnyHttpFetcherTest {
165 public:
166 // Necessary to unhide the definition in the base class.
167 using AnyHttpFetcherTest::NewLargeFetcher;
168 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
169 vector<char> big_data(1000000);
170 CHECK(num_proxies > 0);
171 proxy_resolver_.set_num_proxies(num_proxies);
172 return new MockHttpFetcher(
173 big_data.data(),
174 big_data.size(),
175 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
176 }
177
178 // Necessary to unhide the definition in the base class.
179 using AnyHttpFetcherTest::NewSmallFetcher;
180 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
181 CHECK(num_proxies > 0);
182 proxy_resolver_.set_num_proxies(num_proxies);
183 return new MockHttpFetcher(
184 "x",
185 1,
186 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
187 }
188
189 virtual bool IsMock() const { return true; }
190 virtual bool IsMulti() const { return false; }
191
192 virtual HttpServer *CreateServer() {
193 return new NullHttpServer;
194 }
195};
196
197class LibcurlHttpFetcherTest : public AnyHttpFetcherTest {
198 public:
199 // Necessary to unhide the definition in the base class.
200 using AnyHttpFetcherTest::NewLargeFetcher;
201 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
202 CHECK(num_proxies > 0);
203 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes45168102010-11-22 11:13:50 -0800204 LibcurlHttpFetcher *ret = new
205 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
Darin Petkovb83371f2010-08-17 09:34:49 -0700206 // Speed up test execution.
207 ret->set_idle_seconds(1);
208 ret->set_retry_seconds(1);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700209 ret->SetConnectionAsExpensive(false);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700210 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000211 return ret;
212 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800213
214 // Necessary to unhide the definition in the base class.
215 using AnyHttpFetcherTest::NewSmallFetcher;
216 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
217 return NewLargeFetcher(num_proxies);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000218 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800219
220 virtual string BigUrl() const {
221 return LocalServerUrlForPath(base::StringPrintf("/download/%d",
222 kBigLength));
rspangler@google.com49fdf182009-10-10 00:57:34 +0000223 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800224 virtual string SmallUrl() const {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000225 return LocalServerUrlForPath("/foo");
226 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800227 virtual string ErrorUrl() const {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800228 return LocalServerUrlForPath("/error");
229 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800230
231 virtual bool IsMock() const { return false; }
232 virtual bool IsMulti() const { return false; }
233
234 virtual void IgnoreServerAborting(HttpServer* server) const {
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700235 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
236 pyserver->validate_quit_ = false;
237 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800238
239 virtual HttpServer *CreateServer() {
240 return new PythonHttpServer;
241 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000242};
243
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800244class MultiRangeHttpFetcherTest : public LibcurlHttpFetcherTest {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700245 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800246 // Necessary to unhide the definition in the base class.
247 using AnyHttpFetcherTest::NewLargeFetcher;
248 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
249 CHECK(num_proxies > 0);
250 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800251 ProxyResolver* resolver =
252 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800253 MultiRangeHttpFetcher *ret =
254 new MultiRangeHttpFetcher(new LibcurlHttpFetcher(resolver));
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800255 ret->ClearRanges();
256 ret->AddRange(0, -1);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700257 // Speed up test execution.
258 ret->set_idle_seconds(1);
259 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700260 ret->SetConnectionAsExpensive(false);
261 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700262 return ret;
263 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800264
265 // Necessary to unhide the definition in the base class.
266 using AnyHttpFetcherTest::NewSmallFetcher;
267 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
268 return NewLargeFetcher(num_proxies);
269 }
270
271 virtual bool IsMulti() const { return true; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700272};
273
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800274
275//
276// Infrastructure for type tests of HTTP fetcher.
277// See: http://code.google.com/p/googletest/wiki/AdvancedGuide#Typed_Tests
278//
279
280// Fixture class template. We use an explicit constraint to guarantee that it
281// can only be instantiated with an AnyHttpFetcherTest type, see:
282// http://www2.research.att.com/~bs/bs_faq2.html#constraints
283template <typename T>
284class HttpFetcherTest : public ::testing::Test {
285 public:
286 T test_;
287
288 private:
289 static void TypeConstraint(T *a) {
290 AnyHttpFetcherTest *b = a;
291 }
292};
293
294// Test case types list.
295typedef ::testing::Types<LibcurlHttpFetcherTest,
296 MockHttpFetcherTest,
297 MultiRangeHttpFetcherTest> HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000298TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
299
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800300
rspangler@google.com49fdf182009-10-10 00:57:34 +0000301namespace {
302class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000303 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800304 HttpFetcherTestDelegate() :
Gilad Arnold48085ba2011-11-16 09:36:08 -0800305 is_expect_error_(false), times_transfer_complete_called_(0),
306 times_transfer_terminated_called_(0), times_received_bytes_called_(0) {}
307
rspangler@google.com49fdf182009-10-10 00:57:34 +0000308 virtual void ReceivedBytes(HttpFetcher* fetcher,
309 const char* bytes, int length) {
310 char str[length + 1];
311 memset(str, 0, length + 1);
312 memcpy(str, bytes, length);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800313
314 // Update counters
315 times_received_bytes_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000316 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800317
rspangler@google.com49fdf182009-10-10 00:57:34 +0000318 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800319 if (is_expect_error_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800320 EXPECT_EQ(kHttpResponseNotFound, fetcher->http_response_code());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800321 else
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800322 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000323 g_main_loop_quit(loop_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800324
325 // Update counter
326 times_transfer_complete_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000327 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800328
Darin Petkov9ce452b2010-11-17 14:33:28 -0800329 virtual void TransferTerminated(HttpFetcher* fetcher) {
330 ADD_FAILURE();
Gilad Arnold48085ba2011-11-16 09:36:08 -0800331 times_transfer_terminated_called_++;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800332 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800333
rspangler@google.com49fdf182009-10-10 00:57:34 +0000334 GMainLoop* loop_;
Gilad Arnold48085ba2011-11-16 09:36:08 -0800335
336 // Are we expecting an error response? (default: no)
337 bool is_expect_error_;
338
339 // Counters for callback invocations.
340 int times_transfer_complete_called_;
341 int times_transfer_terminated_called_;
342 int times_received_bytes_called_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000343};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000344
345struct StartTransferArgs {
346 HttpFetcher *http_fetcher;
347 string url;
348};
349
350gboolean StartTransfer(gpointer data) {
351 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
352 args->http_fetcher->BeginTransfer(args->url);
353 return FALSE;
354}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000355} // namespace {}
356
357TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700358 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000359 {
360 HttpFetcherTestDelegate delegate;
361 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800362 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000363 fetcher->set_delegate(&delegate);
364
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800365 scoped_ptr<HttpServer> server(this->test_.CreateServer());
366 ASSERT_TRUE(server->started_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000367
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800368 StartTransferArgs start_xfer_args = {fetcher.get(), this->test_.SmallUrl()};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000369
370 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000371 g_main_loop_run(loop);
372 }
373 g_main_loop_unref(loop);
374}
375
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700376TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700377 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700378 {
379 HttpFetcherTestDelegate delegate;
380 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800381 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700382 fetcher->set_delegate(&delegate);
383
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800384 scoped_ptr<HttpServer> server(this->test_.CreateServer());
385 ASSERT_TRUE(server->started_);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700386
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800387 StartTransferArgs start_xfer_args = {fetcher.get(), this->test_.BigUrl()};
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700388
389 g_timeout_add(0, StartTransfer, &start_xfer_args);
390 g_main_loop_run(loop);
391 }
392 g_main_loop_unref(loop);
393}
394
Gilad Arnold48085ba2011-11-16 09:36:08 -0800395// Issue #9648: when server returns an error HTTP response, the fetcher needs to
396// terminate transfer prematurely, rather than try to process the error payload.
397TYPED_TEST(HttpFetcherTest, ErrorTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800398 if (this->test_.IsMock() || this->test_.IsMulti())
Gilad Arnold48085ba2011-11-16 09:36:08 -0800399 return;
400 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
401 {
402 HttpFetcherTestDelegate delegate;
403 delegate.loop_ = loop;
404
405 // Delegate should expect an error response.
406 delegate.is_expect_error_ = true;
407
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800408 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800409 fetcher->set_delegate(&delegate);
410
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800411 scoped_ptr<HttpServer> server(this->test_.CreateServer());
412 ASSERT_TRUE(server->started_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800413
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800414 StartTransferArgs start_xfer_args = {
415 fetcher.get(),
416 this->test_.ErrorUrl()
417 };
Gilad Arnold48085ba2011-11-16 09:36:08 -0800418
419 g_timeout_add(0, StartTransfer, &start_xfer_args);
420 g_main_loop_run(loop);
421
422 // Make sure that no bytes were received.
423 CHECK_EQ(delegate.times_received_bytes_called_, 0);
424 CHECK_EQ(fetcher->GetBytesDownloaded(), 0);
425
426 // Make sure that transfer completion was signaled once, and no termination
427 // was signaled.
428 CHECK_EQ(delegate.times_transfer_complete_called_, 1);
429 CHECK_EQ(delegate.times_transfer_terminated_called_, 0);
430 }
431 g_main_loop_unref(loop);
432}
433
rspangler@google.com49fdf182009-10-10 00:57:34 +0000434namespace {
435class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
436 public:
437 virtual void ReceivedBytes(HttpFetcher* fetcher,
438 const char* bytes, int length) {
439 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000440 memset(str, 0, length + 1);
441 memcpy(str, bytes, length);
442 CHECK(!paused_);
443 paused_ = true;
444 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000445 }
446 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
447 g_main_loop_quit(loop_);
448 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800449 virtual void TransferTerminated(HttpFetcher* fetcher) {
450 ADD_FAILURE();
451 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000452 void Unpause() {
453 CHECK(paused_);
454 paused_ = false;
455 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000456 }
457 bool paused_;
458 HttpFetcher* fetcher_;
459 GMainLoop* loop_;
460};
461
462gboolean UnpausingTimeoutCallback(gpointer data) {
463 PausingHttpFetcherTestDelegate *delegate =
464 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
465 if (delegate->paused_)
466 delegate->Unpause();
467 return TRUE;
468}
469} // namespace {}
470
471TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700472 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000473 {
474 PausingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800475 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000476 delegate.paused_ = false;
477 delegate.loop_ = loop;
478 delegate.fetcher_ = fetcher.get();
479 fetcher->set_delegate(&delegate);
480
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800481 scoped_ptr<HttpServer> server(this->test_.CreateServer());
482 ASSERT_TRUE(server->started_);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800483
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800484 guint callback_id = g_timeout_add(kHttpResponseInternalServerError,
485 UnpausingTimeoutCallback, &delegate);
486 fetcher->BeginTransfer(this->test_.BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000487
488 g_main_loop_run(loop);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800489 g_source_remove(callback_id);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000490 }
491 g_main_loop_unref(loop);
492}
493
494namespace {
495class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
496 public:
497 virtual void ReceivedBytes(HttpFetcher* fetcher,
498 const char* bytes, int length) {}
499 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800500 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000501 g_main_loop_quit(loop_);
502 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800503 virtual void TransferTerminated(HttpFetcher* fetcher) {
504 EXPECT_EQ(fetcher, fetcher_.get());
505 EXPECT_FALSE(once_);
506 EXPECT_TRUE(callback_once_);
507 callback_once_ = false;
508 // |fetcher| can be destroyed during this callback.
509 fetcher_.reset(NULL);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800510 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000511 void TerminateTransfer() {
512 CHECK(once_);
513 once_ = false;
514 fetcher_->TerminateTransfer();
515 }
516 void EndLoop() {
517 g_main_loop_quit(loop_);
518 }
519 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800520 bool callback_once_;
521 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000522 GMainLoop* loop_;
523};
524
525gboolean AbortingTimeoutCallback(gpointer data) {
526 AbortingHttpFetcherTestDelegate *delegate =
527 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
528 if (delegate->once_) {
529 delegate->TerminateTransfer();
530 return TRUE;
531 } else {
532 delegate->EndLoop();
533 return FALSE;
534 }
535}
536} // namespace {}
537
538TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700539 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000540 {
541 AbortingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800542 delegate.fetcher_.reset(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000543 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800544 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000545 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800546 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000547
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800548 scoped_ptr<HttpServer> server(this->test_.CreateServer());
549 this->test_.IgnoreServerAborting(server.get());
550 ASSERT_TRUE(server->started_);
551
rspangler@google.com49fdf182009-10-10 00:57:34 +0000552 GSource* timeout_source_;
553 timeout_source_ = g_timeout_source_new(0); // ms
554 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
555 NULL);
556 g_source_attach(timeout_source_, NULL);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800557 delegate.fetcher_->BeginTransfer(this->test_.BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000558
559 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800560 CHECK(!delegate.once_);
561 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000562 g_source_destroy(timeout_source_);
563 }
564 g_main_loop_unref(loop);
565}
566
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000567namespace {
568class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
569 public:
570 virtual void ReceivedBytes(HttpFetcher* fetcher,
571 const char* bytes, int length) {
572 data.append(bytes, length);
573 }
574 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700575 EXPECT_TRUE(successful);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800576 EXPECT_EQ(kHttpResponsePartialContent, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000577 g_main_loop_quit(loop_);
578 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800579 virtual void TransferTerminated(HttpFetcher* fetcher) {
580 ADD_FAILURE();
581 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000582 string data;
583 GMainLoop* loop_;
584};
585} // namespace {}
586
587TYPED_TEST(HttpFetcherTest, FlakyTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800588 if (this->test_.IsMock())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000589 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700590 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000591 {
592 FlakyHttpFetcherTestDelegate delegate;
593 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800594 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000595 fetcher->set_delegate(&delegate);
596
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800597 scoped_ptr<HttpServer> server(this->test_.CreateServer());
598 ASSERT_TRUE(server->started_);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000599
600 StartTransferArgs start_xfer_args = {
601 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800602 LocalServerUrlForPath(StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
603 kFlakyTruncateLength,
604 kFlakySleepEvery,
605 kFlakySleepSecs))
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000606 };
607
608 g_timeout_add(0, StartTransfer, &start_xfer_args);
609 g_main_loop_run(loop);
610
611 // verify the data we get back
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800612 ASSERT_EQ(kBigLength, delegate.data.size());
613 for (int i = 0; i < kBigLength; i += 10) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000614 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
615 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
616 }
617 }
618 g_main_loop_unref(loop);
619}
620
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700621namespace {
622class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
623 public:
624 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
625 virtual void ReceivedBytes(HttpFetcher* fetcher,
626 const char* bytes, int length) {
627 if (server_) {
628 LOG(INFO) << "Stopping server";
629 delete server_;
630 LOG(INFO) << "server stopped";
631 server_ = NULL;
632 }
633 }
634 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
635 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700636 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700637 g_main_loop_quit(loop_);
638 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800639 virtual void TransferTerminated(HttpFetcher* fetcher) {
640 ADD_FAILURE();
641 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700642 GMainLoop* loop_;
643 PythonHttpServer* server_;
644};
645} // namespace {}
646
647
648TYPED_TEST(HttpFetcherTest, FailureTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800649 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700650 return;
651 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
652 {
653 FailureHttpFetcherTestDelegate delegate;
654 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800655 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700656 fetcher->set_delegate(&delegate);
657
658 StartTransferArgs start_xfer_args = {
659 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800660 LocalServerUrlForPath(this->test_.SmallUrl())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700661 };
662
663 g_timeout_add(0, StartTransfer, &start_xfer_args);
664 g_main_loop_run(loop);
665
666 // Exiting and testing happens in the delegate
667 }
668 g_main_loop_unref(loop);
669}
670
671TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800672 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700673 return;
674 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
675 {
676 FailureHttpFetcherTestDelegate delegate;
677 delegate.loop_ = loop;
678 delegate.server_ = new PythonHttpServer;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800679 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700680 fetcher->set_delegate(&delegate);
681
682 StartTransferArgs start_xfer_args = {
683 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800684 LocalServerUrlForPath(StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
685 kFlakyTruncateLength,
686 kFlakySleepEvery,
687 kFlakySleepSecs))
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700688 };
689
690 g_timeout_add(0, StartTransfer, &start_xfer_args);
691 g_main_loop_run(loop);
692
693 // Exiting and testing happens in the delegate
694 }
695 g_main_loop_unref(loop);
696}
697
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700698namespace {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800699const HttpResponseCode kRedirectCodes[] = {
700 kHttpResponseMovedPermanently, kHttpResponseFound, kHttpResponseSeeOther,
701 kHttpResponseTempRedirect
702};
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700703
704class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
705 public:
706 RedirectHttpFetcherTestDelegate(bool expected_successful)
707 : expected_successful_(expected_successful) {}
708 virtual void ReceivedBytes(HttpFetcher* fetcher,
709 const char* bytes, int length) {
710 data.append(bytes, length);
711 }
712 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
713 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700714 if (expected_successful_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800715 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
Darin Petkovcb466212010-08-26 09:40:11 -0700716 else {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800717 EXPECT_GE(fetcher->http_response_code(), kHttpResponseMovedPermanently);
718 EXPECT_LE(fetcher->http_response_code(), kHttpResponseTempRedirect);
Darin Petkovcb466212010-08-26 09:40:11 -0700719 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700720 g_main_loop_quit(loop_);
721 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800722 virtual void TransferTerminated(HttpFetcher* fetcher) {
723 ADD_FAILURE();
724 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700725 bool expected_successful_;
726 string data;
727 GMainLoop* loop_;
728};
729
730// RedirectTest takes ownership of |http_fetcher|.
731void RedirectTest(bool expected_successful,
732 const string& url,
733 HttpFetcher* http_fetcher) {
734 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
735 RedirectHttpFetcherTestDelegate delegate(expected_successful);
736 delegate.loop_ = loop;
737 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
738 fetcher->set_delegate(&delegate);
739
740 StartTransferArgs start_xfer_args =
741 { fetcher.get(), LocalServerUrlForPath(url) };
742
743 g_timeout_add(0, StartTransfer, &start_xfer_args);
744 g_main_loop_run(loop);
745 if (expected_successful) {
746 // verify the data we get back
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800747 ASSERT_EQ(kMediumLength, delegate.data.size());
748 for (int i = 0; i < kMediumLength; i += 10) {
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700749 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
750 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
751 }
752 }
753 g_main_loop_unref(loop);
754}
755} // namespace {}
756
757TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800758 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700759 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800760
761 scoped_ptr<HttpServer> server(this->test_.CreateServer());
762 ASSERT_TRUE(server->started_);
763
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700764 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800765 const string url = base::StringPrintf("/redirect/%d/download/%d",
766 kRedirectCodes[c],
767 kMediumLength);
768 RedirectTest(true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700769 }
770}
771
772TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800773 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700774 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800775
776 scoped_ptr<HttpServer> server(this->test_.CreateServer());
777 ASSERT_TRUE(server->started_);
778
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700779 string url;
780 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
781 url += base::StringPrintf("/redirect/%d",
782 kRedirectCodes[r % arraysize(kRedirectCodes)]);
783 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800784 url += base::StringPrintf("/download/%d", kMediumLength);
785 RedirectTest(true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700786}
787
788TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800789 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700790 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800791
792 scoped_ptr<HttpServer> server(this->test_.CreateServer());
793 ASSERT_TRUE(server->started_);
794
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700795 string url;
796 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
797 url += base::StringPrintf("/redirect/%d",
798 kRedirectCodes[r % arraysize(kRedirectCodes)]);
799 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800800 url += base::StringPrintf("/download/%d", kMediumLength);
801 RedirectTest(false, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700802}
803
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700804namespace {
805class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
806 public:
807 MultiHttpFetcherTestDelegate(int expected_response_code)
808 : expected_response_code_(expected_response_code) {}
809 virtual void ReceivedBytes(HttpFetcher* fetcher,
810 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800811 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700812 data.append(bytes, length);
813 }
814 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800815 EXPECT_EQ(fetcher, fetcher_.get());
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800816 EXPECT_EQ(expected_response_code_ != kHttpResponseUndefined, successful);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700817 if (expected_response_code_ != 0)
818 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800819 // Destroy the fetcher (because we're allowed to).
820 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700821 g_main_loop_quit(loop_);
822 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800823 virtual void TransferTerminated(HttpFetcher* fetcher) {
824 ADD_FAILURE();
825 }
826 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700827 int expected_response_code_;
828 string data;
829 GMainLoop* loop_;
830};
831
832void MultiTest(HttpFetcher* fetcher_in,
833 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800834 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700835 const string& expected_prefix,
836 off_t expected_size,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800837 HttpResponseCode expected_response_code) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700838 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
839 {
840 MultiHttpFetcherTestDelegate delegate(expected_response_code);
841 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800842 delegate.fetcher_.reset(fetcher_in);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800843 MultiRangeHttpFetcher* multi_fetcher =
844 dynamic_cast<MultiRangeHttpFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700845 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800846 multi_fetcher->ClearRanges();
847 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
848 e = ranges.end(); it != e; ++it) {
849 LOG(INFO) << "Adding range";
850 multi_fetcher->AddRange(it->first, it->second);
851 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700852 multi_fetcher->SetConnectionAsExpensive(false);
853 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800854 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700855
Darin Petkov9ce452b2010-11-17 14:33:28 -0800856 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700857
858 g_timeout_add(0, StartTransfer, &start_xfer_args);
859 g_main_loop_run(loop);
860
861 EXPECT_EQ(expected_size, delegate.data.size());
862 EXPECT_EQ(expected_prefix,
863 string(delegate.data.data(), expected_prefix.size()));
864 }
865 g_main_loop_unref(loop);
866}
867} // namespace {}
868
Darin Petkov9ce452b2010-11-17 14:33:28 -0800869TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800870 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700871 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800872
873 scoped_ptr<HttpServer> server(this->test_.CreateServer());
874 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700875
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800876 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700877 ranges.push_back(make_pair(0, 25));
878 ranges.push_back(make_pair(99, -1));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800879 MultiTest(this->test_.NewLargeFetcher(),
880 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700881 ranges,
882 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800883 kBigLength - (99 - 25),
884 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700885}
886
887TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800888 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700889 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800890
891 scoped_ptr<HttpServer> server(this->test_.CreateServer());
892 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700893
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800894 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700895 ranges.push_back(make_pair(0, 24));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800896 MultiTest(this->test_.NewLargeFetcher(),
897 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700898 ranges,
899 "abcdefghijabcdefghijabcd",
900 24,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800901 kHttpResponseOk);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700902}
903
904TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800905 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700906 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800907
908 scoped_ptr<HttpServer> server(this->test_.CreateServer());
909 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700910
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800911 vector<pair<off_t, off_t> > ranges;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800912 ranges.push_back(make_pair(kBigLength - 2, -1));
913 ranges.push_back(make_pair(kBigLength - 3, -1));
914 MultiTest(this->test_.NewLargeFetcher(),
915 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700916 ranges,
917 "ijhij",
918 5,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800919 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700920}
921
922TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800923 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700924 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800925
926 scoped_ptr<HttpServer> server(this->test_.CreateServer());
927 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700928
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800929 vector<pair<off_t, off_t> > ranges;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800930 ranges.push_back(make_pair(kBigLength - 2, 4));
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700931 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800932 LOG(INFO) << "i = " << i;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800933 MultiTest(this->test_.NewLargeFetcher(),
934 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700935 ranges,
936 "ij",
937 2,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800938 kHttpResponseUndefined);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700939 ranges.push_back(make_pair(0, 5));
940 }
941}
942
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800943// Issue #18143: when a fetch of a secondary chunk out of a chain, then it
944// should retry with other proxies listed before giving up.
945//
946// (1) successful recovery: The offset fetch will fail twice but succeed with
947// the third proxy.
948TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetRecoverableTest) {
949 if (!this->test_.IsMulti())
950 return;
951
952 scoped_ptr<HttpServer> server(this->test_.CreateServer());
953 ASSERT_TRUE(server->started_);
954
955 vector<pair<off_t, off_t> > ranges;
956 ranges.push_back(make_pair(0, 25));
957 ranges.push_back(make_pair(99, -1));
958 MultiTest(this->test_.NewLargeFetcher(3),
959 LocalServerUrlForPath(base::StringPrintf("/error-if-offset/%d/2",
960 kBigLength)),
961 ranges,
962 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
963 kBigLength - (99 - 25),
964 kHttpResponsePartialContent);
965}
966
967// (2) unsuccessful recovery: The offset fetch will fail repeatedly. The
968// fetcher will signal a (failed) completed transfer to the delegate.
969TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetUnrecoverableTest) {
970 if (!this->test_.IsMulti())
971 return;
972
973 scoped_ptr<HttpServer> server(this->test_.CreateServer());
974 ASSERT_TRUE(server->started_);
975
976 vector<pair<off_t, off_t> > ranges;
977 ranges.push_back(make_pair(0, 25));
978 ranges.push_back(make_pair(99, -1));
979 MultiTest(this->test_.NewLargeFetcher(2),
980 LocalServerUrlForPath(base::StringPrintf("/error-if-offset/%d/3",
981 kBigLength)),
982 ranges,
983 "abcdefghijabcdefghijabcde", // only received the first chunk
984 25,
985 kHttpResponseUndefined);
986}
987
988
989
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700990namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700991class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700992 public:
993 virtual void ReceivedBytes(HttpFetcher* fetcher,
994 const char* bytes, int length) {
995 ADD_FAILURE();
996 }
997 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
998 EXPECT_FALSE(successful);
999 g_main_loop_quit(loop_);
1000 }
Darin Petkov9ce452b2010-11-17 14:33:28 -08001001 virtual void TransferTerminated(HttpFetcher* fetcher) {
1002 ADD_FAILURE();
1003 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001004 GMainLoop* loop_;
1005};
1006
1007} // namespace
1008
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001009TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001010 if (this->test_.IsMock() || this->test_.IsMulti())
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001011 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001012
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001013 for (int i = 0; i < 2; i++) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001014 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1015 ASSERT_TRUE(server->started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001016
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001017 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
1018 BlockedTransferTestDelegate delegate;
1019 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001020
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001021 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001022 LibcurlHttpFetcher* curl_fetcher =
1023 dynamic_cast<LibcurlHttpFetcher*>(fetcher.get());
1024 bool is_expensive_connection = (i == 0);
1025 bool is_official_build = (i == 1);
1026 LOG(INFO) << "is_expensive_connection: " << is_expensive_connection;
1027 LOG(INFO) << "is_official_build: " << is_official_build;
1028 curl_fetcher->SetConnectionAsExpensive(is_expensive_connection);
1029 curl_fetcher->SetBuildType(is_official_build);
1030 fetcher->set_delegate(&delegate);
1031
1032 StartTransferArgs start_xfer_args =
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001033 { fetcher.get(), LocalServerUrlForPath(this->test_.SmallUrl()) };
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001034
1035 g_timeout_add(0, StartTransfer, &start_xfer_args);
1036 g_main_loop_run(loop);
1037 g_main_loop_unref(loop);
1038 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001039}
1040
rspangler@google.com49fdf182009-10-10 00:57:34 +00001041} // namespace chromeos_update_engine