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/memory/ref_counted.h"
7 #include "base/message_loop/message_loop_proxy.h"
8 #include "base/synchronization/waitable_event.h"
9 #include "base/threading/thread.h"
10 #include "base/values.h"
11 #include "chrome/service/cloud_print/cloud_print_url_fetcher.h"
12 #include "chrome/service/service_process.h"
13 #include "net/test/spawned_test_server/spawned_test_server.h"
14 #include "net/url_request/url_request_context_getter.h"
15 #include "net/url_request/url_request_status.h"
16 #include "net/url_request/url_request_test_util.h"
17 #include "net/url_request/url_request_throttler_manager.h"
18 #include "testing/gtest/include/gtest/gtest.h"
22 using base::TimeDelta
;
24 namespace cloud_print
{
26 const base::FilePath::CharType kDocRoot
[] =
27 FILE_PATH_LITERAL("chrome/test/data");
29 int g_request_context_getter_instances
= 0;
30 class TrackingTestURLRequestContextGetter
31 : public net::TestURLRequestContextGetter
{
33 explicit TrackingTestURLRequestContextGetter(
34 base::MessageLoopProxy
* io_message_loop_proxy
,
35 net::URLRequestThrottlerManager
* throttler_manager
)
36 : TestURLRequestContextGetter(io_message_loop_proxy
),
37 throttler_manager_(throttler_manager
) {
38 g_request_context_getter_instances
++;
41 net::TestURLRequestContext
* GetURLRequestContext() override
{
42 if (!context_
.get()) {
43 context_
.reset(new net::TestURLRequestContext(true));
44 context_
->set_throttler_manager(throttler_manager_
);
47 return context_
.get();
51 ~TrackingTestURLRequestContextGetter() override
{
52 g_request_context_getter_instances
--;
57 net::URLRequestThrottlerManager
* throttler_manager_
;
58 scoped_ptr
<net::TestURLRequestContext
> context_
;
61 class TestCloudPrintURLFetcher
: public CloudPrintURLFetcher
{
63 explicit TestCloudPrintURLFetcher(
64 base::MessageLoopProxy
* io_message_loop_proxy
)
65 : io_message_loop_proxy_(io_message_loop_proxy
) {
68 net::URLRequestContextGetter
* GetRequestContextGetter() override
{
69 return new TrackingTestURLRequestContextGetter(
70 io_message_loop_proxy_
.get(), throttler_manager());
73 net::URLRequestThrottlerManager
* throttler_manager() {
74 return &throttler_manager_
;
78 ~TestCloudPrintURLFetcher() override
{}
80 scoped_refptr
<base::MessageLoopProxy
> io_message_loop_proxy_
;
82 // We set this as the throttler manager for the
83 // TestURLRequestContext we create.
84 net::URLRequestThrottlerManager throttler_manager_
;
87 class CloudPrintURLFetcherTest
: public testing::Test
,
88 public CloudPrintURLFetcherDelegate
{
90 CloudPrintURLFetcherTest() : max_retries_(0), fetcher_(NULL
) { }
92 // Creates a URLFetcher, using the program's main thread to do IO.
93 virtual void CreateFetcher(const GURL
& url
, int max_retries
);
95 // CloudPrintURLFetcher::Delegate
96 CloudPrintURLFetcher::ResponseAction
HandleRawResponse(
97 const net::URLFetcher
* source
,
99 const net::URLRequestStatus
& status
,
101 const net::ResponseCookies
& cookies
,
102 const std::string
& data
) override
;
104 CloudPrintURLFetcher::ResponseAction
OnRequestAuthError() override
{
106 return CloudPrintURLFetcher::STOP_PROCESSING
;
109 std::string
GetAuthHeader() override
{ return std::string(); }
111 scoped_refptr
<base::MessageLoopProxy
> io_message_loop_proxy() {
112 return io_message_loop_proxy_
;
116 void SetUp() override
{
117 testing::Test::SetUp();
119 io_message_loop_proxy_
= base::MessageLoopProxy::current();
122 void TearDown() override
{
124 // Deleting the fetcher causes a task to be posted to the IO thread to
125 // release references to the URLRequestContextGetter. We need to run all
126 // pending tasks to execute that (this is the IO thread).
127 base::MessageLoop::current()->RunUntilIdle();
128 EXPECT_EQ(0, g_request_context_getter_instances
);
131 // URLFetcher is designed to run on the main UI thread, but in our tests
132 // we assume that the current thread is the IO thread where the URLFetcher
133 // dispatches its requests to. When we wish to simulate being used from
134 // a UI thread, we dispatch a worker thread to do so.
135 base::MessageLoopForIO io_loop_
;
136 scoped_refptr
<base::MessageLoopProxy
> io_message_loop_proxy_
;
139 scoped_refptr
<TestCloudPrintURLFetcher
> fetcher_
;
142 class CloudPrintURLFetcherBasicTest
: public CloudPrintURLFetcherTest
{
144 CloudPrintURLFetcherBasicTest()
145 : handle_raw_response_(false), handle_raw_data_(false) { }
146 // CloudPrintURLFetcher::Delegate
147 CloudPrintURLFetcher::ResponseAction
HandleRawResponse(
148 const net::URLFetcher
* source
,
150 const net::URLRequestStatus
& status
,
152 const net::ResponseCookies
& cookies
,
153 const std::string
& data
) override
;
155 CloudPrintURLFetcher::ResponseAction
HandleRawData(
156 const net::URLFetcher
* source
,
158 const std::string
& data
) override
;
160 CloudPrintURLFetcher::ResponseAction
HandleJSONData(
161 const net::URLFetcher
* source
,
163 base::DictionaryValue
* json_data
,
164 bool succeeded
) override
;
166 void SetHandleRawResponse(bool handle_raw_response
) {
167 handle_raw_response_
= handle_raw_response
;
169 void SetHandleRawData(bool handle_raw_data
) {
170 handle_raw_data_
= handle_raw_data
;
173 bool handle_raw_response_
;
174 bool handle_raw_data_
;
177 // Version of CloudPrintURLFetcherTest that tests overload protection.
178 class CloudPrintURLFetcherOverloadTest
: public CloudPrintURLFetcherTest
{
180 CloudPrintURLFetcherOverloadTest() : response_count_(0) {
183 // CloudPrintURLFetcher::Delegate
184 CloudPrintURLFetcher::ResponseAction
HandleRawData(
185 const net::URLFetcher
* source
,
187 const std::string
& data
) override
;
193 // Version of CloudPrintURLFetcherTest that tests backoff protection.
194 class CloudPrintURLFetcherRetryBackoffTest
: public CloudPrintURLFetcherTest
{
196 CloudPrintURLFetcherRetryBackoffTest() : response_count_(0) {
199 // CloudPrintURLFetcher::Delegate
200 CloudPrintURLFetcher::ResponseAction
HandleRawData(
201 const net::URLFetcher
* source
,
203 const std::string
& data
) override
;
205 void OnRequestGiveUp() override
;
212 void CloudPrintURLFetcherTest::CreateFetcher(const GURL
& url
, int max_retries
) {
213 fetcher_
= new TestCloudPrintURLFetcher(io_message_loop_proxy().get());
215 // Registers an entry for test url. It only allows 3 requests to be sent
216 // in 200 milliseconds.
217 scoped_refptr
<net::URLRequestThrottlerEntry
>
218 entry(new net::URLRequestThrottlerEntry(
219 fetcher_
->throttler_manager(), std::string(), 200, 3, 1, 2.0, 0.0, 256));
220 fetcher_
->throttler_manager()->OverrideEntryForTests(url
, entry
.get());
222 max_retries_
= max_retries
;
223 start_time_
= Time::Now();
224 fetcher_
->StartGetRequest(CloudPrintURLFetcher::REQUEST_MAX
, url
, this,
225 max_retries_
, std::string());
228 CloudPrintURLFetcher::ResponseAction
229 CloudPrintURLFetcherTest::HandleRawResponse(
230 const net::URLFetcher
* source
,
232 const net::URLRequestStatus
& status
,
234 const net::ResponseCookies
& cookies
,
235 const std::string
& data
) {
236 EXPECT_TRUE(status
.is_success());
237 EXPECT_EQ(200, response_code
); // HTTP OK
238 EXPECT_FALSE(data
.empty());
239 return CloudPrintURLFetcher::CONTINUE_PROCESSING
;
242 CloudPrintURLFetcher::ResponseAction
243 CloudPrintURLFetcherBasicTest::HandleRawResponse(
244 const net::URLFetcher
* source
,
246 const net::URLRequestStatus
& status
,
248 const net::ResponseCookies
& cookies
,
249 const std::string
& data
) {
250 EXPECT_TRUE(status
.is_success());
251 EXPECT_EQ(200, response_code
); // HTTP OK
252 EXPECT_FALSE(data
.empty());
254 if (handle_raw_response_
) {
255 // If the current message loop is not the IO loop, it will be shut down when
256 // the main loop returns and this thread subsequently goes out of scope.
257 io_message_loop_proxy()->PostTask(FROM_HERE
,
258 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_message_loop_proxy()->PostTask(FROM_HERE
,
273 base::MessageLoop::QuitClosure());
274 return CloudPrintURLFetcher::STOP_PROCESSING
;
276 return CloudPrintURLFetcher::CONTINUE_PROCESSING
;
279 CloudPrintURLFetcher::ResponseAction
280 CloudPrintURLFetcherBasicTest::HandleJSONData(
281 const net::URLFetcher
* source
,
283 base::DictionaryValue
* json_data
,
285 // We should never get here if we returned true in one of the above methods.
286 EXPECT_FALSE(handle_raw_response_
);
287 EXPECT_FALSE(handle_raw_data_
);
288 io_message_loop_proxy()->PostTask(FROM_HERE
,
289 base::MessageLoop::QuitClosure());
290 return CloudPrintURLFetcher::STOP_PROCESSING
;
293 CloudPrintURLFetcher::ResponseAction
294 CloudPrintURLFetcherOverloadTest::HandleRawData(
295 const net::URLFetcher
* source
,
297 const std::string
& data
) {
298 const TimeDelta one_second
= TimeDelta::FromMilliseconds(1000);
300 if (response_count_
< 20) {
301 fetcher_
->StartGetRequest(CloudPrintURLFetcher::REQUEST_MAX
, url
, this,
302 max_retries_
, std::string());
304 // We have already sent 20 requests continuously. And we expect that
305 // it takes more than 1 second due to the overload protection settings.
306 EXPECT_TRUE(Time::Now() - start_time_
>= one_second
);
307 io_message_loop_proxy()->PostTask(FROM_HERE
,
308 base::MessageLoop::QuitClosure());
310 return CloudPrintURLFetcher::STOP_PROCESSING
;
313 CloudPrintURLFetcher::ResponseAction
314 CloudPrintURLFetcherRetryBackoffTest::HandleRawData(
315 const net::URLFetcher
* source
,
317 const std::string
& data
) {
319 // First attempt + 11 retries = 12 total responses.
320 EXPECT_LE(response_count_
, 12);
321 return CloudPrintURLFetcher::RETRY_REQUEST
;
324 void CloudPrintURLFetcherRetryBackoffTest::OnRequestGiveUp() {
325 // It takes more than 200 ms to finish all 11 requests.
326 EXPECT_TRUE(Time::Now() - start_time_
>= TimeDelta::FromMilliseconds(200));
327 io_message_loop_proxy()->PostTask(FROM_HERE
,
328 base::MessageLoop::QuitClosure());
331 TEST_F(CloudPrintURLFetcherBasicTest
, HandleRawResponse
) {
332 net::SpawnedTestServer
test_server(net::SpawnedTestServer::TYPE_HTTP
,
333 net::SpawnedTestServer::kLocalhost
,
334 base::FilePath(kDocRoot
));
335 ASSERT_TRUE(test_server
.Start());
336 SetHandleRawResponse(true);
338 CreateFetcher(test_server
.GetURL("echo"), 0);
339 base::MessageLoop::current()->Run();
342 TEST_F(CloudPrintURLFetcherBasicTest
, HandleRawData
) {
343 net::SpawnedTestServer
test_server(net::SpawnedTestServer::TYPE_HTTP
,
344 net::SpawnedTestServer::kLocalhost
,
345 base::FilePath(kDocRoot
));
346 ASSERT_TRUE(test_server
.Start());
348 SetHandleRawData(true);
349 CreateFetcher(test_server
.GetURL("echo"), 0);
350 base::MessageLoop::current()->Run();
353 TEST_F(CloudPrintURLFetcherOverloadTest
, Protect
) {
354 net::SpawnedTestServer
test_server(net::SpawnedTestServer::TYPE_HTTP
,
355 net::SpawnedTestServer::kLocalhost
,
356 base::FilePath(kDocRoot
));
357 ASSERT_TRUE(test_server
.Start());
359 GURL
url(test_server
.GetURL("defaultresponse"));
360 CreateFetcher(url
, 11);
362 base::MessageLoop::current()->Run();
365 TEST_F(CloudPrintURLFetcherRetryBackoffTest
, GiveUp
) {
366 net::SpawnedTestServer
test_server(net::SpawnedTestServer::TYPE_HTTP
,
367 net::SpawnedTestServer::kLocalhost
,
368 base::FilePath(kDocRoot
));
369 ASSERT_TRUE(test_server
.Start());
371 GURL
url(test_server
.GetURL("defaultresponse"));
372 CreateFetcher(url
, 11);
374 base::MessageLoop::current()->Run();
377 } // namespace cloud_print