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