cloud_print_url_fetcher_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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. 4 5#include "base/command_line.h" 6#include "base/memory/ref_counted.h" 7#include "base/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 "googleurl/src/gurl.h" 14#include "net/test/test_server.h" 15#include "net/url_request/url_request_context_getter.h" 16#include "net/url_request/url_request_status.h" 17#include "net/url_request/url_request_test_util.h" 18#include "net/url_request/url_request_throttler_manager.h" 19#include "testing/gtest/include/gtest/gtest.h" 20 21using base::Time; 22using base::TimeDelta; 23 24namespace cloud_print { 25 26const base::FilePath::CharType kDocRoot[] = 27 FILE_PATH_LITERAL("chrome/test/data"); 28 29int g_request_context_getter_instances = 0; 30class TrackingTestURLRequestContextGetter 31 : public net::TestURLRequestContextGetter { 32 public: 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 context_(NULL) { 39 g_request_context_getter_instances++; 40 } 41 42 virtual net::TestURLRequestContext* GetURLRequestContext() OVERRIDE { 43 if (!context_.get()) { 44 context_.reset(new net::TestURLRequestContext(true)); 45 context_->set_throttler_manager(throttler_manager_); 46 context_->Init(); 47 } 48 return context_.get(); 49 } 50 51 protected: 52 virtual ~TrackingTestURLRequestContextGetter() { 53 g_request_context_getter_instances--; 54 } 55 56 private: 57 // Not owned here. 58 net::URLRequestThrottlerManager* throttler_manager_; 59 scoped_ptr<net::TestURLRequestContext> context_; 60}; 61 62class TestCloudPrintURLFetcher : public CloudPrintURLFetcher { 63 public: 64 explicit TestCloudPrintURLFetcher( 65 base::MessageLoopProxy* io_message_loop_proxy) 66 : io_message_loop_proxy_(io_message_loop_proxy) { 67 } 68 69 virtual net::URLRequestContextGetter* GetRequestContextGetter() OVERRIDE { 70 return new TrackingTestURLRequestContextGetter( 71 io_message_loop_proxy_.get(), throttler_manager()); 72 } 73 74 net::URLRequestThrottlerManager* throttler_manager() { 75 return &throttler_manager_; 76 } 77 78 private: 79 virtual ~TestCloudPrintURLFetcher() {} 80 81 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; 82 83 // We set this as the throttler manager for the 84 // TestURLRequestContext we create. 85 net::URLRequestThrottlerManager throttler_manager_; 86}; 87 88class CloudPrintURLFetcherTest : public testing::Test, 89 public CloudPrintURLFetcherDelegate { 90 public: 91 CloudPrintURLFetcherTest() : max_retries_(0), fetcher_(NULL) { } 92 93 // Creates a URLFetcher, using the program's main thread to do IO. 94 virtual void CreateFetcher(const GURL& url, int max_retries); 95 96 // CloudPrintURLFetcher::Delegate 97 virtual 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; 104 105 virtual CloudPrintURLFetcher::ResponseAction OnRequestAuthError() OVERRIDE { 106 ADD_FAILURE(); 107 return CloudPrintURLFetcher::STOP_PROCESSING; 108 } 109 110 virtual std::string GetAuthHeader() OVERRIDE { 111 return std::string(); 112 } 113 114 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy() { 115 return io_message_loop_proxy_; 116 } 117 118 protected: 119 virtual void SetUp() { 120 testing::Test::SetUp(); 121 122 io_message_loop_proxy_ = base::MessageLoopProxy::current(); 123 } 124 125 virtual void TearDown() { 126 fetcher_ = NULL; 127 // Deleting the fetcher causes a task to be posted to the IO thread to 128 // release references to the URLRequestContextGetter. We need to run all 129 // pending tasks to execute that (this is the IO thread). 130 MessageLoop::current()->RunUntilIdle(); 131 EXPECT_EQ(0, g_request_context_getter_instances); 132 } 133 134 // URLFetcher is designed to run on the main UI thread, but in our tests 135 // we assume that the current thread is the IO thread where the URLFetcher 136 // dispatches its requests to. When we wish to simulate being used from 137 // a UI thread, we dispatch a worker thread to do so. 138 MessageLoopForIO io_loop_; 139 scoped_refptr<base::MessageLoopProxy> io_message_loop_proxy_; 140 int max_retries_; 141 Time start_time_; 142 scoped_refptr<TestCloudPrintURLFetcher> fetcher_; 143}; 144 145class CloudPrintURLFetcherBasicTest : public CloudPrintURLFetcherTest { 146 public: 147 CloudPrintURLFetcherBasicTest() 148 : handle_raw_response_(false), handle_raw_data_(false) { } 149 // CloudPrintURLFetcher::Delegate 150 virtual CloudPrintURLFetcher::ResponseAction HandleRawResponse( 151 const net::URLFetcher* source, 152 const GURL& url, 153 const net::URLRequestStatus& status, 154 int response_code, 155 const net::ResponseCookies& cookies, 156 const std::string& data) OVERRIDE; 157 158 virtual CloudPrintURLFetcher::ResponseAction HandleRawData( 159 const net::URLFetcher* source, 160 const GURL& url, 161 const std::string& data) OVERRIDE; 162 163 virtual CloudPrintURLFetcher::ResponseAction HandleJSONData( 164 const net::URLFetcher* source, 165 const GURL& url, 166 DictionaryValue* json_data, 167 bool succeeded) OVERRIDE; 168 169 void SetHandleRawResponse(bool handle_raw_response) { 170 handle_raw_response_ = handle_raw_response; 171 } 172 void SetHandleRawData(bool handle_raw_data) { 173 handle_raw_data_ = handle_raw_data; 174 } 175 private: 176 bool handle_raw_response_; 177 bool handle_raw_data_; 178}; 179 180// Version of CloudPrintURLFetcherTest that tests overload protection. 181class CloudPrintURLFetcherOverloadTest : public CloudPrintURLFetcherTest { 182 public: 183 CloudPrintURLFetcherOverloadTest() : response_count_(0) { 184 } 185 186 // CloudPrintURLFetcher::Delegate 187 virtual CloudPrintURLFetcher::ResponseAction HandleRawData( 188 const net::URLFetcher* source, 189 const GURL& url, 190 const std::string& data) OVERRIDE; 191 192 private: 193 int response_count_; 194}; 195 196// Version of CloudPrintURLFetcherTest that tests backoff protection. 197class CloudPrintURLFetcherRetryBackoffTest : public CloudPrintURLFetcherTest { 198 public: 199 CloudPrintURLFetcherRetryBackoffTest() : response_count_(0) { 200 } 201 202 // CloudPrintURLFetcher::Delegate 203 virtual CloudPrintURLFetcher::ResponseAction HandleRawData( 204 const net::URLFetcher* source, 205 const GURL& url, 206 const std::string& data) OVERRIDE; 207 208 virtual void OnRequestGiveUp() OVERRIDE; 209 210 private: 211 int response_count_; 212}; 213 214 215void CloudPrintURLFetcherTest::CreateFetcher(const GURL& url, int max_retries) { 216 fetcher_ = new TestCloudPrintURLFetcher(io_message_loop_proxy()); 217 218 // Registers an entry for test url. It only allows 3 requests to be sent 219 // in 200 milliseconds. 220 scoped_refptr<net::URLRequestThrottlerEntry> entry( 221 new net::URLRequestThrottlerEntry( 222 fetcher_->throttler_manager(), "", 200, 3, 1, 2.0, 0.0, 256)); 223 fetcher_->throttler_manager()->OverrideEntryForTests(url, entry); 224 225 max_retries_ = max_retries; 226 start_time_ = Time::Now(); 227 fetcher_->StartGetRequest(url, this, max_retries_, std::string()); 228} 229 230CloudPrintURLFetcher::ResponseAction 231CloudPrintURLFetcherTest::HandleRawResponse( 232 const net::URLFetcher* source, 233 const GURL& url, 234 const net::URLRequestStatus& status, 235 int response_code, 236 const net::ResponseCookies& cookies, 237 const std::string& data) { 238 EXPECT_TRUE(status.is_success()); 239 EXPECT_EQ(200, response_code); // HTTP OK 240 EXPECT_FALSE(data.empty()); 241 return CloudPrintURLFetcher::CONTINUE_PROCESSING; 242} 243 244CloudPrintURLFetcher::ResponseAction 245CloudPrintURLFetcherBasicTest::HandleRawResponse( 246 const net::URLFetcher* source, 247 const GURL& url, 248 const net::URLRequestStatus& status, 249 int response_code, 250 const net::ResponseCookies& cookies, 251 const std::string& data) { 252 EXPECT_TRUE(status.is_success()); 253 EXPECT_EQ(200, response_code); // HTTP OK 254 EXPECT_FALSE(data.empty()); 255 256 if (handle_raw_response_) { 257 // If the current message loop is not the IO loop, it will be shut down when 258 // the main loop returns and this thread subsequently goes out of scope. 259 io_message_loop_proxy()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 260 return CloudPrintURLFetcher::STOP_PROCESSING; 261 } 262 return CloudPrintURLFetcher::CONTINUE_PROCESSING; 263} 264 265CloudPrintURLFetcher::ResponseAction 266CloudPrintURLFetcherBasicTest::HandleRawData( 267 const net::URLFetcher* source, 268 const GURL& url, 269 const std::string& data) { 270 // We should never get here if we returned true in HandleRawResponse 271 EXPECT_FALSE(handle_raw_response_); 272 if (handle_raw_data_) { 273 io_message_loop_proxy()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 274 return CloudPrintURLFetcher::STOP_PROCESSING; 275 } 276 return CloudPrintURLFetcher::CONTINUE_PROCESSING; 277} 278 279CloudPrintURLFetcher::ResponseAction 280CloudPrintURLFetcherBasicTest::HandleJSONData( 281 const net::URLFetcher* source, 282 const GURL& url, 283 DictionaryValue* json_data, 284 bool succeeded) { 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, MessageLoop::QuitClosure()); 289 return CloudPrintURLFetcher::STOP_PROCESSING; 290} 291 292CloudPrintURLFetcher::ResponseAction 293CloudPrintURLFetcherOverloadTest::HandleRawData( 294 const net::URLFetcher* source, 295 const GURL& url, 296 const std::string& data) { 297 const TimeDelta one_second = TimeDelta::FromMilliseconds(1000); 298 response_count_++; 299 if (response_count_ < 20) { 300 fetcher_->StartGetRequest(url, 301 this, 302 max_retries_, 303 std::string()); 304 } else { 305 // We have already sent 20 requests continuously. And we expect that 306 // it takes more than 1 second due to the overload protection settings. 307 EXPECT_TRUE(Time::Now() - start_time_ >= one_second); 308 io_message_loop_proxy()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); 309 } 310 return CloudPrintURLFetcher::STOP_PROCESSING; 311} 312 313CloudPrintURLFetcher::ResponseAction 314CloudPrintURLFetcherRetryBackoffTest::HandleRawData( 315 const net::URLFetcher* source, 316 const GURL& url, 317 const std::string& data) { 318 response_count_++; 319 // First attempt + 11 retries = 12 total responses. 320 EXPECT_LE(response_count_, 12); 321 return CloudPrintURLFetcher::RETRY_REQUEST; 322} 323 324void 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, MessageLoop::QuitClosure()); 328} 329 330TEST_F(CloudPrintURLFetcherBasicTest, HandleRawResponse) { 331 net::TestServer test_server(net::TestServer::TYPE_HTTP, 332 net::TestServer::kLocalhost, 333 base::FilePath(kDocRoot)); 334 ASSERT_TRUE(test_server.Start()); 335 SetHandleRawResponse(true); 336 337 CreateFetcher(test_server.GetURL("echo"), 0); 338 MessageLoop::current()->Run(); 339} 340 341TEST_F(CloudPrintURLFetcherBasicTest, HandleRawData) { 342 net::TestServer test_server(net::TestServer::TYPE_HTTP, 343 net::TestServer::kLocalhost, 344 base::FilePath(kDocRoot)); 345 ASSERT_TRUE(test_server.Start()); 346 347 SetHandleRawData(true); 348 CreateFetcher(test_server.GetURL("echo"), 0); 349 MessageLoop::current()->Run(); 350} 351 352TEST_F(CloudPrintURLFetcherOverloadTest, Protect) { 353 net::TestServer test_server(net::TestServer::TYPE_HTTP, 354 net::TestServer::kLocalhost, 355 base::FilePath(kDocRoot)); 356 ASSERT_TRUE(test_server.Start()); 357 358 GURL url(test_server.GetURL("defaultresponse")); 359 CreateFetcher(url, 11); 360 361 MessageLoop::current()->Run(); 362} 363 364TEST_F(CloudPrintURLFetcherRetryBackoffTest, GiveUp) { 365 net::TestServer test_server(net::TestServer::TYPE_HTTP, 366 net::TestServer::kLocalhost, 367 base::FilePath(kDocRoot)); 368 ASSERT_TRUE(test_server.Start()); 369 370 GURL url(test_server.GetURL("defaultresponse")); 371 CreateFetcher(url, 11); 372 373 MessageLoop::current()->Run(); 374} 375 376} // namespace cloud_print 377