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"
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
{
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_
);
49 return context_
.get();
53 ~TrackingTestURLRequestContextGetter() override
{
54 g_request_context_getter_instances
--;
59 net::URLRequestThrottlerManager
* throttler_manager_
;
60 scoped_ptr
<net::TestURLRequestContext
> context_
;
63 class TestCloudPrintURLFetcher
: public CloudPrintURLFetcher
{
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(),
74 net::URLRequestThrottlerManager
* throttler_manager() {
75 return &throttler_manager_
;
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
{
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
,
100 const net::URLRequestStatus
& status
,
102 const net::ResponseCookies
& cookies
,
103 const std::string
& data
) override
;
105 CloudPrintURLFetcher::ResponseAction
OnRequestAuthError() override
{
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_
;
117 void SetUp() override
{
118 testing::Test::SetUp();
120 io_task_runner_
= base::ThreadTaskRunnerHandle::Get();
123 void TearDown() override
{
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_
;
140 scoped_refptr
<TestCloudPrintURLFetcher
> fetcher_
;
143 class CloudPrintURLFetcherBasicTest
: public CloudPrintURLFetcherTest
{
145 CloudPrintURLFetcherBasicTest()
146 : handle_raw_response_(false), handle_raw_data_(false) { }
147 // CloudPrintURLFetcher::Delegate
148 CloudPrintURLFetcher::ResponseAction
HandleRawResponse(
149 const net::URLFetcher
* source
,
151 const net::URLRequestStatus
& status
,
153 const net::ResponseCookies
& cookies
,
154 const std::string
& data
) override
;
156 CloudPrintURLFetcher::ResponseAction
HandleRawData(
157 const net::URLFetcher
* source
,
159 const std::string
& data
) override
;
161 CloudPrintURLFetcher::ResponseAction
HandleJSONData(
162 const net::URLFetcher
* source
,
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
;
174 bool handle_raw_response_
;
175 bool handle_raw_data_
;
178 // Version of CloudPrintURLFetcherTest that tests overload protection.
179 class CloudPrintURLFetcherOverloadTest
: public CloudPrintURLFetcherTest
{
181 CloudPrintURLFetcherOverloadTest() : response_count_(0) {
184 // CloudPrintURLFetcher::Delegate
185 CloudPrintURLFetcher::ResponseAction
HandleRawData(
186 const net::URLFetcher
* source
,
188 const std::string
& data
) override
;
194 // Version of CloudPrintURLFetcherTest that tests backoff protection.
195 class CloudPrintURLFetcherRetryBackoffTest
: public CloudPrintURLFetcherTest
{
197 CloudPrintURLFetcherRetryBackoffTest() : response_count_(0) {
200 // CloudPrintURLFetcher::Delegate
201 CloudPrintURLFetcher::ResponseAction
HandleRawData(
202 const net::URLFetcher
* source
,
204 const std::string
& data
) override
;
206 void OnRequestGiveUp() override
;
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
,
233 const net::URLRequestStatus
& status
,
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
,
247 const net::URLRequestStatus
& status
,
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
,
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
,
282 base::DictionaryValue
* json_data
,
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
,
295 const std::string
& data
) {
296 const TimeDelta one_second
= TimeDelta::FromMilliseconds(1000);
298 if (response_count_
< 20) {
299 fetcher_
->StartGetRequest(CloudPrintURLFetcher::REQUEST_MAX
, url
, this,
300 max_retries_
, std::string());
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
,
314 const std::string
& data
) {
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