blob: 2a0d5a664895aa0e97c02315bdea6316601de99a [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"
Jay Srinivasan08fce042012-06-07 16:31:01 -070022#include "update_engine/mock_system_state.h"
Andrew de los Reyes819fef22010-12-17 11:33:58 -080023#include "update_engine/multi_range_http_fetcher.h"
Andrew de los Reyes45168102010-11-22 11:13:50 -080024#include "update_engine/proxy_resolver.h"
Jay Srinivasan08fce042012-06-07 16:31:01 -070025#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000026
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070027using std::make_pair;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080028using std::pair;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000029using std::string;
30using std::vector;
31
Gilad Arnold9bedeb52011-11-17 16:19:57 -080032namespace {
33
34const int kBigLength = 100000;
35const int kMediumLength = 1000;
Gilad Arnold34bf1ee2012-02-09 16:16:02 -080036const int kFlakyTruncateLength = 29000;
37const int kFlakySleepEvery = 3;
Gilad Arnold9bedeb52011-11-17 16:19:57 -080038const int kFlakySleepSecs = 10;
39
40} // namespace
41
rspangler@google.com49fdf182009-10-10 00:57:34 +000042namespace chromeos_update_engine {
43
Gilad Arnold9bedeb52011-11-17 16:19:57 -080044static const char *kUnusedUrl = "unused://unused";
45
46static inline string LocalServerUrlForPath(const string& path) {
47 return (string("http://127.0.0.1:") + base::StringPrintf("%d", kServerPort) + path);
rspangler@google.com49fdf182009-10-10 00:57:34 +000048}
49
rspangler@google.com49fdf182009-10-10 00:57:34 +000050
Gilad Arnold9bedeb52011-11-17 16:19:57 -080051//
52// Class hierarchy for HTTP server implementations.
53//
54
55class HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000056 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080057 // This makes it an abstract class (dirty but works).
58 virtual ~HttpServer() = 0;
59
rspangler@google.com49fdf182009-10-10 00:57:34 +000060 bool started_;
61};
62
Gilad Arnold9bedeb52011-11-17 16:19:57 -080063HttpServer::~HttpServer() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000064
Gilad Arnold9bedeb52011-11-17 16:19:57 -080065
66class NullHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000067 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080068 NullHttpServer() {
69 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000070 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000071};
72
Gilad Arnold9bedeb52011-11-17 16:19:57 -080073
74class PythonHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000075 public:
76 PythonHttpServer() {
adlr@google.comc98a7ed2009-12-04 18:54:03 +000077 char *argv[2] = {strdup("./test_http_server"), NULL};
rspangler@google.com49fdf182009-10-10 00:57:34 +000078 GError *err;
79 started_ = false;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -070080 validate_quit_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000081 if (!g_spawn_async(NULL,
82 argv,
83 NULL,
84 G_SPAWN_DO_NOT_REAP_CHILD,
85 NULL,
86 NULL,
87 &pid_,
88 &err)) {
89 return;
90 }
91 int rc = 1;
Andrew de los Reyese7dcc2a2011-08-19 10:50:37 -070092 const uint64_t kMaxSleep = 60UL * 60UL * 1000UL * 1000UL; // 60 min
93 uint64_t timeout = 15 * 1000; // 15 ms
Andrew de los Reyes3270f742010-07-15 22:28:14 -070094 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000095 while (0 != rc) {
Andrew de los Reyes3270f742010-07-15 22:28:14 -070096 LOG(INFO) << "running wget to start";
rspangler@google.com49fdf182009-10-10 00:57:34 +000097 rc = system((string("wget --output-document=/dev/null ") +
98 LocalServerUrlForPath("/test")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -070099 LOG(INFO) << "done running wget to start";
Josh Horwich2d4e1c52011-08-22 11:58:02 -0700100 if (0 != rc) {
101 if (timeout > kMaxSleep) {
102 LOG(ERROR) << "Unable to start server.";
103 started_ = false;
104 break;
105 }
106 if (timeout < (1000 * 1000)) // sub 1-second sleep, use usleep
107 usleep(static_cast<useconds_t>(timeout));
108 else
109 sleep(static_cast<unsigned int>(timeout / (1000 * 1000)));
110 timeout *= 2;
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700111 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000112 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000113 free(argv[0]);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700114 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000115 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800116
rspangler@google.com49fdf182009-10-10 00:57:34 +0000117 ~PythonHttpServer() {
118 if (!started_)
119 return;
120 // request that the server exit itself
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700121 LOG(INFO) << "running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700122 int rc = system((string("wget -t 1 --output-document=/dev/null ") +
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700123 LocalServerUrlForPath("/quitquitquit")).c_str());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700124 LOG(INFO) << "done running wget to exit";
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700125 if (validate_quit_)
126 EXPECT_EQ(0, rc);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000127 waitpid(pid_, NULL, 0);
128 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800129
rspangler@google.com49fdf182009-10-10 00:57:34 +0000130 GPid pid_;
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700131 bool validate_quit_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000132};
133
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800134
135
136//
137// Class hierarchy for HTTP fetcher test wrappers.
138//
139
140class AnyHttpFetcherTest {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000141 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800142 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) = 0;
143 HttpFetcher* NewLargeFetcher() {
144 return NewLargeFetcher(1);
145 }
146
147 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) = 0;
148 HttpFetcher* NewSmallFetcher() {
149 return NewSmallFetcher(1);
150 }
151
152 virtual string BigUrl() const { return kUnusedUrl; }
153 virtual string SmallUrl() const { return kUnusedUrl; }
154 virtual string ErrorUrl() const { return kUnusedUrl; }
155
156 virtual bool IsMock() const = 0;
157 virtual bool IsMulti() const = 0;
158
159 virtual void IgnoreServerAborting(HttpServer* server) const {}
160
161 virtual HttpServer *CreateServer() = 0;
162
163 protected:
164 DirectProxyResolver proxy_resolver_;
165};
166
167class MockHttpFetcherTest : public AnyHttpFetcherTest {
168 public:
169 // Necessary to unhide the definition in the base class.
170 using AnyHttpFetcherTest::NewLargeFetcher;
171 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
172 vector<char> big_data(1000000);
173 CHECK(num_proxies > 0);
174 proxy_resolver_.set_num_proxies(num_proxies);
175 return new MockHttpFetcher(
176 big_data.data(),
177 big_data.size(),
178 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
179 }
180
181 // Necessary to unhide the definition in the base class.
182 using AnyHttpFetcherTest::NewSmallFetcher;
183 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
184 CHECK(num_proxies > 0);
185 proxy_resolver_.set_num_proxies(num_proxies);
186 return new MockHttpFetcher(
187 "x",
188 1,
189 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
190 }
191
192 virtual bool IsMock() const { return true; }
193 virtual bool IsMulti() const { return false; }
194
195 virtual HttpServer *CreateServer() {
196 return new NullHttpServer;
197 }
198};
199
200class LibcurlHttpFetcherTest : public AnyHttpFetcherTest {
201 public:
202 // Necessary to unhide the definition in the base class.
203 using AnyHttpFetcherTest::NewLargeFetcher;
204 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
205 CHECK(num_proxies > 0);
206 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes45168102010-11-22 11:13:50 -0800207 LibcurlHttpFetcher *ret = new
Jay Srinivasan08fce042012-06-07 16:31:01 -0700208 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_),
209 &mock_system_state_);
Darin Petkovb83371f2010-08-17 09:34:49 -0700210 // Speed up test execution.
211 ret->set_idle_seconds(1);
212 ret->set_retry_seconds(1);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -0700213 ret->SetConnectionAsExpensive(false);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700214 ret->SetBuildType(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000215 return ret;
216 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800217
218 // Necessary to unhide the definition in the base class.
219 using AnyHttpFetcherTest::NewSmallFetcher;
220 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
221 return NewLargeFetcher(num_proxies);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000222 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800223
224 virtual string BigUrl() const {
225 return LocalServerUrlForPath(base::StringPrintf("/download/%d",
226 kBigLength));
rspangler@google.com49fdf182009-10-10 00:57:34 +0000227 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800228 virtual string SmallUrl() const {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000229 return LocalServerUrlForPath("/foo");
230 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800231 virtual string ErrorUrl() const {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800232 return LocalServerUrlForPath("/error");
233 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800234
235 virtual bool IsMock() const { return false; }
236 virtual bool IsMulti() const { return false; }
237
238 virtual void IgnoreServerAborting(HttpServer* server) const {
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700239 PythonHttpServer *pyserver = reinterpret_cast<PythonHttpServer*>(server);
240 pyserver->validate_quit_ = false;
241 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800242
243 virtual HttpServer *CreateServer() {
244 return new PythonHttpServer;
245 }
Jay Srinivasan08fce042012-06-07 16:31:01 -0700246
247 MockSystemState mock_system_state_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000248};
249
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800250class MultiRangeHttpFetcherTest : public LibcurlHttpFetcherTest {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700251 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800252 // Necessary to unhide the definition in the base class.
253 using AnyHttpFetcherTest::NewLargeFetcher;
254 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
255 CHECK(num_proxies > 0);
256 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800257 ProxyResolver* resolver =
258 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
Jay Srinivasan08fce042012-06-07 16:31:01 -0700259 MultiRangeHttpFetcher *ret = new MultiRangeHttpFetcher(
260 new LibcurlHttpFetcher(resolver, &mock_system_state_));
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800261 ret->ClearRanges();
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800262 ret->AddRange(0);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700263 // Speed up test execution.
264 ret->set_idle_seconds(1);
265 ret->set_retry_seconds(1);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700266 ret->SetConnectionAsExpensive(false);
267 ret->SetBuildType(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700268 return ret;
269 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800270
271 // Necessary to unhide the definition in the base class.
272 using AnyHttpFetcherTest::NewSmallFetcher;
273 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
274 return NewLargeFetcher(num_proxies);
275 }
276
277 virtual bool IsMulti() const { return true; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700278};
279
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800280
281//
282// Infrastructure for type tests of HTTP fetcher.
283// See: http://code.google.com/p/googletest/wiki/AdvancedGuide#Typed_Tests
284//
285
286// Fixture class template. We use an explicit constraint to guarantee that it
287// can only be instantiated with an AnyHttpFetcherTest type, see:
288// http://www2.research.att.com/~bs/bs_faq2.html#constraints
289template <typename T>
290class HttpFetcherTest : public ::testing::Test {
291 public:
292 T test_;
293
294 private:
295 static void TypeConstraint(T *a) {
296 AnyHttpFetcherTest *b = a;
297 }
298};
299
300// Test case types list.
301typedef ::testing::Types<LibcurlHttpFetcherTest,
302 MockHttpFetcherTest,
303 MultiRangeHttpFetcherTest> HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000304TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
305
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800306
rspangler@google.com49fdf182009-10-10 00:57:34 +0000307namespace {
308class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000309 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800310 HttpFetcherTestDelegate() :
Gilad Arnold48085ba2011-11-16 09:36:08 -0800311 is_expect_error_(false), times_transfer_complete_called_(0),
312 times_transfer_terminated_called_(0), times_received_bytes_called_(0) {}
313
rspangler@google.com49fdf182009-10-10 00:57:34 +0000314 virtual void ReceivedBytes(HttpFetcher* fetcher,
315 const char* bytes, int length) {
316 char str[length + 1];
317 memset(str, 0, length + 1);
318 memcpy(str, bytes, length);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800319
320 // Update counters
321 times_received_bytes_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000322 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800323
rspangler@google.com49fdf182009-10-10 00:57:34 +0000324 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800325 if (is_expect_error_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800326 EXPECT_EQ(kHttpResponseNotFound, fetcher->http_response_code());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800327 else
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800328 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000329 g_main_loop_quit(loop_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800330
331 // Update counter
332 times_transfer_complete_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000333 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800334
Darin Petkov9ce452b2010-11-17 14:33:28 -0800335 virtual void TransferTerminated(HttpFetcher* fetcher) {
336 ADD_FAILURE();
Gilad Arnold48085ba2011-11-16 09:36:08 -0800337 times_transfer_terminated_called_++;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800338 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800339
rspangler@google.com49fdf182009-10-10 00:57:34 +0000340 GMainLoop* loop_;
Gilad Arnold48085ba2011-11-16 09:36:08 -0800341
342 // Are we expecting an error response? (default: no)
343 bool is_expect_error_;
344
345 // Counters for callback invocations.
346 int times_transfer_complete_called_;
347 int times_transfer_terminated_called_;
348 int times_received_bytes_called_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000349};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000350
351struct StartTransferArgs {
352 HttpFetcher *http_fetcher;
353 string url;
354};
355
356gboolean StartTransfer(gpointer data) {
357 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
358 args->http_fetcher->BeginTransfer(args->url);
359 return FALSE;
360}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000361} // namespace {}
362
363TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700364 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000365 {
366 HttpFetcherTestDelegate delegate;
367 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800368 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000369 fetcher->set_delegate(&delegate);
370
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800371 scoped_ptr<HttpServer> server(this->test_.CreateServer());
372 ASSERT_TRUE(server->started_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000373
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800374 StartTransferArgs start_xfer_args = {fetcher.get(), this->test_.SmallUrl()};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000375
376 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000377 g_main_loop_run(loop);
378 }
379 g_main_loop_unref(loop);
380}
381
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700382TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700383 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700384 {
385 HttpFetcherTestDelegate delegate;
386 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800387 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700388 fetcher->set_delegate(&delegate);
389
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800390 scoped_ptr<HttpServer> server(this->test_.CreateServer());
391 ASSERT_TRUE(server->started_);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700392
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800393 StartTransferArgs start_xfer_args = {fetcher.get(), this->test_.BigUrl()};
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700394
395 g_timeout_add(0, StartTransfer, &start_xfer_args);
396 g_main_loop_run(loop);
397 }
398 g_main_loop_unref(loop);
399}
400
Gilad Arnold48085ba2011-11-16 09:36:08 -0800401// Issue #9648: when server returns an error HTTP response, the fetcher needs to
402// terminate transfer prematurely, rather than try to process the error payload.
403TYPED_TEST(HttpFetcherTest, ErrorTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800404 if (this->test_.IsMock() || this->test_.IsMulti())
Gilad Arnold48085ba2011-11-16 09:36:08 -0800405 return;
406 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
407 {
408 HttpFetcherTestDelegate delegate;
409 delegate.loop_ = loop;
410
411 // Delegate should expect an error response.
412 delegate.is_expect_error_ = true;
413
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800414 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800415 fetcher->set_delegate(&delegate);
416
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800417 scoped_ptr<HttpServer> server(this->test_.CreateServer());
418 ASSERT_TRUE(server->started_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800419
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800420 StartTransferArgs start_xfer_args = {
421 fetcher.get(),
422 this->test_.ErrorUrl()
423 };
Gilad Arnold48085ba2011-11-16 09:36:08 -0800424
425 g_timeout_add(0, StartTransfer, &start_xfer_args);
426 g_main_loop_run(loop);
427
428 // Make sure that no bytes were received.
429 CHECK_EQ(delegate.times_received_bytes_called_, 0);
Mike Frysinger0f9547d2012-02-16 12:11:37 -0500430 CHECK_EQ(fetcher->GetBytesDownloaded(), static_cast<size_t>(0));
Gilad Arnold48085ba2011-11-16 09:36:08 -0800431
432 // Make sure that transfer completion was signaled once, and no termination
433 // was signaled.
434 CHECK_EQ(delegate.times_transfer_complete_called_, 1);
435 CHECK_EQ(delegate.times_transfer_terminated_called_, 0);
436 }
437 g_main_loop_unref(loop);
438}
439
rspangler@google.com49fdf182009-10-10 00:57:34 +0000440namespace {
441class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
442 public:
443 virtual void ReceivedBytes(HttpFetcher* fetcher,
444 const char* bytes, int length) {
445 char str[length + 1];
rspangler@google.com49fdf182009-10-10 00:57:34 +0000446 memset(str, 0, length + 1);
447 memcpy(str, bytes, length);
448 CHECK(!paused_);
449 paused_ = true;
450 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000451 }
452 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
453 g_main_loop_quit(loop_);
454 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800455 virtual void TransferTerminated(HttpFetcher* fetcher) {
456 ADD_FAILURE();
457 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000458 void Unpause() {
459 CHECK(paused_);
460 paused_ = false;
461 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000462 }
463 bool paused_;
464 HttpFetcher* fetcher_;
465 GMainLoop* loop_;
466};
467
468gboolean UnpausingTimeoutCallback(gpointer data) {
469 PausingHttpFetcherTestDelegate *delegate =
470 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
471 if (delegate->paused_)
472 delegate->Unpause();
473 return TRUE;
474}
475} // namespace {}
476
477TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700478 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000479 {
480 PausingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800481 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000482 delegate.paused_ = false;
483 delegate.loop_ = loop;
484 delegate.fetcher_ = fetcher.get();
485 fetcher->set_delegate(&delegate);
486
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800487 scoped_ptr<HttpServer> server(this->test_.CreateServer());
488 ASSERT_TRUE(server->started_);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800489
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800490 guint callback_id = g_timeout_add(kHttpResponseInternalServerError,
491 UnpausingTimeoutCallback, &delegate);
492 fetcher->BeginTransfer(this->test_.BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000493
494 g_main_loop_run(loop);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800495 g_source_remove(callback_id);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000496 }
497 g_main_loop_unref(loop);
498}
499
500namespace {
501class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
502 public:
503 virtual void ReceivedBytes(HttpFetcher* fetcher,
504 const char* bytes, int length) {}
505 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800506 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000507 g_main_loop_quit(loop_);
508 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800509 virtual void TransferTerminated(HttpFetcher* fetcher) {
510 EXPECT_EQ(fetcher, fetcher_.get());
511 EXPECT_FALSE(once_);
512 EXPECT_TRUE(callback_once_);
513 callback_once_ = false;
514 // |fetcher| can be destroyed during this callback.
515 fetcher_.reset(NULL);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800516 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000517 void TerminateTransfer() {
518 CHECK(once_);
519 once_ = false;
520 fetcher_->TerminateTransfer();
521 }
522 void EndLoop() {
523 g_main_loop_quit(loop_);
524 }
525 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800526 bool callback_once_;
527 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000528 GMainLoop* loop_;
529};
530
531gboolean AbortingTimeoutCallback(gpointer data) {
532 AbortingHttpFetcherTestDelegate *delegate =
533 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
534 if (delegate->once_) {
535 delegate->TerminateTransfer();
536 return TRUE;
537 } else {
538 delegate->EndLoop();
539 return FALSE;
540 }
541}
542} // namespace {}
543
544TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700545 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000546 {
547 AbortingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800548 delegate.fetcher_.reset(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000549 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800550 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000551 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800552 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000553
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800554 scoped_ptr<HttpServer> server(this->test_.CreateServer());
555 this->test_.IgnoreServerAborting(server.get());
556 ASSERT_TRUE(server->started_);
557
rspangler@google.com49fdf182009-10-10 00:57:34 +0000558 GSource* timeout_source_;
559 timeout_source_ = g_timeout_source_new(0); // ms
560 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
561 NULL);
562 g_source_attach(timeout_source_, NULL);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800563 delegate.fetcher_->BeginTransfer(this->test_.BigUrl());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000564
565 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800566 CHECK(!delegate.once_);
567 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000568 g_source_destroy(timeout_source_);
569 }
570 g_main_loop_unref(loop);
571}
572
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000573namespace {
574class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
575 public:
576 virtual void ReceivedBytes(HttpFetcher* fetcher,
577 const char* bytes, int length) {
578 data.append(bytes, length);
579 }
580 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700581 EXPECT_TRUE(successful);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800582 EXPECT_EQ(kHttpResponsePartialContent, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000583 g_main_loop_quit(loop_);
584 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800585 virtual void TransferTerminated(HttpFetcher* fetcher) {
586 ADD_FAILURE();
587 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000588 string data;
589 GMainLoop* loop_;
590};
591} // namespace {}
592
593TYPED_TEST(HttpFetcherTest, FlakyTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800594 if (this->test_.IsMock())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000595 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700596 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000597 {
598 FlakyHttpFetcherTestDelegate delegate;
599 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800600 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000601 fetcher->set_delegate(&delegate);
602
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800603 scoped_ptr<HttpServer> server(this->test_.CreateServer());
604 ASSERT_TRUE(server->started_);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000605
606 StartTransferArgs start_xfer_args = {
607 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800608 LocalServerUrlForPath(StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
609 kFlakyTruncateLength,
610 kFlakySleepEvery,
611 kFlakySleepSecs))
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000612 };
613
614 g_timeout_add(0, StartTransfer, &start_xfer_args);
615 g_main_loop_run(loop);
616
617 // verify the data we get back
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800618 ASSERT_EQ(kBigLength, delegate.data.size());
619 for (int i = 0; i < kBigLength; i += 10) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000620 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
621 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
622 }
623 }
624 g_main_loop_unref(loop);
625}
626
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700627namespace {
628class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
629 public:
630 FailureHttpFetcherTestDelegate() : loop_(NULL), server_(NULL) {}
631 virtual void ReceivedBytes(HttpFetcher* fetcher,
632 const char* bytes, int length) {
633 if (server_) {
634 LOG(INFO) << "Stopping server";
635 delete server_;
636 LOG(INFO) << "server stopped";
637 server_ = NULL;
638 }
639 }
640 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
641 EXPECT_FALSE(successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700642 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700643 g_main_loop_quit(loop_);
644 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800645 virtual void TransferTerminated(HttpFetcher* fetcher) {
646 ADD_FAILURE();
647 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700648 GMainLoop* loop_;
649 PythonHttpServer* server_;
650};
651} // namespace {}
652
653
654TYPED_TEST(HttpFetcherTest, FailureTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800655 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700656 return;
657 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
658 {
659 FailureHttpFetcherTestDelegate delegate;
660 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800661 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700662 fetcher->set_delegate(&delegate);
663
664 StartTransferArgs start_xfer_args = {
665 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800666 LocalServerUrlForPath(this->test_.SmallUrl())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700667 };
668
669 g_timeout_add(0, StartTransfer, &start_xfer_args);
670 g_main_loop_run(loop);
671
672 // Exiting and testing happens in the delegate
673 }
674 g_main_loop_unref(loop);
675}
676
677TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800678 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700679 return;
680 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
681 {
682 FailureHttpFetcherTestDelegate delegate;
683 delegate.loop_ = loop;
684 delegate.server_ = new PythonHttpServer;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800685 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700686 fetcher->set_delegate(&delegate);
687
688 StartTransferArgs start_xfer_args = {
689 fetcher.get(),
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800690 LocalServerUrlForPath(StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
691 kFlakyTruncateLength,
692 kFlakySleepEvery,
693 kFlakySleepSecs))
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700694 };
695
696 g_timeout_add(0, StartTransfer, &start_xfer_args);
697 g_main_loop_run(loop);
698
699 // Exiting and testing happens in the delegate
700 }
701 g_main_loop_unref(loop);
702}
703
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700704namespace {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800705const HttpResponseCode kRedirectCodes[] = {
706 kHttpResponseMovedPermanently, kHttpResponseFound, kHttpResponseSeeOther,
707 kHttpResponseTempRedirect
708};
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700709
710class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
711 public:
712 RedirectHttpFetcherTestDelegate(bool expected_successful)
713 : expected_successful_(expected_successful) {}
714 virtual void ReceivedBytes(HttpFetcher* fetcher,
715 const char* bytes, int length) {
716 data.append(bytes, length);
717 }
718 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
719 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700720 if (expected_successful_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800721 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
Darin Petkovcb466212010-08-26 09:40:11 -0700722 else {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800723 EXPECT_GE(fetcher->http_response_code(), kHttpResponseMovedPermanently);
724 EXPECT_LE(fetcher->http_response_code(), kHttpResponseTempRedirect);
Darin Petkovcb466212010-08-26 09:40:11 -0700725 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700726 g_main_loop_quit(loop_);
727 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800728 virtual void TransferTerminated(HttpFetcher* fetcher) {
729 ADD_FAILURE();
730 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700731 bool expected_successful_;
732 string data;
733 GMainLoop* loop_;
734};
735
736// RedirectTest takes ownership of |http_fetcher|.
737void RedirectTest(bool expected_successful,
738 const string& url,
739 HttpFetcher* http_fetcher) {
740 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
741 RedirectHttpFetcherTestDelegate delegate(expected_successful);
742 delegate.loop_ = loop;
743 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
744 fetcher->set_delegate(&delegate);
745
746 StartTransferArgs start_xfer_args =
747 { fetcher.get(), LocalServerUrlForPath(url) };
748
749 g_timeout_add(0, StartTransfer, &start_xfer_args);
750 g_main_loop_run(loop);
751 if (expected_successful) {
752 // verify the data we get back
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800753 ASSERT_EQ(kMediumLength, delegate.data.size());
754 for (int i = 0; i < kMediumLength; i += 10) {
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700755 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
756 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
757 }
758 }
759 g_main_loop_unref(loop);
760}
761} // namespace {}
762
763TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800764 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700765 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800766
767 scoped_ptr<HttpServer> server(this->test_.CreateServer());
768 ASSERT_TRUE(server->started_);
769
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700770 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800771 const string url = base::StringPrintf("/redirect/%d/download/%d",
772 kRedirectCodes[c],
773 kMediumLength);
774 RedirectTest(true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700775 }
776}
777
778TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800779 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700780 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800781
782 scoped_ptr<HttpServer> server(this->test_.CreateServer());
783 ASSERT_TRUE(server->started_);
784
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700785 string url;
786 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects; r++) {
787 url += base::StringPrintf("/redirect/%d",
788 kRedirectCodes[r % arraysize(kRedirectCodes)]);
789 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800790 url += base::StringPrintf("/download/%d", kMediumLength);
791 RedirectTest(true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700792}
793
794TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800795 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700796 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800797
798 scoped_ptr<HttpServer> server(this->test_.CreateServer());
799 ASSERT_TRUE(server->started_);
800
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700801 string url;
802 for (int r = 0; r < LibcurlHttpFetcher::kMaxRedirects + 1; r++) {
803 url += base::StringPrintf("/redirect/%d",
804 kRedirectCodes[r % arraysize(kRedirectCodes)]);
805 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800806 url += base::StringPrintf("/download/%d", kMediumLength);
807 RedirectTest(false, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700808}
809
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700810namespace {
811class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
812 public:
813 MultiHttpFetcherTestDelegate(int expected_response_code)
814 : expected_response_code_(expected_response_code) {}
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800815
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700816 virtual void ReceivedBytes(HttpFetcher* fetcher,
817 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800818 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700819 data.append(bytes, length);
820 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800821
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700822 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800823 EXPECT_EQ(fetcher, fetcher_.get());
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800824 EXPECT_EQ(expected_response_code_ != kHttpResponseUndefined, successful);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700825 if (expected_response_code_ != 0)
826 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800827 // Destroy the fetcher (because we're allowed to).
828 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700829 g_main_loop_quit(loop_);
830 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800831
Darin Petkov9ce452b2010-11-17 14:33:28 -0800832 virtual void TransferTerminated(HttpFetcher* fetcher) {
833 ADD_FAILURE();
834 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800835
Darin Petkov9ce452b2010-11-17 14:33:28 -0800836 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700837 int expected_response_code_;
838 string data;
839 GMainLoop* loop_;
840};
841
842void MultiTest(HttpFetcher* fetcher_in,
843 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800844 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700845 const string& expected_prefix,
846 off_t expected_size,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800847 HttpResponseCode expected_response_code) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700848 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
849 {
850 MultiHttpFetcherTestDelegate delegate(expected_response_code);
851 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800852 delegate.fetcher_.reset(fetcher_in);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800853 MultiRangeHttpFetcher* multi_fetcher =
854 dynamic_cast<MultiRangeHttpFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700855 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800856 multi_fetcher->ClearRanges();
857 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
858 e = ranges.end(); it != e; ++it) {
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800859 std::string tmp_str = StringPrintf("%jd+", it->first);
860 if (it->second > 0) {
861 base::StringAppendF(&tmp_str, "%jd", it->second);
862 multi_fetcher->AddRange(it->first, it->second);
863 } else {
864 base::StringAppendF(&tmp_str, "?");
865 multi_fetcher->AddRange(it->first);
866 }
867 LOG(INFO) << "added range: " << tmp_str;
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800868 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -0700869 multi_fetcher->SetConnectionAsExpensive(false);
870 multi_fetcher->SetBuildType(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800871 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700872
Darin Petkov9ce452b2010-11-17 14:33:28 -0800873 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700874
875 g_timeout_add(0, StartTransfer, &start_xfer_args);
876 g_main_loop_run(loop);
877
878 EXPECT_EQ(expected_size, delegate.data.size());
879 EXPECT_EQ(expected_prefix,
880 string(delegate.data.data(), expected_prefix.size()));
881 }
882 g_main_loop_unref(loop);
883}
884} // namespace {}
885
Darin Petkov9ce452b2010-11-17 14:33:28 -0800886TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800887 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700888 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800889
890 scoped_ptr<HttpServer> server(this->test_.CreateServer());
891 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700892
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800893 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700894 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800895 ranges.push_back(make_pair(99, 0));
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 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800900 kBigLength - (99 - 25),
901 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700902}
903
904TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
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;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700912 ranges.push_back(make_pair(0, 24));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800913 MultiTest(this->test_.NewLargeFetcher(),
914 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700915 ranges,
916 "abcdefghijabcdefghijabcd",
917 24,
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800918 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700919}
920
921TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800922 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700923 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800924
925 scoped_ptr<HttpServer> server(this->test_.CreateServer());
926 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700927
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800928 vector<pair<off_t, off_t> > ranges;
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800929 ranges.push_back(make_pair(kBigLength - 2, 0));
930 ranges.push_back(make_pair(kBigLength - 3, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800931 MultiTest(this->test_.NewLargeFetcher(),
932 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700933 ranges,
934 "ijhij",
935 5,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800936 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700937}
938
939TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800940 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700941 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800942
943 scoped_ptr<HttpServer> server(this->test_.CreateServer());
944 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700945
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800946 vector<pair<off_t, off_t> > ranges;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800947 ranges.push_back(make_pair(kBigLength - 2, 4));
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700948 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800949 LOG(INFO) << "i = " << i;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800950 MultiTest(this->test_.NewLargeFetcher(),
951 this->test_.BigUrl(),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700952 ranges,
953 "ij",
954 2,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800955 kHttpResponseUndefined);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700956 ranges.push_back(make_pair(0, 5));
957 }
958}
959
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800960// Issue #18143: when a fetch of a secondary chunk out of a chain, then it
961// should retry with other proxies listed before giving up.
962//
963// (1) successful recovery: The offset fetch will fail twice but succeed with
964// the third proxy.
965TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetRecoverableTest) {
966 if (!this->test_.IsMulti())
967 return;
968
969 scoped_ptr<HttpServer> server(this->test_.CreateServer());
970 ASSERT_TRUE(server->started_);
971
972 vector<pair<off_t, off_t> > ranges;
973 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800974 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800975 MultiTest(this->test_.NewLargeFetcher(3),
976 LocalServerUrlForPath(base::StringPrintf("/error-if-offset/%d/2",
977 kBigLength)),
978 ranges,
979 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
980 kBigLength - (99 - 25),
981 kHttpResponsePartialContent);
982}
983
984// (2) unsuccessful recovery: The offset fetch will fail repeatedly. The
985// fetcher will signal a (failed) completed transfer to the delegate.
986TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetUnrecoverableTest) {
987 if (!this->test_.IsMulti())
988 return;
989
990 scoped_ptr<HttpServer> server(this->test_.CreateServer());
991 ASSERT_TRUE(server->started_);
992
993 vector<pair<off_t, off_t> > ranges;
994 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800995 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800996 MultiTest(this->test_.NewLargeFetcher(2),
997 LocalServerUrlForPath(base::StringPrintf("/error-if-offset/%d/3",
998 kBigLength)),
999 ranges,
1000 "abcdefghijabcdefghijabcde", // only received the first chunk
1001 25,
1002 kHttpResponseUndefined);
1003}
1004
1005
1006
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001007namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001008class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001009 public:
1010 virtual void ReceivedBytes(HttpFetcher* fetcher,
1011 const char* bytes, int length) {
1012 ADD_FAILURE();
1013 }
1014 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
1015 EXPECT_FALSE(successful);
1016 g_main_loop_quit(loop_);
1017 }
Darin Petkov9ce452b2010-11-17 14:33:28 -08001018 virtual void TransferTerminated(HttpFetcher* fetcher) {
1019 ADD_FAILURE();
1020 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001021 GMainLoop* loop_;
1022};
1023
1024} // namespace
1025
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001026TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001027 if (this->test_.IsMock() || this->test_.IsMulti())
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001028 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001029
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001030 for (int i = 0; i < 2; i++) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001031 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1032 ASSERT_TRUE(server->started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001033
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001034 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
1035 BlockedTransferTestDelegate delegate;
1036 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001037
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001038 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001039 LibcurlHttpFetcher* curl_fetcher =
1040 dynamic_cast<LibcurlHttpFetcher*>(fetcher.get());
1041 bool is_expensive_connection = (i == 0);
1042 bool is_official_build = (i == 1);
1043 LOG(INFO) << "is_expensive_connection: " << is_expensive_connection;
1044 LOG(INFO) << "is_official_build: " << is_official_build;
1045 curl_fetcher->SetConnectionAsExpensive(is_expensive_connection);
1046 curl_fetcher->SetBuildType(is_official_build);
1047 fetcher->set_delegate(&delegate);
1048
1049 StartTransferArgs start_xfer_args =
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001050 { fetcher.get(), LocalServerUrlForPath(this->test_.SmallUrl()) };
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001051
1052 g_timeout_add(0, StartTransfer, &start_xfer_args);
1053 g_main_loop_run(loop);
1054 g_main_loop_unref(loop);
1055 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001056}
1057
rspangler@google.com49fdf182009-10-10 00:57:34 +00001058} // namespace chromeos_update_engine