blob: 33920984128d6edf11cdd6008cdbb556e8bfa517 [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 {
682class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
683 public:
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700684 FailureHttpFetcherTestDelegate(PythonHttpServer* server)
685 : loop_(NULL),
686 server_(server) {}
687
688 virtual ~FailureHttpFetcherTestDelegate() {
689 if (server_) {
690 LOG(INFO) << "Stopping server in destructor";
691 delete server_;
692 LOG(INFO) << "server stopped";
693 }
694 }
695
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700696 virtual void ReceivedBytes(HttpFetcher* fetcher,
697 const char* bytes, int length) {
698 if (server_) {
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700699 LOG(INFO) << "Stopping server in ReceivedBytes";
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700700 delete server_;
701 LOG(INFO) << "server stopped";
702 server_ = NULL;
703 }
704 }
705 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
706 EXPECT_FALSE(successful);
Chris Sosa77f79e82014-06-02 18:16:24 -0700707 EXPECT_EQ(404, fetcher->http_response_code());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700708 g_main_loop_quit(loop_);
709 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800710 virtual void TransferTerminated(HttpFetcher* fetcher) {
711 ADD_FAILURE();
712 }
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700713 GMainLoop* loop_;
714 PythonHttpServer* server_;
715};
716} // namespace {}
717
718
719TYPED_TEST(HttpFetcherTest, FailureTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800720 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700721 return;
722 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
723 {
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700724 FailureHttpFetcherTestDelegate delegate(NULL);
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700725 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800726 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700727 fetcher->set_delegate(&delegate);
728
729 StartTransferArgs start_xfer_args = {
730 fetcher.get(),
Chris Sosa77f79e82014-06-02 18:16:24 -0700731 this->test_.SmallUrl(0)
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700732 };
733
734 g_timeout_add(0, StartTransfer, &start_xfer_args);
735 g_main_loop_run(loop);
736
737 // Exiting and testing happens in the delegate
738 }
739 g_main_loop_unref(loop);
740}
741
742TYPED_TEST(HttpFetcherTest, ServerDiesTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800743 if (this->test_.IsMock())
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700744 return;
745 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
746 {
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700747 FailureHttpFetcherTestDelegate delegate(new PythonHttpServer);
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700748 delegate.loop_ = loop;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800749 scoped_ptr<HttpFetcher> fetcher(this->test_.NewSmallFetcher());
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700750 fetcher->set_delegate(&delegate);
751
752 StartTransferArgs start_xfer_args = {
753 fetcher.get(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700754 LocalServerUrlForPath(0,
Alex Vakulenko75039d72014-03-25 12:36:28 -0700755 base::StringPrintf("/flaky/%d/%d/%d/%d", kBigLength,
756 kFlakyTruncateLength,
757 kFlakySleepEvery,
758 kFlakySleepSecs))
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700759 };
Andrew de los Reyes9bbd1872010-07-16 14:52:29 -0700760 g_timeout_add(0, StartTransfer, &start_xfer_args);
761 g_main_loop_run(loop);
762
763 // Exiting and testing happens in the delegate
764 }
765 g_main_loop_unref(loop);
766}
767
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700768namespace {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800769const HttpResponseCode kRedirectCodes[] = {
770 kHttpResponseMovedPermanently, kHttpResponseFound, kHttpResponseSeeOther,
771 kHttpResponseTempRedirect
772};
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700773
774class RedirectHttpFetcherTestDelegate : public HttpFetcherDelegate {
775 public:
776 RedirectHttpFetcherTestDelegate(bool expected_successful)
777 : expected_successful_(expected_successful) {}
778 virtual void ReceivedBytes(HttpFetcher* fetcher,
779 const char* bytes, int length) {
780 data.append(bytes, length);
781 }
782 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
783 EXPECT_EQ(expected_successful_, successful);
Darin Petkovcb466212010-08-26 09:40:11 -0700784 if (expected_successful_)
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800785 EXPECT_EQ(kHttpResponseOk, fetcher->http_response_code());
Darin Petkovcb466212010-08-26 09:40:11 -0700786 else {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800787 EXPECT_GE(fetcher->http_response_code(), kHttpResponseMovedPermanently);
788 EXPECT_LE(fetcher->http_response_code(), kHttpResponseTempRedirect);
Darin Petkovcb466212010-08-26 09:40:11 -0700789 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700790 g_main_loop_quit(loop_);
791 }
Darin Petkov9ce452b2010-11-17 14:33:28 -0800792 virtual void TransferTerminated(HttpFetcher* fetcher) {
793 ADD_FAILURE();
794 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700795 bool expected_successful_;
796 string data;
797 GMainLoop* loop_;
798};
799
800// RedirectTest takes ownership of |http_fetcher|.
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700801void RedirectTest(const HttpServer* server,
802 bool expected_successful,
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700803 const string& url,
804 HttpFetcher* http_fetcher) {
805 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700806 {
807 RedirectHttpFetcherTestDelegate delegate(expected_successful);
808 delegate.loop_ = loop;
809 scoped_ptr<HttpFetcher> fetcher(http_fetcher);
810 fetcher->set_delegate(&delegate);
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700811
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700812 StartTransferArgs start_xfer_args =
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700813 { fetcher.get(), LocalServerUrlForPath(server->GetPort(), url) };
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700814
Jay Srinivasan135a58b2012-07-13 12:46:49 -0700815 g_timeout_add(0, StartTransfer, &start_xfer_args);
816 g_main_loop_run(loop);
817 if (expected_successful) {
818 // verify the data we get back
819 ASSERT_EQ(kMediumLength, delegate.data.size());
820 for (int i = 0; i < kMediumLength; i += 10) {
821 // Assert so that we don't flood the screen w/ EXPECT errors on failure.
822 ASSERT_EQ(delegate.data.substr(i, 10), "abcdefghij");
823 }
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700824 }
825 }
826 g_main_loop_unref(loop);
827}
828} // namespace {}
829
830TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800831 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700832 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800833
834 scoped_ptr<HttpServer> server(this->test_.CreateServer());
835 ASSERT_TRUE(server->started_);
836
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700837 for (size_t c = 0; c < arraysize(kRedirectCodes); ++c) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800838 const string url = base::StringPrintf("/redirect/%d/download/%d",
839 kRedirectCodes[c],
840 kMediumLength);
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700841 RedirectTest(server.get(), true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700842 }
843}
844
845TYPED_TEST(HttpFetcherTest, MaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800846 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700847 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800848
849 scoped_ptr<HttpServer> server(this->test_.CreateServer());
850 ASSERT_TRUE(server->started_);
851
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700852 string url;
David Zeuthen34135a92013-08-06 11:16:16 -0700853 for (int r = 0; r < kDownloadMaxRedirects; r++) {
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700854 url += base::StringPrintf("/redirect/%d",
855 kRedirectCodes[r % arraysize(kRedirectCodes)]);
856 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800857 url += base::StringPrintf("/download/%d", kMediumLength);
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700858 RedirectTest(server.get(), true, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700859}
860
861TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800862 if (this->test_.IsMock())
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700863 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800864
865 scoped_ptr<HttpServer> server(this->test_.CreateServer());
866 ASSERT_TRUE(server->started_);
867
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700868 string url;
David Zeuthen34135a92013-08-06 11:16:16 -0700869 for (int r = 0; r < kDownloadMaxRedirects + 1; r++) {
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700870 url += base::StringPrintf("/redirect/%d",
871 kRedirectCodes[r % arraysize(kRedirectCodes)]);
872 }
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800873 url += base::StringPrintf("/download/%d", kMediumLength);
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700874 RedirectTest(server.get(), false, url, this->test_.NewLargeFetcher());
Darin Petkov41c2fcf2010-08-25 13:14:48 -0700875}
876
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700877namespace {
878class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
879 public:
880 MultiHttpFetcherTestDelegate(int expected_response_code)
881 : expected_response_code_(expected_response_code) {}
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800882
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700883 virtual void ReceivedBytes(HttpFetcher* fetcher,
884 const char* bytes, int length) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800885 EXPECT_EQ(fetcher, fetcher_.get());
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700886 data.append(bytes, length);
887 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800888
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700889 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
Darin Petkov9ce452b2010-11-17 14:33:28 -0800890 EXPECT_EQ(fetcher, fetcher_.get());
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800891 EXPECT_EQ(expected_response_code_ != kHttpResponseUndefined, successful);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700892 if (expected_response_code_ != 0)
893 EXPECT_EQ(expected_response_code_, fetcher->http_response_code());
Darin Petkov9ce452b2010-11-17 14:33:28 -0800894 // Destroy the fetcher (because we're allowed to).
895 fetcher_.reset(NULL);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700896 g_main_loop_quit(loop_);
897 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800898
Darin Petkov9ce452b2010-11-17 14:33:28 -0800899 virtual void TransferTerminated(HttpFetcher* fetcher) {
900 ADD_FAILURE();
901 }
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800902
Darin Petkov9ce452b2010-11-17 14:33:28 -0800903 scoped_ptr<HttpFetcher> fetcher_;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700904 int expected_response_code_;
905 string data;
906 GMainLoop* loop_;
907};
908
909void MultiTest(HttpFetcher* fetcher_in,
910 const string& url,
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800911 const vector<pair<off_t, off_t> >& ranges,
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700912 const string& expected_prefix,
913 off_t expected_size,
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800914 HttpResponseCode expected_response_code) {
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700915 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
916 {
917 MultiHttpFetcherTestDelegate delegate(expected_response_code);
918 delegate.loop_ = loop;
Darin Petkov9ce452b2010-11-17 14:33:28 -0800919 delegate.fetcher_.reset(fetcher_in);
Jay Srinivasan43488792012-06-19 00:25:31 -0700920
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800921 MultiRangeHttpFetcher* multi_fetcher =
922 dynamic_cast<MultiRangeHttpFetcher*>(fetcher_in);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700923 ASSERT_TRUE(multi_fetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800924 multi_fetcher->ClearRanges();
925 for (vector<pair<off_t, off_t> >::const_iterator it = ranges.begin(),
926 e = ranges.end(); it != e; ++it) {
Alex Vakulenko75039d72014-03-25 12:36:28 -0700927 std::string tmp_str = base::StringPrintf("%jd+", it->first);
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800928 if (it->second > 0) {
929 base::StringAppendF(&tmp_str, "%jd", it->second);
930 multi_fetcher->AddRange(it->first, it->second);
931 } else {
932 base::StringAppendF(&tmp_str, "?");
933 multi_fetcher->AddRange(it->first);
934 }
935 LOG(INFO) << "added range: " << tmp_str;
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800936 }
Gilad Arnold5bb4c902014-04-10 12:32:13 -0700937 dynamic_cast<FakeSystemState*>(fetcher_in->GetSystemState())
Gilad Arnold1f847232014-04-07 12:07:49 -0700938 ->fake_hardware()->SetIsOfficialBuild(false);
Darin Petkov9ce452b2010-11-17 14:33:28 -0800939 multi_fetcher->set_delegate(&delegate);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700940
Darin Petkov9ce452b2010-11-17 14:33:28 -0800941 StartTransferArgs start_xfer_args = {multi_fetcher, url};
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700942
943 g_timeout_add(0, StartTransfer, &start_xfer_args);
944 g_main_loop_run(loop);
945
946 EXPECT_EQ(expected_size, delegate.data.size());
947 EXPECT_EQ(expected_prefix,
948 string(delegate.data.data(), expected_prefix.size()));
949 }
950 g_main_loop_unref(loop);
951}
952} // namespace {}
953
Darin Petkov9ce452b2010-11-17 14:33:28 -0800954TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800955 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700956 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800957
958 scoped_ptr<HttpServer> server(this->test_.CreateServer());
959 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700960
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800961 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700962 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800963 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800964 MultiTest(this->test_.NewLargeFetcher(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700965 this->test_.BigUrl(server->GetPort()),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700966 ranges,
967 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800968 kBigLength - (99 - 25),
969 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700970}
971
972TYPED_TEST(HttpFetcherTest, MultiHttpFetcherLengthLimitTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800973 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700974 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800975
976 scoped_ptr<HttpServer> server(this->test_.CreateServer());
977 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700978
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800979 vector<pair<off_t, off_t> > ranges;
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700980 ranges.push_back(make_pair(0, 24));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800981 MultiTest(this->test_.NewLargeFetcher(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -0700982 this->test_.BigUrl(server->GetPort()),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700983 ranges,
984 "abcdefghijabcdefghijabcd",
985 24,
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800986 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700987}
988
989TYPED_TEST(HttpFetcherTest, MultiHttpFetcherMultiEndTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800990 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700991 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800992
993 scoped_ptr<HttpServer> server(this->test_.CreateServer());
994 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -0700995
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800996 vector<pair<off_t, off_t> > ranges;
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800997 ranges.push_back(make_pair(kBigLength - 2, 0));
998 ranges.push_back(make_pair(kBigLength - 3, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800999 MultiTest(this->test_.NewLargeFetcher(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001000 this->test_.BigUrl(server->GetPort()),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001001 ranges,
1002 "ijhij",
1003 5,
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001004 kHttpResponsePartialContent);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001005}
1006
1007TYPED_TEST(HttpFetcherTest, MultiHttpFetcherInsufficientTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001008 if (!this->test_.IsMulti())
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001009 return;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001010
1011 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1012 ASSERT_TRUE(server->started_);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001013
Andrew de los Reyes819fef22010-12-17 11:33:58 -08001014 vector<pair<off_t, off_t> > ranges;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001015 ranges.push_back(make_pair(kBigLength - 2, 4));
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001016 for (int i = 0; i < 2; ++i) {
Andrew de los Reyes819fef22010-12-17 11:33:58 -08001017 LOG(INFO) << "i = " << i;
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001018 MultiTest(this->test_.NewLargeFetcher(),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001019 this->test_.BigUrl(server->GetPort()),
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001020 ranges,
1021 "ij",
1022 2,
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001023 kHttpResponseUndefined);
Andrew de los Reyes3fd5d302010-10-07 20:07:18 -07001024 ranges.push_back(make_pair(0, 5));
1025 }
1026}
1027
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001028// Issue #18143: when a fetch of a secondary chunk out of a chain, then it
1029// should retry with other proxies listed before giving up.
1030//
1031// (1) successful recovery: The offset fetch will fail twice but succeed with
1032// the third proxy.
1033TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetRecoverableTest) {
1034 if (!this->test_.IsMulti())
1035 return;
1036
1037 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1038 ASSERT_TRUE(server->started_);
1039
1040 vector<pair<off_t, off_t> > ranges;
1041 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001042 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001043 MultiTest(this->test_.NewLargeFetcher(3),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001044 LocalServerUrlForPath(server->GetPort(),
1045 base::StringPrintf("/error-if-offset/%d/2",
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001046 kBigLength)),
1047 ranges,
1048 "abcdefghijabcdefghijabcdejabcdefghijabcdef",
1049 kBigLength - (99 - 25),
1050 kHttpResponsePartialContent);
1051}
1052
1053// (2) unsuccessful recovery: The offset fetch will fail repeatedly. The
1054// fetcher will signal a (failed) completed transfer to the delegate.
1055TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetUnrecoverableTest) {
1056 if (!this->test_.IsMulti())
1057 return;
1058
1059 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1060 ASSERT_TRUE(server->started_);
1061
1062 vector<pair<off_t, off_t> > ranges;
1063 ranges.push_back(make_pair(0, 25));
Gilad Arnolde4ad2502011-12-29 17:08:54 -08001064 ranges.push_back(make_pair(99, 0));
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001065 MultiTest(this->test_.NewLargeFetcher(2),
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001066 LocalServerUrlForPath(server->GetPort(),
1067 base::StringPrintf("/error-if-offset/%d/3",
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001068 kBigLength)),
1069 ranges,
1070 "abcdefghijabcdefghijabcde", // only received the first chunk
1071 25,
1072 kHttpResponseUndefined);
1073}
1074
1075
1076
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001077namespace {
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001078class BlockedTransferTestDelegate : public HttpFetcherDelegate {
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001079 public:
1080 virtual void ReceivedBytes(HttpFetcher* fetcher,
1081 const char* bytes, int length) {
1082 ADD_FAILURE();
1083 }
1084 virtual void TransferComplete(HttpFetcher* fetcher, bool successful) {
1085 EXPECT_FALSE(successful);
1086 g_main_loop_quit(loop_);
1087 }
Darin Petkov9ce452b2010-11-17 14:33:28 -08001088 virtual void TransferTerminated(HttpFetcher* fetcher) {
1089 ADD_FAILURE();
1090 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001091 GMainLoop* loop_;
1092};
1093
1094} // namespace
1095
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001096TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001097 if (this->test_.IsMock() || this->test_.IsMulti())
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001098 return;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001099
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001100 for (int i = 0; i < 2; i++) {
Gilad Arnold9bedeb52011-11-17 16:19:57 -08001101 scoped_ptr<HttpServer> server(this->test_.CreateServer());
1102 ASSERT_TRUE(server->started_);
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001103
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001104 GMainLoop* loop = g_main_loop_new(g_main_context_default(), FALSE);
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001105 {
1106 BlockedTransferTestDelegate delegate;
1107 delegate.loop_ = loop;
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001108
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001109 bool is_allowed = (i != 0);
1110 scoped_ptr<HttpFetcher> fetcher(this->test_.NewLargeFetcher());
Jay Srinivasan43488792012-06-19 00:25:31 -07001111
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001112 bool is_official_build = (i == 1);
1113 LOG(INFO) << "is_update_allowed_over_connection: " << is_allowed;
1114 LOG(INFO) << "is_official_build: " << is_official_build;
Gilad Arnold5bb4c902014-04-10 12:32:13 -07001115 // NewLargeFetcher creates the HttpFetcher* with a FakeSystemState.
1116 dynamic_cast<FakeSystemState*>(fetcher->GetSystemState())
Gilad Arnold1f847232014-04-07 12:07:49 -07001117 ->fake_hardware()->SetIsOfficialBuild(is_official_build);
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001118 fetcher->set_delegate(&delegate);
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001119
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001120 StartTransferArgs start_xfer_args =
Gilad Arnoldb6c562a2013-07-01 02:19:26 -07001121 {fetcher.get(),
1122 LocalServerUrlForPath(server->GetPort(),
1123 this->test_.SmallUrl(server->GetPort()))};
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001124
Jay Srinivasan135a58b2012-07-13 12:46:49 -07001125 g_timeout_add(0, StartTransfer, &start_xfer_args);
1126 g_main_loop_run(loop);
1127 }
Darin Petkovfc7a0ce2010-10-25 10:38:37 -07001128 g_main_loop_unref(loop);
1129 }
Andrew de los Reyesd57d1472010-10-21 13:34:08 -07001130}
1131
rspangler@google.com49fdf182009-10-10 00:57:34 +00001132} // namespace chromeos_update_engine