Avoid crashing when going back/forward to debug URLs on a sad WebUI tab.
[chromium-blink-merge.git] / chrome / service / cloud_print / cloud_print_url_fetcher_unittest.cc
blob7d7c657a50895147adb04b17279140ff3ab95649
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/location.h"
7 #include "base/memory/ref_counted.h"
8 #include "base/single_thread_task_runner.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "base/threading/thread.h"
12 #include "base/values.h"
13 #include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
14 #include "chrome/service/service_process.h"
15 #include "net/test/spawned_test_server/spawned_test_server.h"
16 #include "net/url_request/url_request_context_getter.h"
17 #include "net/url_request/url_request_status.h"
18 #include "net/url_request/url_request_test_util.h"
19 #include "net/url_request/url_request_throttler_manager.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "url/gurl.h"
23 using base::Time;
24 using base::TimeDelta;
26 namespace cloud_print {
28 const base::FilePath::CharType kDocRoot[] =
29 FILE_PATH_LITERAL("chrome/test/data");
31 int g_request_context_getter_instances = 0;
32 class TrackingTestURLRequestContextGetter
33 : public net::TestURLRequestContextGetter {
34 public:
35 explicit TrackingTestURLRequestContextGetter(
36 base::SingleThreadTaskRunner* io_task_runner,
37 net::URLRequestThrottlerManager* throttler_manager)
38 : TestURLRequestContextGetter(io_task_runner),
39 throttler_manager_(throttler_manager) {
40 g_request_context_getter_instances++;
43 net::TestURLRequestContext* GetURLRequestContext() override {
44 if (!context_.get()) {
45 context_.reset(new net::TestURLRequestContext(true));
46 context_->set_throttler_manager(throttler_manager_);
47 context_->Init();
49 return context_.get();
52 protected:
53 ~TrackingTestURLRequestContextGetter() override {
54 g_request_context_getter_instances--;
57 private:
58 // Not owned here.
59 net::URLRequestThrottlerManager* throttler_manager_;
60 scoped_ptr<net::TestURLRequestContext> context_;
63 class TestCloudPrintURLFetcher : public CloudPrintURLFetcher {
64 public:
65 explicit TestCloudPrintURLFetcher(
66 base::SingleThreadTaskRunner* io_task_runner)
67 : io_task_runner_(io_task_runner) {}
69 net::URLRequestContextGetter* GetRequestContextGetter() override {
70 return new TrackingTestURLRequestContextGetter(io_task_runner_.get(),
71 throttler_manager());
74 net::URLRequestThrottlerManager* throttler_manager() {
75 return &throttler_manager_;
78 private:
79 ~TestCloudPrintURLFetcher() override {}
81 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
83 // We set this as the throttler manager for the
84 // TestURLRequestContext we create.
85 net::URLRequestThrottlerManager throttler_manager_;
88 class CloudPrintURLFetcherTest : public testing::Test,
89 public CloudPrintURLFetcherDelegate {
90 public:
91 CloudPrintURLFetcherTest() : max_retries_(0), fetcher_(NULL) { }
93 // Creates a URLFetcher, using the program's main thread to do IO.
94 virtual void CreateFetcher(const GURL& url, int max_retries);
96 // CloudPrintURLFetcher::Delegate
97 CloudPrintURLFetcher::ResponseAction HandleRawResponse(
98 const net::URLFetcher* source,
99 const GURL& url,
100 const net::URLRequestStatus& status,
101 int response_code,
102 const net::ResponseCookies& cookies,
103 const std::string& data) override;
105 CloudPrintURLFetcher::ResponseAction OnRequestAuthError() override {
106 ADD_FAILURE();
107 return CloudPrintURLFetcher::STOP_PROCESSING;
110 std::string GetAuthHeader() override { return std::string(); }
112 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner() {
113 return io_task_runner_;
116 protected:
117 void SetUp() override {
118 testing::Test::SetUp();
120 io_task_runner_ = base::ThreadTaskRunnerHandle::Get();
123 void TearDown() override {
124 fetcher_ = NULL;
125 // Deleting the fetcher causes a task to be posted to the IO thread to
126 // release references to the URLRequestContextGetter. We need to run all
127 // pending tasks to execute that (this is the IO thread).
128 base::MessageLoop::current()->RunUntilIdle();
129 EXPECT_EQ(0, g_request_context_getter_instances);
132 // URLFetcher is designed to run on the main UI thread, but in our tests
133 // we assume that the current thread is the IO thread where the URLFetcher
134 // dispatches its requests to. When we wish to simulate being used from
135 // a UI thread, we dispatch a worker thread to do so.
136 base::MessageLoopForIO io_loop_;
137 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
138 int max_retries_;
139 Time start_time_;
140 scoped_refptr<TestCloudPrintURLFetcher> fetcher_;
143 class CloudPrintURLFetcherBasicTest : public CloudPrintURLFetcherTest {
144 public:
145 CloudPrintURLFetcherBasicTest()
146 : handle_raw_response_(false), handle_raw_data_(false) { }
147 // CloudPrintURLFetcher::Delegate
148 CloudPrintURLFetcher::ResponseAction HandleRawResponse(
149 const net::URLFetcher* source,
150 const GURL& url,
151 const net::URLRequestStatus& status,
152 int response_code,
153 const net::ResponseCookies& cookies,
154 const std::string& data) override;
156 CloudPrintURLFetcher::ResponseAction HandleRawData(
157 const net::URLFetcher* source,
158 const GURL& url,
159 const std::string& data) override;
161 CloudPrintURLFetcher::ResponseAction HandleJSONData(
162 const net::URLFetcher* source,
163 const GURL& url,
164 base::DictionaryValue* json_data,
165 bool succeeded) override;
167 void SetHandleRawResponse(bool handle_raw_response) {
168 handle_raw_response_ = handle_raw_response;
170 void SetHandleRawData(bool handle_raw_data) {
171 handle_raw_data_ = handle_raw_data;
173 private:
174 bool handle_raw_response_;
175 bool handle_raw_data_;
178 // Version of CloudPrintURLFetcherTest that tests overload protection.
179 class CloudPrintURLFetcherOverloadTest : public CloudPrintURLFetcherTest {
180 public:
181 CloudPrintURLFetcherOverloadTest() : response_count_(0) {
184 // CloudPrintURLFetcher::Delegate
185 CloudPrintURLFetcher::ResponseAction HandleRawData(
186 const net::URLFetcher* source,
187 const GURL& url,
188 const std::string& data) override;
190 private:
191 int response_count_;
194 // Version of CloudPrintURLFetcherTest that tests backoff protection.
195 class CloudPrintURLFetcherRetryBackoffTest : public CloudPrintURLFetcherTest {
196 public:
197 CloudPrintURLFetcherRetryBackoffTest() : response_count_(0) {
200 // CloudPrintURLFetcher::Delegate
201 CloudPrintURLFetcher::ResponseAction HandleRawData(
202 const net::URLFetcher* source,
203 const GURL& url,
204 const std::string& data) override;
206 void OnRequestGiveUp() override;
208 private:
209 int response_count_;
213 void CloudPrintURLFetcherTest::CreateFetcher(const GURL& url, int max_retries) {
214 fetcher_ = new TestCloudPrintURLFetcher(io_task_runner().get());
216 // Registers an entry for test url. It only allows 3 requests to be sent
217 // in 200 milliseconds.
218 scoped_refptr<net::URLRequestThrottlerEntry>
219 entry(new net::URLRequestThrottlerEntry(
220 fetcher_->throttler_manager(), std::string(), 200, 3, 1, 2.0, 0.0, 256));
221 fetcher_->throttler_manager()->OverrideEntryForTests(url, entry.get());
223 max_retries_ = max_retries;
224 start_time_ = Time::Now();
225 fetcher_->StartGetRequest(CloudPrintURLFetcher::REQUEST_MAX, url, this,
226 max_retries_, std::string());
229 CloudPrintURLFetcher::ResponseAction
230 CloudPrintURLFetcherTest::HandleRawResponse(
231 const net::URLFetcher* source,
232 const GURL& url,
233 const net::URLRequestStatus& status,
234 int response_code,
235 const net::ResponseCookies& cookies,
236 const std::string& data) {
237 EXPECT_TRUE(status.is_success());
238 EXPECT_EQ(200, response_code); // HTTP OK
239 EXPECT_FALSE(data.empty());
240 return CloudPrintURLFetcher::CONTINUE_PROCESSING;
243 CloudPrintURLFetcher::ResponseAction
244 CloudPrintURLFetcherBasicTest::HandleRawResponse(
245 const net::URLFetcher* source,
246 const GURL& url,
247 const net::URLRequestStatus& status,
248 int response_code,
249 const net::ResponseCookies& cookies,
250 const std::string& data) {
251 EXPECT_TRUE(status.is_success());
252 EXPECT_EQ(200, response_code); // HTTP OK
253 EXPECT_FALSE(data.empty());
255 if (handle_raw_response_) {
256 // If the current message loop is not the IO loop, it will be shut down when
257 // the main loop returns and this thread subsequently goes out of scope.
258 io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
259 return CloudPrintURLFetcher::STOP_PROCESSING;
261 return CloudPrintURLFetcher::CONTINUE_PROCESSING;
264 CloudPrintURLFetcher::ResponseAction
265 CloudPrintURLFetcherBasicTest::HandleRawData(
266 const net::URLFetcher* source,
267 const GURL& url,
268 const std::string& data) {
269 // We should never get here if we returned true in HandleRawResponse
270 EXPECT_FALSE(handle_raw_response_);
271 if (handle_raw_data_) {
272 io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
273 return CloudPrintURLFetcher::STOP_PROCESSING;
275 return CloudPrintURLFetcher::CONTINUE_PROCESSING;
278 CloudPrintURLFetcher::ResponseAction
279 CloudPrintURLFetcherBasicTest::HandleJSONData(
280 const net::URLFetcher* source,
281 const GURL& url,
282 base::DictionaryValue* json_data,
283 bool succeeded) {
284 // We should never get here if we returned true in one of the above methods.
285 EXPECT_FALSE(handle_raw_response_);
286 EXPECT_FALSE(handle_raw_data_);
287 io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
288 return CloudPrintURLFetcher::STOP_PROCESSING;
291 CloudPrintURLFetcher::ResponseAction
292 CloudPrintURLFetcherOverloadTest::HandleRawData(
293 const net::URLFetcher* source,
294 const GURL& url,
295 const std::string& data) {
296 const TimeDelta one_second = TimeDelta::FromMilliseconds(1000);
297 response_count_++;
298 if (response_count_ < 20) {
299 fetcher_->StartGetRequest(CloudPrintURLFetcher::REQUEST_MAX, url, this,
300 max_retries_, std::string());
301 } else {
302 // We have already sent 20 requests continuously. And we expect that
303 // it takes more than 1 second due to the overload protection settings.
304 EXPECT_TRUE(Time::Now() - start_time_ >= one_second);
305 io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
307 return CloudPrintURLFetcher::STOP_PROCESSING;
310 CloudPrintURLFetcher::ResponseAction
311 CloudPrintURLFetcherRetryBackoffTest::HandleRawData(
312 const net::URLFetcher* source,
313 const GURL& url,
314 const std::string& data) {
315 response_count_++;
316 // First attempt + 11 retries = 12 total responses.
317 EXPECT_LE(response_count_, 12);
318 return CloudPrintURLFetcher::RETRY_REQUEST;
321 void CloudPrintURLFetcherRetryBackoffTest::OnRequestGiveUp() {
322 // It takes more than 200 ms to finish all 11 requests.
323 EXPECT_TRUE(Time::Now() - start_time_ >= TimeDelta::FromMilliseconds(200));
324 io_task_runner()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
327 TEST_F(CloudPrintURLFetcherBasicTest, HandleRawResponse) {
328 net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTP,
329 net::SpawnedTestServer::kLocalhost,
330 base::FilePath(kDocRoot));
331 ASSERT_TRUE(test_server.Start());
332 SetHandleRawResponse(true);
334 CreateFetcher(test_server.GetURL("echo"), 0);
335 base::MessageLoop::current()->Run();
338 TEST_F(CloudPrintURLFetcherBasicTest, HandleRawData) {
339 net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTP,
340 net::SpawnedTestServer::kLocalhost,
341 base::FilePath(kDocRoot));
342 ASSERT_TRUE(test_server.Start());
344 SetHandleRawData(true);
345 CreateFetcher(test_server.GetURL("echo"), 0);
346 base::MessageLoop::current()->Run();
349 TEST_F(CloudPrintURLFetcherOverloadTest, Protect) {
350 net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTP,
351 net::SpawnedTestServer::kLocalhost,
352 base::FilePath(kDocRoot));
353 ASSERT_TRUE(test_server.Start());
355 GURL url(test_server.GetURL("defaultresponse"));
356 CreateFetcher(url, 11);
358 base::MessageLoop::current()->Run();
361 TEST_F(CloudPrintURLFetcherRetryBackoffTest, GiveUp) {
362 net::SpawnedTestServer test_server(net::SpawnedTestServer::TYPE_HTTP,
363 net::SpawnedTestServer::kLocalhost,
364 base::FilePath(kDocRoot));
365 ASSERT_TRUE(test_server.Start());
367 GURL url(test_server.GetURL("defaultresponse"));
368 CreateFetcher(url, 11);
370 base::MessageLoop::current()->Run();
373 } // namespace cloud_print