blob: b2848f3f999763f6fe37bca9314ae909c186155f [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
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07005#include <netinet/in.h>
6#include <netinet/ip.h>
7#include <sys/socket.h>
rspangler@google.com49fdf182009-10-10 00:57:34 +00008#include <unistd.h>
Darin Petkov41c2fcf2010-08-25 13:14:48 -07009
adlr@google.comc98a7ed2009-12-04 18:54:03 +000010#include <string>
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070011#include <utility>
adlr@google.comc98a7ed2009-12-04 18:54:03 +000012#include <vector>
Darin Petkov41c2fcf2010-08-25 13:14:48 -070013
Andrew de los Reyes45168102010-11-22 11:13:50 -080014#include <base/logging.h>
Chris Masoned903c3b2011-05-12 15:35:46 -070015#include <base/memory/scoped_ptr.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070016#include <base/strings/string_util.h>
17#include <base/strings/stringprintf.h>
18#include <base/time/time.h>
Jay Srinivasan43488792012-06-19 00:25:31 -070019#include <chromeos/dbus/service_constants.h>
Andrew de los Reyes45168102010-11-22 11:13:50 -080020#include <glib.h>
21#include <gtest/gtest.h>
22
Gilad Arnold5bb4c902014-04-10 12:32:13 -070023#include "update_engine/fake_system_state.h"
Gilad Arnold9bedeb52011-11-17 16:19:57 -080024#include "update_engine/http_common.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000025#include "update_engine/libcurl_http_fetcher.h"
26#include "update_engine/mock_http_fetcher.h"
Andrew de los Reyes819fef22010-12-17 11:33:58 -080027#include "update_engine/multi_range_http_fetcher.h"
Andrew de los Reyes45168102010-11-22 11:13:50 -080028#include "update_engine/proxy_resolver.h"
Jay Srinivasan08fce042012-06-07 16:31:01 -070029#include "update_engine/utils.h"
rspangler@google.com49fdf182009-10-10 00:57:34 +000030
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -070031using std::make_pair;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080032using std::pair;
adlr@google.comc98a7ed2009-12-04 18:54:03 +000033using std::string;
34using std::vector;
35
Gilad Arnold8e3f1262013-01-08 14:59:54 -080036using base::TimeDelta;
Jay Srinivasan43488792012-06-19 00:25:31 -070037using testing::DoAll;
38using testing::Return;
Alex Deymoc4acdf42014-05-28 21:07:10 -070039using testing::SetArgumentPointee;
40using testing::_;
Jay Srinivasan43488792012-06-19 00:25:31 -070041
Gilad Arnold9bedeb52011-11-17 16:19:57 -080042namespace {
43
44const int kBigLength = 100000;
45const int kMediumLength = 1000;
Gilad Arnold34bf1ee2012-02-09 16:16:02 -080046const int kFlakyTruncateLength = 29000;
47const int kFlakySleepEvery = 3;
Gilad Arnold9bedeb52011-11-17 16:19:57 -080048const int kFlakySleepSecs = 10;
49
50} // namespace
51
rspangler@google.com49fdf182009-10-10 00:57:34 +000052namespace chromeos_update_engine {
53
Gilad Arnold9bedeb52011-11-17 16:19:57 -080054static const char *kUnusedUrl = "unused://unused";
55
Gilad Arnoldb6c562a2013-07-01 02:19:26 -070056static inline string LocalServerUrlForPath(in_port_t port,
57 const string& path) {
Alex Vakulenko75039d72014-03-25 12:36:28 -070058 string port_str = (port ? base::StringPrintf(":%hu", port) : "");
Gilad Arnoldb6c562a2013-07-01 02:19:26 -070059 return base::StringPrintf("http://127.0.0.1%s%s", port_str.c_str(),
60 path.c_str());
rspangler@google.com49fdf182009-10-10 00:57:34 +000061}
62
Gilad Arnold9bedeb52011-11-17 16:19:57 -080063//
64// Class hierarchy for HTTP server implementations.
65//
66
67class HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000068 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080069 // This makes it an abstract class (dirty but works).
70 virtual ~HttpServer() = 0;
71
Gilad Arnoldb6c562a2013-07-01 02:19:26 -070072 virtual in_port_t GetPort() const {
73 return 0;
74 }
75
rspangler@google.com49fdf182009-10-10 00:57:34 +000076 bool started_;
77};
78
Gilad Arnold9bedeb52011-11-17 16:19:57 -080079HttpServer::~HttpServer() {}
rspangler@google.com49fdf182009-10-10 00:57:34 +000080
Gilad Arnold9bedeb52011-11-17 16:19:57 -080081
82class NullHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000083 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -080084 NullHttpServer() {
85 started_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +000086 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000087};
88
Gilad Arnold9bedeb52011-11-17 16:19:57 -080089
90class PythonHttpServer : public HttpServer {
rspangler@google.com49fdf182009-10-10 00:57:34 +000091 public:
Gilad Arnoldb6c562a2013-07-01 02:19:26 -070092 PythonHttpServer() : pid_(-1), port_(0) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000093 started_ = false;
Gilad Arnoldb6c562a2013-07-01 02:19:26 -070094
95 // Spawn the server process.
96 gchar *argv[] = {
97 const_cast<gchar*>("./test_http_server"),
98 NULL };
99 GError *err;
100 gint server_stdout = -1;
101 if (!g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
102 NULL, NULL, &pid_, NULL, &server_stdout, NULL,
103 &err)) {
104 LOG(ERROR) << "failed to spawn http server process";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000105 return;
106 }
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700107 CHECK_GT(pid_, 0);
108 CHECK_GE(server_stdout, 0);
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700109 LOG(INFO) << "started http server with pid " << pid_;
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700110
111 // Wait for server to begin accepting connections, obtain its port.
112 char line[80];
113 const size_t listening_msg_prefix_len = strlen(kServerListeningMsgPrefix);
114 CHECK_GT(sizeof(line), listening_msg_prefix_len);
115 int line_len = read(server_stdout, line, sizeof(line) - 1);
116 if (line_len <= static_cast<int>(listening_msg_prefix_len)) {
117 if (line_len < 0) {
118 LOG(ERROR) << "error reading http server stdout: "
119 << strerror(errno);
120 } else {
121 LOG(ERROR) << "server output too short";
122 }
123 Terminate(true);
124 return;
125 }
126
127 line[line_len] = '\0';
128 CHECK_EQ(strstr(line, kServerListeningMsgPrefix), line);
129 const char* listening_port_str = line + listening_msg_prefix_len;
130 char* end_ptr;
131 long raw_port = strtol(listening_port_str, &end_ptr, 10);
132 CHECK(!*end_ptr || *end_ptr == '\n');
133 port_ = static_cast<in_port_t>(raw_port);
134 CHECK_GT(port_, 0);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700135 started_ = true;
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700136 LOG(INFO) << "server running, listening on port " << port_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700137 LOG(INFO) << "gdb attach now!";
rspangler@google.com49fdf182009-10-10 00:57:34 +0000138 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800139
rspangler@google.com49fdf182009-10-10 00:57:34 +0000140 ~PythonHttpServer() {
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700141 // If there's no process, do nothing.
142 if (pid_ == -1)
rspangler@google.com49fdf182009-10-10 00:57:34 +0000143 return;
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700144
145 // If server is responsive, request that it gracefully terminate.
146 bool do_kill = false;
147 if (started_) {
148 LOG(INFO) << "running wget to exit";
149 if (system((string("wget -t 1 --output-document=/dev/null ") +
150 LocalServerUrlForPath(port_, "/quitquitquit")).c_str())) {
151 LOG(WARNING) << "wget failed, resorting to brute force";
152 do_kill = true;
153 }
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700154 }
155
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700156 // Server not responding or wget failed, kill the process.
157 Terminate(do_kill);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000158 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800159
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700160 virtual in_port_t GetPort() const {
161 return port_;
162 }
163
164 private:
165 void Terminate(bool do_kill) {
166 ASSERT_GT(pid_, 0);
167
168 if (do_kill) {
169 LOG(INFO) << "terminating (SIGKILL) server process with pid " << pid_;
170 kill(pid_, SIGKILL);
171 }
172
173 LOG(INFO) << "waiting for http server with pid " << pid_ << " to terminate";
174 int status;
175 pid_t killed_pid = waitpid(pid_, &status, 0);
176 ASSERT_EQ(killed_pid, pid_);
177 LOG(INFO) << "http server with pid " << pid_
178 << " terminated with status " << status;
179 pid_ = -1;
180 }
181
182 static const char* kServerListeningMsgPrefix;
183
rspangler@google.com49fdf182009-10-10 00:57:34 +0000184 GPid pid_;
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700185 in_port_t port_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000186};
187
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700188const char* PythonHttpServer::kServerListeningMsgPrefix = "listening on port ";
189
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800190//
191// Class hierarchy for HTTP fetcher test wrappers.
192//
193
194class AnyHttpFetcherTest {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000195 public:
Chris Sosa77f79e82014-06-02 18:16:24 -0700196 AnyHttpFetcherTest() {}
Alex Deymoc4acdf42014-05-28 21:07:10 -0700197 virtual ~AnyHttpFetcherTest() {}
Jay Srinivasan43488792012-06-19 00:25:31 -0700198
Alex Deymo7984bf02014-04-02 20:41:57 -0700199 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) = 0;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800200 HttpFetcher* NewLargeFetcher() {
201 return NewLargeFetcher(1);
202 }
203
204 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) = 0;
205 HttpFetcher* NewSmallFetcher() {
206 return NewSmallFetcher(1);
207 }
208
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700209 virtual string BigUrl(in_port_t port) const { return kUnusedUrl; }
210 virtual string SmallUrl(in_port_t port) const { return kUnusedUrl; }
211 virtual string ErrorUrl(in_port_t port) const { return kUnusedUrl; }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800212
213 virtual bool IsMock() const = 0;
214 virtual bool IsMulti() const = 0;
215
216 virtual void IgnoreServerAborting(HttpServer* server) const {}
217
218 virtual HttpServer *CreateServer() = 0;
219
220 protected:
221 DirectProxyResolver proxy_resolver_;
Gilad Arnold5bb4c902014-04-10 12:32:13 -0700222 FakeSystemState fake_system_state_;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800223};
224
225class MockHttpFetcherTest : public AnyHttpFetcherTest {
226 public:
227 // Necessary to unhide the definition in the base class.
228 using AnyHttpFetcherTest::NewLargeFetcher;
229 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
230 vector<char> big_data(1000000);
231 CHECK(num_proxies > 0);
232 proxy_resolver_.set_num_proxies(num_proxies);
233 return new MockHttpFetcher(
234 big_data.data(),
235 big_data.size(),
236 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
237 }
238
239 // Necessary to unhide the definition in the base class.
240 using AnyHttpFetcherTest::NewSmallFetcher;
241 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
242 CHECK(num_proxies > 0);
243 proxy_resolver_.set_num_proxies(num_proxies);
244 return new MockHttpFetcher(
245 "x",
246 1,
247 reinterpret_cast<ProxyResolver*>(&proxy_resolver_));
248 }
249
250 virtual bool IsMock() const { return true; }
251 virtual bool IsMulti() const { return false; }
252
253 virtual HttpServer *CreateServer() {
254 return new NullHttpServer;
255 }
256};
257
258class LibcurlHttpFetcherTest : public AnyHttpFetcherTest {
259 public:
260 // Necessary to unhide the definition in the base class.
261 using AnyHttpFetcherTest::NewLargeFetcher;
262 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
263 CHECK(num_proxies > 0);
264 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes45168102010-11-22 11:13:50 -0800265 LibcurlHttpFetcher *ret = new
Jay Srinivasan08fce042012-06-07 16:31:01 -0700266 LibcurlHttpFetcher(reinterpret_cast<ProxyResolver*>(&proxy_resolver_),
Nam T. Nguyen7d623eb2014-05-13 16:06:28 -0700267 &fake_system_state_);
Darin Petkovb83371f2010-08-17 09:34:49 -0700268 // Speed up test execution.
269 ret->set_idle_seconds(1);
270 ret->set_retry_seconds(1);
Gilad Arnold5bb4c902014-04-10 12:32:13 -0700271 fake_system_state_.fake_hardware()->SetIsOfficialBuild(false);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000272 return ret;
273 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800274
275 // Necessary to unhide the definition in the base class.
276 using AnyHttpFetcherTest::NewSmallFetcher;
277 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
278 return NewLargeFetcher(num_proxies);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000279 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800280
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700281 virtual string BigUrl(in_port_t port) const {
282 return LocalServerUrlForPath(port,
283 base::StringPrintf("/download/%d",
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800284 kBigLength));
rspangler@google.com49fdf182009-10-10 00:57:34 +0000285 }
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700286 virtual string SmallUrl(in_port_t port) const {
287 return LocalServerUrlForPath(port, "/foo");
rspangler@google.com49fdf182009-10-10 00:57:34 +0000288 }
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700289 virtual string ErrorUrl(in_port_t port) const {
290 return LocalServerUrlForPath(port, "/error");
Gilad Arnold48085ba2011-11-16 09:36:08 -0800291 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800292
293 virtual bool IsMock() const { return false; }
294 virtual bool IsMulti() const { return false; }
295
296 virtual void IgnoreServerAborting(HttpServer* server) const {
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700297 // Nothing to do.
Andrew de los Reyes08c4e272010-04-15 14:02:17 -0700298 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800299
300 virtual HttpServer *CreateServer() {
301 return new PythonHttpServer;
302 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000303};
304
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800305class MultiRangeHttpFetcherTest : public LibcurlHttpFetcherTest {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700306 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800307 // Necessary to unhide the definition in the base class.
308 using AnyHttpFetcherTest::NewLargeFetcher;
309 virtual HttpFetcher* NewLargeFetcher(size_t num_proxies) {
310 CHECK(num_proxies > 0);
311 proxy_resolver_.set_num_proxies(num_proxies);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800312 ProxyResolver* resolver =
313 reinterpret_cast<ProxyResolver*>(&proxy_resolver_);
Gilad Arnold7c04e762012-05-23 10:54:02 -0700314 MultiRangeHttpFetcher *ret =
315 new MultiRangeHttpFetcher(
Nam T. Nguyen7d623eb2014-05-13 16:06:28 -0700316 new LibcurlHttpFetcher(resolver, &fake_system_state_));
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800317 ret->ClearRanges();
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800318 ret->AddRange(0);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700319 // Speed up test execution.
320 ret->set_idle_seconds(1);
321 ret->set_retry_seconds(1);
Gilad Arnold5bb4c902014-04-10 12:32:13 -0700322 fake_system_state_.fake_hardware()->SetIsOfficialBuild(false);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700323 return ret;
324 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800325
326 // Necessary to unhide the definition in the base class.
327 using AnyHttpFetcherTest::NewSmallFetcher;
328 virtual HttpFetcher* NewSmallFetcher(size_t num_proxies) {
329 return NewLargeFetcher(num_proxies);
330 }
331
332 virtual bool IsMulti() const { return true; }
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700333};
334
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800335
336//
337// Infrastructure for type tests of HTTP fetcher.
338// See: http://code.google.com/p/googletest/wiki/AdvancedGuide#Typed_Tests
339//
340
341// Fixture class template. We use an explicit constraint to guarantee that it
342// can only be instantiated with an AnyHttpFetcherTest type, see:
343// http://www2.research.att.com/~bs/bs_faq2.html#constraints
344template <typename T>
345class HttpFetcherTest : public ::testing::Test {
346 public:
347 T test_;
348
349 private:
350 static void TypeConstraint(T *a) {
351 AnyHttpFetcherTest *b = a;
Yunlian Jiang2dac5762013-04-12 09:53:09 -0700352 if (b == 0) // Silence compiler warning of unused variable.
353 *b = a;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800354 }
355};
356
357// Test case types list.
358typedef ::testing::Types<LibcurlHttpFetcherTest,
359 MockHttpFetcherTest,
360 MultiRangeHttpFetcherTest> HttpFetcherTestTypes;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000361TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
362
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800363
rspangler@google.com49fdf182009-10-10 00:57:34 +0000364namespace {
365class HttpFetcherTestDelegate : public HttpFetcherDelegate {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000366 public:
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800367 HttpFetcherTestDelegate() :
Gilad Arnold48085ba2011-11-16 09:36:08 -0800368 is_expect_error_(false), times_transfer_complete_called_(0),
369 times_transfer_terminated_called_(0), times_received_bytes_called_(0) {}
370
Alex Deymof9c59992014-04-02 21:16:59 -0700371 virtual void ReceivedBytes(HttpFetcher* /* fetcher */,
372 const char* /* bytes */, int /* length */) {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800373 // Update counters
374 times_received_bytes_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000375 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800376
rspangler@google.com49fdf182009-10-10 00:57:34 +0000377 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800378 if (is_expect_error_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800379 EXPECT_EQ(kHttpResponseNotFound, fetcher->http_response_code());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800380 else
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800381 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000382 g_main_loop_quit(loop_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800383
384 // Update counter
385 times_transfer_complete_called_++;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000386 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800387
Darin Petkov9ce452b2010-11-17 14:33:28 -0800388 virtual void TransferTerminated(HttpFetcher* fetcher) {
389 ADD_FAILURE();
Gilad Arnold48085ba2011-11-16 09:36:08 -0800390 times_transfer_terminated_called_++;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800391 }
Gilad Arnold48085ba2011-11-16 09:36:08 -0800392
rspangler@google.com49fdf182009-10-10 00:57:34 +0000393 GMainLoop* loop_;
Gilad Arnold48085ba2011-11-16 09:36:08 -0800394
395 // Are we expecting an error response? (default: no)
396 bool is_expect_error_;
397
398 // Counters for callback invocations.
399 int times_transfer_complete_called_;
400 int times_transfer_terminated_called_;
401 int times_received_bytes_called_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000402};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000403
404struct StartTransferArgs {
405 HttpFetcher *http_fetcher;
406 string url;
407};
408
409gboolean StartTransfer(gpointer data) {
410 StartTransferArgs *args = reinterpret_cast<StartTransferArgs*>(data);
411 args->http_fetcher->BeginTransfer(args->url);
412 return FALSE;
413}
rspangler@google.com49fdf182009-10-10 00:57:34 +0000414} // namespace {}
415
416TYPED_TEST(HttpFetcherTest, SimpleTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700417 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000418 {
419 HttpFetcherTestDelegate delegate;
420 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800421 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000422 fetcher->set_delegate(&delegate);
423
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800424 scoped_ptr<HttpServer> server(this->test_.CreateServer());
425 ASSERT_TRUE(server->started_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000426
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700427 StartTransferArgs start_xfer_args = {
428 fetcher.get(), this->test_.SmallUrl(server->GetPort())};
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000429
430 g_timeout_add(0, StartTransfer, &start_xfer_args);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000431 g_main_loop_run(loop);
432 }
433 g_main_loop_unref(loop);
434}
435
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700436TYPED_TEST(HttpFetcherTest, SimpleBigTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700437 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700438 {
439 HttpFetcherTestDelegate delegate;
440 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800441 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700442 fetcher->set_delegate(&delegate);
443
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800444 scoped_ptr<HttpServer> server(this->test_.CreateServer());
445 ASSERT_TRUE(server->started_);
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700446
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700447 StartTransferArgs start_xfer_args = {
448 fetcher.get(), this->test_.BigUrl(server->GetPort())};
Andrew de los Reyes3270f742010-07-15 22:28:14 -0700449
450 g_timeout_add(0, StartTransfer, &start_xfer_args);
451 g_main_loop_run(loop);
452 }
453 g_main_loop_unref(loop);
454}
455
Gilad Arnold48085ba2011-11-16 09:36:08 -0800456// Issue #9648: when server returns an error HTTP response, the fetcher needs to
457// terminate transfer prematurely, rather than try to process the error payload.
458TYPED_TEST(HttpFetcherTest, ErrorTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800459 if (this->test_.IsMock() || this->test_.IsMulti())
Gilad Arnold48085ba2011-11-16 09:36:08 -0800460 return;
461 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
462 {
463 HttpFetcherTestDelegate delegate;
464 delegate.loop_ = loop;
465
466 // Delegate should expect an error response.
467 delegate.is_expect_error_ = true;
468
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800469 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Gilad Arnold48085ba2011-11-16 09:36:08 -0800470 fetcher->set_delegate(&delegate);
471
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800472 scoped_ptr<HttpServer> server(this->test_.CreateServer());
473 ASSERT_TRUE(server->started_);
Gilad Arnold48085ba2011-11-16 09:36:08 -0800474
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800475 StartTransferArgs start_xfer_args = {
476 fetcher.get(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700477 this->test_.ErrorUrl(server->GetPort())
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800478 };
Gilad Arnold48085ba2011-11-16 09:36:08 -0800479
480 g_timeout_add(0, StartTransfer, &start_xfer_args);
481 g_main_loop_run(loop);
482
483 // Make sure that no bytes were received.
484 CHECK_EQ(delegate.times_received_bytes_called_, 0);
Mike Frysinger0f9547d2012-02-16 12:11:37 -0500485 CHECK_EQ(fetcher->GetBytesDownloaded(), static_cast<size_t>(0));
Gilad Arnold48085ba2011-11-16 09:36:08 -0800486
487 // Make sure that transfer completion was signaled once, and no termination
488 // was signaled.
489 CHECK_EQ(delegate.times_transfer_complete_called_, 1);
490 CHECK_EQ(delegate.times_transfer_terminated_called_, 0);
491 }
492 g_main_loop_unref(loop);
493}
494
rspangler@google.com49fdf182009-10-10 00:57:34 +0000495namespace {
496class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
497 public:
498 virtual void ReceivedBytes(HttpFetcher* fetcher,
Alex Deymof9c59992014-04-02 21:16:59 -0700499 const char* /* bytes */, int /* length */) {
rspangler@google.com49fdf182009-10-10 00:57:34 +0000500 CHECK(!paused_);
501 paused_ = true;
502 fetcher->Pause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000503 }
504 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
505 g_main_loop_quit(loop_);
506 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800507 virtual void TransferTerminated(HttpFetcher* fetcher) {
508 ADD_FAILURE();
509 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000510 void Unpause() {
511 CHECK(paused_);
512 paused_ = false;
513 fetcher_->Unpause();
rspangler@google.com49fdf182009-10-10 00:57:34 +0000514 }
515 bool paused_;
516 HttpFetcher* fetcher_;
517 GMainLoop* loop_;
518};
519
520gboolean UnpausingTimeoutCallback(gpointer data) {
521 PausingHttpFetcherTestDelegate *delegate =
522 reinterpret_cast<PausingHttpFetcherTestDelegate*>(data);
523 if (delegate->paused_)
524 delegate->Unpause();
525 return TRUE;
526}
527} // namespace {}
528
529TYPED_TEST(HttpFetcherTest, PauseTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700530 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000531 {
532 PausingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800533 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000534 delegate.paused_ = false;
535 delegate.loop_ = loop;
536 delegate.fetcher_ = fetcher.get();
537 fetcher->set_delegate(&delegate);
538
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800539 scoped_ptr<HttpServer> server(this->test_.CreateServer());
540 ASSERT_TRUE(server->started_);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800541
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800542 guint callback_id = g_timeout_add(kHttpResponseInternalServerError,
543 UnpausingTimeoutCallback, &delegate);
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700544 fetcher->BeginTransfer(this->test_.BigUrl(server->GetPort()));
rspangler@google.com49fdf182009-10-10 00:57:34 +0000545
546 g_main_loop_run(loop);
Andrew de los Reyesf3ed8e72011-02-16 10:35:46 -0800547 g_source_remove(callback_id);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000548 }
549 g_main_loop_unref(loop);
550}
551
552namespace {
553class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
554 public:
555 virtual void ReceivedBytes(HttpFetcher* fetcher,
556 const char* bytes, int length) {}
557 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800558 ADD_FAILURE(); // We should never get here
rspangler@google.com49fdf182009-10-10 00:57:34 +0000559 g_main_loop_quit(loop_);
560 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800561 virtual void TransferTerminated(HttpFetcher* fetcher) {
562 EXPECT_EQ(fetcher, fetcher_.get());
563 EXPECT_FALSE(once_);
564 EXPECT_TRUE(callback_once_);
565 callback_once_ = false;
Alex Deymoc4acdf42014-05-28 21:07:10 -0700566 // The fetcher could have a callback scheduled on the ProxyResolver that
567 // can fire after this callback. We wait until the end of the test to
568 // delete the fetcher.
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800569 }
rspangler@google.com49fdf182009-10-10 00:57:34 +0000570 void TerminateTransfer() {
571 CHECK(once_);
572 once_ = false;
573 fetcher_->TerminateTransfer();
574 }
575 void EndLoop() {
576 g_main_loop_quit(loop_);
577 }
578 bool once_;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800579 bool callback_once_;
580 scoped_ptr<HttpFetcher> fetcher_;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000581 GMainLoop* loop_;
582};
583
584gboolean AbortingTimeoutCallback(gpointer data) {
585 AbortingHttpFetcherTestDelegate *delegate =
586 reinterpret_cast<AbortingHttpFetcherTestDelegate*>(data);
587 if (delegate->once_) {
588 delegate->TerminateTransfer();
589 return TRUE;
590 } else {
591 delegate->EndLoop();
592 return FALSE;
593 }
594}
595} // namespace {}
596
597TYPED_TEST(HttpFetcherTest, AbortTest) {
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700598 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000599 {
600 AbortingHttpFetcherTestDelegate delegate;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800601 delegate.fetcher_.reset(this->test_.NewLargeFetcher());
rspangler@google.com49fdf182009-10-10 00:57:34 +0000602 delegate.once_ = true;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800603 delegate.callback_once_ = true;
rspangler@google.com49fdf182009-10-10 00:57:34 +0000604 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800605 delegate.fetcher_->set_delegate(&delegate);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000606
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800607 scoped_ptr<HttpServer> server(this->test_.CreateServer());
608 this->test_.IgnoreServerAborting(server.get());
609 ASSERT_TRUE(server->started_);
610
rspangler@google.com49fdf182009-10-10 00:57:34 +0000611 GSource* timeout_source_;
612 timeout_source_ = g_timeout_source_new(0); // ms
613 g_source_set_callback(timeout_source_, AbortingTimeoutCallback, &delegate,
614 NULL);
615 g_source_attach(timeout_source_, NULL);
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700616 delegate.fetcher_->BeginTransfer(this->test_.BigUrl(server->GetPort()));
rspangler@google.com49fdf182009-10-10 00:57:34 +0000617
618 g_main_loop_run(loop);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800619 CHECK(!delegate.once_);
620 CHECK(!delegate.callback_once_);
rspangler@google.com49fdf182009-10-10 00:57:34 +0000621 g_source_destroy(timeout_source_);
622 }
623 g_main_loop_unref(loop);
624}
625
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000626namespace {
627class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
628 public:
629 virtual void ReceivedBytes(HttpFetcher* fetcher,
630 const char* bytes, int length) {
631 data.append(bytes, length);
632 }
633 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Andrew de los Reyesfb4ad7d2010-07-19 10:43:46 -0700634 EXPECT_TRUE(successful);
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800635 EXPECT_EQ(kHttpResponsePartialContent, fetcher->http_response_code());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000636 g_main_loop_quit(loop_);
637 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800638 virtual void TransferTerminated(HttpFetcher* fetcher) {
639 ADD_FAILURE();
640 }
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000641 string data;
642 GMainLoop* loop_;
643};
644} // namespace {}
645
646TYPED_TEST(HttpFetcherTest, FlakyTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800647 if (this->test_.IsMock())
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000648 return;
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700649 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000650 {
651 FlakyHttpFetcherTestDelegate delegate;
652 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800653 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000654 fetcher->set_delegate(&delegate);
655
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800656 scoped_ptr<HttpServer> server(this->test_.CreateServer());
657 ASSERT_TRUE(server->started_);
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000658
659 StartTransferArgs start_xfer_args = {
660 fetcher.get(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700661 LocalServerUrlForPath(server->GetPort(),
Alex Vakulenko75039d72014-03-25 12:36:28 -0700662 base::StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
663 kFlakyTruncateLength,
664 kFlakySleepEvery,
665 kFlakySleepSecs))
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000666 };
667
668 g_timeout_add(0, StartTransfer, &start_xfer_args);
669 g_main_loop_run(loop);
670
671 // verify the data we get back
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800672 ASSERT_EQ(kBigLength, delegate.data.size());
673 for (int i = 0; i < kBigLength; i += 10) {
adlr@google.comc98a7ed2009-12-04 18:54:03 +0000674 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
675 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
676 }
677 }
678 g_main_loop_unref(loop);
679}
680
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700681namespace {
Chris Sosa0a364bb2014-06-10 18:18:24 -0700682// This delegate kills the server attached to it after receiving any bytes.
683// This can be used for testing what happens when you try to fetch data and
684// the server dies.
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700685class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
686 public:
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700687 FailureHttpFetcherTestDelegate(PythonHttpServer* server)
688 : loop_(NULL),
689 server_(server) {}
690
691 virtual ~FailureHttpFetcherTestDelegate() {
692 if (server_) {
693 LOG(INFO) << "Stopping server in destructor";
694 delete server_;
695 LOG(INFO) << "server stopped";
696 }
697 }
698
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700699 virtual void ReceivedBytes(HttpFetcher* fetcher,
700 const char* bytes, int length) {
701 if (server_) {
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700702 LOG(INFO) << "Stopping server in ReceivedBytes";
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700703 delete server_;
704 LOG(INFO) << "server stopped";
705 server_ = NULL;
706 }
707 }
708 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
709 EXPECT_FALSE(successful);
Chris Sosa0a364bb2014-06-10 18:18:24 -0700710 EXPECT_EQ(0, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700711 g_main_loop_quit(loop_);
712 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800713 virtual void TransferTerminated(HttpFetcher* fetcher) {
714 ADD_FAILURE();
715 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700716 GMainLoop* loop_;
717 PythonHttpServer* server_;
718};
719} // namespace {}
720
721
722TYPED_TEST(HttpFetcherTest, FailureTest) {
Chris Sosa0a364bb2014-06-10 18:18:24 -0700723 // This test ensures that a fetcher responds correctly when a server isn't
724 // available at all.
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800725 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700726 return;
727 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
728 {
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700729 FailureHttpFetcherTestDelegate delegate(NULL);
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700730 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800731 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700732 fetcher->set_delegate(&delegate);
733
734 StartTransferArgs start_xfer_args = {
735 fetcher.get(),
Chris Sosa0a364bb2014-06-10 18:18:24 -0700736 "http://host_doesnt_exist99999999",
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700737 };
738
739 g_timeout_add(0, StartTransfer, &start_xfer_args);
740 g_main_loop_run(loop);
741
742 // Exiting and testing happens in the delegate
743 }
744 g_main_loop_unref(loop);
745}
746
747TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
Chris Sosa0a364bb2014-06-10 18:18:24 -0700748 // This test starts a new http server and kills it after receiving its first
749 // set of bytes. It test whether or not our fetcher eventually gives up on
750 // retries and aborts correctly.
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800751 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700752 return;
753 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
754 {
Chris Sosa0a364bb2014-06-10 18:18:24 -0700755 PythonHttpServer* server = new PythonHttpServer();
756 int port = server->GetPort();
757 ASSERT_TRUE(server->started_);
758
759 // Handles destruction and claims ownership.
760 FailureHttpFetcherTestDelegate delegate(server);
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700761 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800762 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700763 fetcher->set_delegate(&delegate);
764
765 StartTransferArgs start_xfer_args = {
766 fetcher.get(),
Chris Sosa0a364bb2014-06-10 18:18:24 -0700767 LocalServerUrlForPath(port,
Alex Vakulenko75039d72014-03-25 12:36:28 -0700768 base::StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
769 kFlakyTruncateLength,
770 kFlakySleepEvery,
771 kFlakySleepSecs))
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700772 };
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700773 g_timeout_add(0, StartTransfer, &start_xfer_args);
774 g_main_loop_run(loop);
775
776 // Exiting and testing happens in the delegate
777 }
778 g_main_loop_unref(loop);
779}
780
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700781namespace {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800782const HttpResponseCode kRedirectCodes[] = {
783 kHttpResponseMovedPermanently, kHttpResponseFound, kHttpResponseSeeOther,
784 kHttpResponseTempRedirect
785};
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700786
787class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
788 public:
789 RedirectHttpFetcherTestDelegate(bool expected_successful)
790 : expected_successful_(expected_successful) {}
791 virtual void ReceivedBytes(HttpFetcher* fetcher,
792 const char* bytes, int length) {
793 data.append(bytes, length);
794 }
795 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
796 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700797 if (expected_successful_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800798 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
Darin Petkovcb466212010-08-26 09:40:11 -0700799 else {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800800 EXPECT_GE(fetcher->http_response_code(), kHttpResponseMovedPermanently);
801 EXPECT_LE(fetcher->http_response_code(), kHttpResponseTempRedirect);
Darin Petkovcb466212010-08-26 09:40:11 -0700802 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700803 g_main_loop_quit(loop_);
804 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800805 virtual void TransferTerminated(HttpFetcher* fetcher) {
806 ADD_FAILURE();
807 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700808 bool expected_successful_;
809 string data;
810 GMainLoop* loop_;
811};
812
813// RedirectTest takes ownership of |http_fetcher|.
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700814void RedirectTest(const HttpServer* server,
815 bool expected_successful,
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700816 const string& url,
817 HttpFetcher* http_fetcher) {
818 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700819 {
820 RedirectHttpFetcherTestDelegate delegate(expected_successful);
821 delegate.loop_ = loop;
822 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
823 fetcher->set_delegate(&delegate);
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700824
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700825 StartTransferArgs start_xfer_args =
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700826 { fetcher.get(), LocalServerUrlForPath(server->GetPort(), url) };
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700827
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700828 g_timeout_add(0, StartTransfer, &start_xfer_args);
829 g_main_loop_run(loop);
830 if (expected_successful) {
831 // verify the data we get back
832 ASSERT_EQ(kMediumLength, delegate.data.size());
833 for (int i = 0; i < kMediumLength; i += 10) {
834 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
835 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
836 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700837 }
838 }
839 g_main_loop_unref(loop);
840}
841} // namespace {}
842
843TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800844 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700845 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800846
847 scoped_ptr<HttpServer> server(this->test_.CreateServer());
848 ASSERT_TRUE(server->started_);
849
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700850 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800851 const string url = base::StringPrintf("/redirect/%d/download/%d",
852 kRedirectCodes[c],
853 kMediumLength);
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700854 RedirectTest(server.get(), true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700855 }
856}
857
858TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800859 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700860 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800861
862 scoped_ptr<HttpServer> server(this->test_.CreateServer());
863 ASSERT_TRUE(server->started_);
864
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700865 string url;
David Zeuthen34135a92013-08-06 11:16:16 -0700866 for (int r = 0; r < kDownloadMaxRedirects; r++) {
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700867 url += base::StringPrintf("/redirect/%d",
868 kRedirectCodes[r % arraysize(kRedirectCodes)]);
869 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800870 url += base::StringPrintf("/download/%d", kMediumLength);
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700871 RedirectTest(server.get(), true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700872}
873
874TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800875 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700876 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800877
878 scoped_ptr<HttpServer> server(this->test_.CreateServer());
879 ASSERT_TRUE(server->started_);
880
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700881 string url;
David Zeuthen34135a92013-08-06 11:16:16 -0700882 for (int r = 0; r < kDownloadMaxRedirects + 1; r++) {
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700883 url += base::StringPrintf("/redirect/%d",
884 kRedirectCodes[r % arraysize(kRedirectCodes)]);
885 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800886 url += base::StringPrintf("/download/%d", kMediumLength);
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700887 RedirectTest(server.get(), false, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700888}
889
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700890namespace {
891class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
892 public:
893 MultiHttpFetcherTestDelegate(int expected_response_code)
894 : expected_response_code_(expected_response_code) {}
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800895
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700896 virtual void ReceivedBytes(HttpFetcher* fetcher,
897 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800898 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700899 data.append(bytes, length);
900 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800901
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700902 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800903 EXPECT_EQ(fetcher, fetcher_.get());
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800904 EXPECT_EQ(expected_response_code_ != kHttpResponseUndefined, successful);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700905 if (expected_response_code_ != 0)
906 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800907 // Destroy the fetcher (because we're allowed to).
908 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700909 g_main_loop_quit(loop_);
910 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800911
Darin Petkov9ce452b2010-11-17 14:33:28 -0800912 virtual void TransferTerminated(HttpFetcher* fetcher) {
913 ADD_FAILURE();
914 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800915
Darin Petkov9ce452b2010-11-17 14:33:28 -0800916 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700917 int expected_response_code_;
918 string data;
919 GMainLoop* loop_;
920};
921
922void MultiTest(HttpFetcher* fetcher_in,
923 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800924 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700925 const string& expected_prefix,
926 off_t expected_size,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800927 HttpResponseCode expected_response_code) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700928 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
929 {
930 MultiHttpFetcherTestDelegate delegate(expected_response_code);
931 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800932 delegate.fetcher_.reset(fetcher_in);
Jay Srinivasan43488792012-06-19 00:25:31 -0700933
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800934 MultiRangeHttpFetcher* multi_fetcher =
935 dynamic_cast<MultiRangeHttpFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700936 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800937 multi_fetcher->ClearRanges();
938 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
939 e = ranges.end(); it != e; ++it) {
Alex Vakulenko75039d72014-03-25 12:36:28 -0700940 std::string tmp_str = base::StringPrintf("%jd+", it->first);
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800941 if (it->second > 0) {
942 base::StringAppendF(&tmp_str, "%jd", it->second);
943 multi_fetcher->AddRange(it->first, it->second);
944 } else {
945 base::StringAppendF(&tmp_str, "?");
946 multi_fetcher->AddRange(it->first);
947 }
948 LOG(INFO) << "added range: " << tmp_str;
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800949 }
Gilad Arnold5bb4c902014-04-10 12:32:13 -0700950 dynamic_cast<FakeSystemState*>(fetcher_in->GetSystemState())
Gilad Arnold1f847232014-04-07 12:07:49 -0700951 ->fake_hardware()->SetIsOfficialBuild(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800952 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700953
Darin Petkov9ce452b2010-11-17 14:33:28 -0800954 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700955
956 g_timeout_add(0, StartTransfer, &start_xfer_args);
957 g_main_loop_run(loop);
958
959 EXPECT_EQ(expected_size, delegate.data.size());
960 EXPECT_EQ(expected_prefix,
961 string(delegate.data.data(), expected_prefix.size()));
962 }
963 g_main_loop_unref(loop);
964}
965} // namespace {}
966
Darin Petkov9ce452b2010-11-17 14:33:28 -0800967TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800968 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700969 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800970
971 scoped_ptr<HttpServer> server(this->test_.CreateServer());
972 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700973
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800974 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700975 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800976 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800977 MultiTest(this->test_.NewLargeFetcher(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700978 this->test_.BigUrl(server->GetPort()),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700979 ranges,
980 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800981 kBigLength - (99 - 25),
982 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700983}
984
985TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800986 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700987 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800988
989 scoped_ptr<HttpServer> server(this->test_.CreateServer());
990 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700991
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800992 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700993 ranges.push_back(make_pair(0, 24));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800994 MultiTest(this->test_.NewLargeFetcher(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700995 this->test_.BigUrl(server->GetPort()),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700996 ranges,
997 "abcdefghijabcdefghijabcd",
998 24,
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800999 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001000}
1001
1002TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001003 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001004 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001005
1006 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1007 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001008
Andrew de los Reyes819fef22010-12-17 11:33:58 -08001009 vector<pair<off_t, off_t> > ranges;
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001010 ranges.push_back(make_pair(kBigLength - 2, 0));
1011 ranges.push_back(make_pair(kBigLength - 3, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001012 MultiTest(this->test_.NewLargeFetcher(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001013 this->test_.BigUrl(server->GetPort()),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001014 ranges,
1015 "ijhij",
1016 5,
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001017 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001018}
1019
1020TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001021 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001022 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001023
1024 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1025 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001026
Andrew de los Reyes819fef22010-12-17 11:33:58 -08001027 vector<pair<off_t, off_t> > ranges;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001028 ranges.push_back(make_pair(kBigLength - 2, 4));
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001029 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -08001030 LOG(INFO) << "i = " << i;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001031 MultiTest(this->test_.NewLargeFetcher(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001032 this->test_.BigUrl(server->GetPort()),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001033 ranges,
1034 "ij",
1035 2,
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001036 kHttpResponseUndefined);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001037 ranges.push_back(make_pair(0, 5));
1038 }
1039}
1040
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001041// Issue #18143: when a fetch of a secondary chunk out of a chain, then it
1042// should retry with other proxies listed before giving up.
1043//
1044// (1) successful recovery: The offset fetch will fail twice but succeed with
1045// the third proxy.
1046TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetRecoverableTest) {
1047 if (!this->test_.IsMulti())
1048 return;
1049
1050 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1051 ASSERT_TRUE(server->started_);
1052
1053 vector<pair<off_t, off_t> > ranges;
1054 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001055 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001056 MultiTest(this->test_.NewLargeFetcher(3),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001057 LocalServerUrlForPath(server->GetPort(),
1058 base::StringPrintf("/error-if-offset/%d/2",
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001059 kBigLength)),
1060 ranges,
1061 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
1062 kBigLength - (99 - 25),
1063 kHttpResponsePartialContent);
1064}
1065
1066// (2) unsuccessful recovery: The offset fetch will fail repeatedly. The
1067// fetcher will signal a (failed) completed transfer to the delegate.
1068TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetUnrecoverableTest) {
1069 if (!this->test_.IsMulti())
1070 return;
1071
1072 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1073 ASSERT_TRUE(server->started_);
1074
1075 vector<pair<off_t, off_t> > ranges;
1076 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001077 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001078 MultiTest(this->test_.NewLargeFetcher(2),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001079 LocalServerUrlForPath(server->GetPort(),
1080 base::StringPrintf("/error-if-offset/%d/3",
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001081 kBigLength)),
1082 ranges,
1083 "abcdefghijabcdefghijabcde", // only received the first chunk
1084 25,
1085 kHttpResponseUndefined);
1086}
1087
1088
1089
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001090namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001091class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001092 public:
1093 virtual void ReceivedBytes(HttpFetcher* fetcher,
1094 const char* bytes, int length) {
1095 ADD_FAILURE();
1096 }
1097 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
1098 EXPECT_FALSE(successful);
1099 g_main_loop_quit(loop_);
1100 }
Darin Petkov9ce452b2010-11-17 14:33:28 -08001101 virtual void TransferTerminated(HttpFetcher* fetcher) {
1102 ADD_FAILURE();
1103 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001104 GMainLoop* loop_;
1105};
1106
1107} // namespace
1108
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001109TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001110 if (this->test_.IsMock() || this->test_.IsMulti())
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001111 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001112
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001113 for (int i = 0; i < 2; i++) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001114 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1115 ASSERT_TRUE(server->started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001116
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001117 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001118 {
1119 BlockedTransferTestDelegate delegate;
1120 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001121
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001122 bool is_allowed = (i != 0);
1123 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Jay Srinivasan43488792012-06-19 00:25:31 -07001124
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001125 bool is_official_build = (i == 1);
1126 LOG(INFO) << "is_update_allowed_over_connection: " << is_allowed;
1127 LOG(INFO) << "is_official_build: " << is_official_build;
Gilad Arnold5bb4c902014-04-10 12:32:13 -07001128 // NewLargeFetcher creates the HttpFetcher* with a FakeSystemState.
1129 dynamic_cast<FakeSystemState*>(fetcher->GetSystemState())
Gilad Arnold1f847232014-04-07 12:07:49 -07001130 ->fake_hardware()->SetIsOfficialBuild(is_official_build);
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001131 fetcher->set_delegate(&delegate);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001132
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001133 StartTransferArgs start_xfer_args =
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001134 {fetcher.get(),
1135 LocalServerUrlForPath(server->GetPort(),
1136 this->test_.SmallUrl(server->GetPort()))};
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001137
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001138 g_timeout_add(0, StartTransfer, &start_xfer_args);
1139 g_main_loop_run(loop);
1140 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001141 g_main_loop_unref(loop);
1142 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001143}
1144
rspangler@google.com49fdf182009-10-10 00:57:34 +00001145} // namespace chromeos_update_engine