autofill_download_manager_unittest.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright 2014 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 "components/autofill/core/browser/autofill_download_manager.h" 6 7#include <list> 8 9#include "base/message_loop/message_loop.h" 10#include "base/prefs/pref_service.h" 11#include "base/strings/string_util.h" 12#include "base/strings/utf_string_conversions.h" 13#include "base/test/test_timeouts.h" 14#include "components/autofill/core/browser/autofill_field.h" 15#include "components/autofill/core/browser/autofill_metrics.h" 16#include "components/autofill/core/browser/autofill_test_utils.h" 17#include "components/autofill/core/browser/autofill_type.h" 18#include "components/autofill/core/browser/form_structure.h" 19#include "components/autofill/core/browser/test_autofill_driver.h" 20#include "components/autofill/core/common/form_data.h" 21#include "net/url_request/test_url_fetcher_factory.h" 22#include "net/url_request/url_request_status.h" 23#include "net/url_request/url_request_test_util.h" 24#include "testing/gmock/include/gmock/gmock.h" 25#include "testing/gtest/include/gtest/gtest.h" 26 27using base::ASCIIToUTF16; 28 29namespace autofill { 30 31namespace { 32 33class MockAutofillMetrics : public AutofillMetrics { 34 public: 35 MockAutofillMetrics() {} 36 MOCK_CONST_METHOD1(LogServerQueryMetric, void(ServerQueryMetric metric)); 37 38 private: 39 DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics); 40}; 41 42// Call |fetcher->OnURLFetchComplete()| as the URLFetcher would when 43// a response is received. Params allow caller to set fake status. 44void FakeOnURLFetchComplete(net::TestURLFetcher* fetcher, 45 int response_code, 46 const std::string& response_body) { 47 fetcher->set_url(GURL()); 48 fetcher->set_status(net::URLRequestStatus()); 49 fetcher->set_response_code(response_code); 50 fetcher->SetResponseString(response_body); 51 52 fetcher->delegate()->OnURLFetchComplete(fetcher); 53} 54 55} // namespace 56 57// This tests AutofillDownloadManager. AutofillDownloadTest implements 58// AutofillDownloadManager::Observer and creates an instance of 59// AutofillDownloadManager. Then it records responses to different initiated 60// requests, which are verified later. To mock network requests 61// TestURLFetcherFactory is used, which creates URLFetchers that do not 62// go over the wire, but allow calling back HTTP responses directly. 63// The responses in test are out of order and verify: successful query request, 64// successful upload request, failed upload request. 65class AutofillDownloadTest : public AutofillDownloadManager::Observer, 66 public testing::Test { 67 public: 68 AutofillDownloadTest() 69 : prefs_(test::PrefServiceForTesting()), 70 request_context_(new net::TestURLRequestContextGetter( 71 base::MessageLoopProxy::current())), 72 download_manager_(&driver_, prefs_.get(), this) { 73 driver_.SetURLRequestContext(request_context_); 74 } 75 76 void LimitCache(size_t cache_size) { 77 download_manager_.set_max_form_cache_size(cache_size); 78 } 79 80 // AutofillDownloadManager::Observer implementation. 81 virtual void OnLoadedServerPredictions( 82 const std::string& response_xml) OVERRIDE { 83 ResponseData response; 84 response.response = response_xml; 85 response.type_of_response = QUERY_SUCCESSFULL; 86 responses_.push_back(response); 87 } 88 89 virtual void OnUploadedPossibleFieldTypes() OVERRIDE { 90 ResponseData response; 91 response.type_of_response = UPLOAD_SUCCESSFULL; 92 responses_.push_back(response); 93 } 94 95 virtual void OnServerRequestError( 96 const std::string& form_signature, 97 AutofillDownloadManager::RequestType request_type, 98 int http_error) OVERRIDE { 99 ResponseData response; 100 response.signature = form_signature; 101 response.error = http_error; 102 response.type_of_response = 103 request_type == AutofillDownloadManager::REQUEST_QUERY ? 104 REQUEST_QUERY_FAILED : REQUEST_UPLOAD_FAILED; 105 responses_.push_back(response); 106 } 107 108 enum ResponseType { 109 QUERY_SUCCESSFULL, 110 UPLOAD_SUCCESSFULL, 111 REQUEST_QUERY_FAILED, 112 REQUEST_UPLOAD_FAILED, 113 }; 114 115 struct ResponseData { 116 ResponseType type_of_response; 117 int error; 118 std::string signature; 119 std::string response; 120 121 ResponseData() : type_of_response(REQUEST_QUERY_FAILED), error(0) {} 122 }; 123 124 base::MessageLoop message_loop_; 125 std::list<ResponseData> responses_; 126 scoped_ptr<PrefService> prefs_; 127 scoped_refptr<net::TestURLRequestContextGetter> request_context_; 128 TestAutofillDriver driver_; 129 AutofillDownloadManager download_manager_; 130}; 131 132TEST_F(AutofillDownloadTest, QueryAndUploadTest) { 133 // Create and register factory. 134 net::TestURLFetcherFactory factory; 135 136 FormData form; 137 138 FormFieldData field; 139 field.label = ASCIIToUTF16("username"); 140 field.name = ASCIIToUTF16("username"); 141 field.form_control_type = "text"; 142 form.fields.push_back(field); 143 144 field.label = ASCIIToUTF16("First Name"); 145 field.name = ASCIIToUTF16("firstname"); 146 field.form_control_type = "text"; 147 form.fields.push_back(field); 148 149 field.label = ASCIIToUTF16("Last Name"); 150 field.name = ASCIIToUTF16("lastname"); 151 field.form_control_type = "text"; 152 form.fields.push_back(field); 153 154 field.label = ASCIIToUTF16("email"); 155 field.name = ASCIIToUTF16("email"); 156 field.form_control_type = "text"; 157 form.fields.push_back(field); 158 159 field.label = ASCIIToUTF16("email2"); 160 field.name = ASCIIToUTF16("email2"); 161 field.form_control_type = "text"; 162 form.fields.push_back(field); 163 164 field.label = ASCIIToUTF16("password"); 165 field.name = ASCIIToUTF16("password"); 166 field.form_control_type = "password"; 167 form.fields.push_back(field); 168 169 field.label = base::string16(); 170 field.name = ASCIIToUTF16("Submit"); 171 field.form_control_type = "submit"; 172 form.fields.push_back(field); 173 174 FormStructure *form_structure = new FormStructure(form); 175 ScopedVector<FormStructure> form_structures; 176 form_structures.push_back(form_structure); 177 178 form.fields.clear(); 179 180 field.label = ASCIIToUTF16("address"); 181 field.name = ASCIIToUTF16("address"); 182 field.form_control_type = "text"; 183 form.fields.push_back(field); 184 185 field.label = ASCIIToUTF16("address2"); 186 field.name = ASCIIToUTF16("address2"); 187 field.form_control_type = "text"; 188 form.fields.push_back(field); 189 190 field.label = ASCIIToUTF16("city"); 191 field.name = ASCIIToUTF16("city"); 192 field.form_control_type = "text"; 193 form.fields.push_back(field); 194 195 field.label = base::string16(); 196 field.name = ASCIIToUTF16("Submit"); 197 field.form_control_type = "submit"; 198 form.fields.push_back(field); 199 200 form_structure = new FormStructure(form); 201 form_structures.push_back(form_structure); 202 203 // Request with id 0. 204 MockAutofillMetrics mock_metric_logger; 205 EXPECT_CALL(mock_metric_logger, 206 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); 207 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures.get(), 208 mock_metric_logger)); 209 // Set upload to 100% so requests happen. 210 download_manager_.SetPositiveUploadRate(1.0); 211 download_manager_.SetNegativeUploadRate(1.0); 212 // Request with id 1. 213 EXPECT_TRUE(download_manager_.StartUploadRequest( 214 *(form_structures[0]), true, ServerFieldTypeSet())); 215 // Request with id 2. 216 EXPECT_TRUE(download_manager_.StartUploadRequest( 217 *(form_structures[1]), false, ServerFieldTypeSet())); 218 219 const char *responses[] = { 220 "<autofillqueryresponse>" 221 "<field autofilltype=\"0\" />" 222 "<field autofilltype=\"3\" />" 223 "<field autofilltype=\"5\" />" 224 "<field autofilltype=\"9\" />" 225 "<field autofilltype=\"0\" />" 226 "<field autofilltype=\"30\" />" 227 "<field autofilltype=\"31\" />" 228 "<field autofilltype=\"33\" />" 229 "</autofillqueryresponse>", 230 "<autofilluploadresponse positiveuploadrate=\"0.5\" " 231 "negativeuploadrate=\"0.3\"/>", 232 "<html></html>", 233 }; 234 235 // Return them out of sequence. 236 net::TestURLFetcher* fetcher = factory.GetFetcherByID(1); 237 ASSERT_TRUE(fetcher); 238 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[1])); 239 240 // After that upload rates would be adjusted to 0.5/0.3 241 EXPECT_DOUBLE_EQ(0.5, download_manager_.GetPositiveUploadRate()); 242 EXPECT_DOUBLE_EQ(0.3, download_manager_.GetNegativeUploadRate()); 243 244 fetcher = factory.GetFetcherByID(2); 245 ASSERT_TRUE(fetcher); 246 FakeOnURLFetchComplete(fetcher, 404, std::string(responses[2])); 247 248 fetcher = factory.GetFetcherByID(0); 249 ASSERT_TRUE(fetcher); 250 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[0])); 251 EXPECT_EQ(static_cast<size_t>(3), responses_.size()); 252 253 EXPECT_EQ(AutofillDownloadTest::UPLOAD_SUCCESSFULL, 254 responses_.front().type_of_response); 255 EXPECT_EQ(0, responses_.front().error); 256 EXPECT_EQ(std::string(), responses_.front().signature); 257 // Expected response on non-query request is an empty string. 258 EXPECT_EQ(std::string(), responses_.front().response); 259 responses_.pop_front(); 260 261 EXPECT_EQ(AutofillDownloadTest::REQUEST_UPLOAD_FAILED, 262 responses_.front().type_of_response); 263 EXPECT_EQ(404, responses_.front().error); 264 EXPECT_EQ(form_structures[1]->FormSignature(), 265 responses_.front().signature); 266 // Expected response on non-query request is an empty string. 267 EXPECT_EQ(std::string(), responses_.front().response); 268 responses_.pop_front(); 269 270 EXPECT_EQ(responses_.front().type_of_response, 271 AutofillDownloadTest::QUERY_SUCCESSFULL); 272 EXPECT_EQ(0, responses_.front().error); 273 EXPECT_EQ(std::string(), responses_.front().signature); 274 EXPECT_EQ(responses[0], responses_.front().response); 275 responses_.pop_front(); 276 277 // Set upload to 0% so no new requests happen. 278 download_manager_.SetPositiveUploadRate(0.0); 279 download_manager_.SetNegativeUploadRate(0.0); 280 // No actual requests for the next two calls, as we set upload rate to 0%. 281 EXPECT_FALSE(download_manager_.StartUploadRequest( 282 *(form_structures[0]), true, ServerFieldTypeSet())); 283 EXPECT_FALSE(download_manager_.StartUploadRequest( 284 *(form_structures[1]), false, ServerFieldTypeSet())); 285 fetcher = factory.GetFetcherByID(3); 286 EXPECT_EQ(NULL, fetcher); 287 288 // Modify form structures to miss the cache. 289 field.label = ASCIIToUTF16("Address line 2"); 290 field.name = ASCIIToUTF16("address2"); 291 field.form_control_type = "text"; 292 form.fields.push_back(field); 293 form_structure = new FormStructure(form); 294 form_structures.push_back(form_structure); 295 296 // Request with id 3. 297 EXPECT_CALL(mock_metric_logger, 298 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); 299 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures.get(), 300 mock_metric_logger)); 301 fetcher = factory.GetFetcherByID(3); 302 ASSERT_TRUE(fetcher); 303 fetcher->set_backoff_delay(TestTimeouts::action_max_timeout()); 304 FakeOnURLFetchComplete(fetcher, 500, std::string(responses[0])); 305 306 EXPECT_EQ(AutofillDownloadTest::REQUEST_QUERY_FAILED, 307 responses_.front().type_of_response); 308 EXPECT_EQ(500, responses_.front().error); 309 // Expected response on non-query request is an empty string. 310 EXPECT_EQ(std::string(), responses_.front().response); 311 responses_.pop_front(); 312 313 // Query requests should be ignored for the next 10 seconds. 314 EXPECT_CALL(mock_metric_logger, 315 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(0); 316 EXPECT_FALSE(download_manager_.StartQueryRequest(form_structures.get(), 317 mock_metric_logger)); 318 fetcher = factory.GetFetcherByID(4); 319 EXPECT_EQ(NULL, fetcher); 320 321 // Set upload required to true so requests happen. 322 form_structures[0]->upload_required_ = UPLOAD_REQUIRED; 323 // Request with id 4. 324 EXPECT_TRUE(download_manager_.StartUploadRequest( 325 *(form_structures[0]), true, ServerFieldTypeSet())); 326 fetcher = factory.GetFetcherByID(4); 327 ASSERT_TRUE(fetcher); 328 fetcher->set_backoff_delay(TestTimeouts::action_max_timeout()); 329 FakeOnURLFetchComplete(fetcher, 503, std::string(responses[2])); 330 EXPECT_EQ(AutofillDownloadTest::REQUEST_UPLOAD_FAILED, 331 responses_.front().type_of_response); 332 EXPECT_EQ(503, responses_.front().error); 333 responses_.pop_front(); 334 335 // Upload requests should be ignored for the next 10 seconds. 336 EXPECT_FALSE(download_manager_.StartUploadRequest( 337 *(form_structures[0]), true, ServerFieldTypeSet())); 338 fetcher = factory.GetFetcherByID(5); 339 EXPECT_EQ(NULL, fetcher); 340} 341 342TEST_F(AutofillDownloadTest, CacheQueryTest) { 343 // Create and register factory. 344 net::TestURLFetcherFactory factory; 345 346 FormData form; 347 348 FormFieldData field; 349 field.form_control_type = "text"; 350 351 field.label = ASCIIToUTF16("username"); 352 field.name = ASCIIToUTF16("username"); 353 form.fields.push_back(field); 354 355 field.label = ASCIIToUTF16("First Name"); 356 field.name = ASCIIToUTF16("firstname"); 357 form.fields.push_back(field); 358 359 field.label = ASCIIToUTF16("Last Name"); 360 field.name = ASCIIToUTF16("lastname"); 361 form.fields.push_back(field); 362 363 FormStructure *form_structure = new FormStructure(form); 364 ScopedVector<FormStructure> form_structures0; 365 form_structures0.push_back(form_structure); 366 367 // Add a slightly different form, which should result in a different request. 368 field.label = ASCIIToUTF16("email"); 369 field.name = ASCIIToUTF16("email"); 370 form.fields.push_back(field); 371 form_structure = new FormStructure(form); 372 ScopedVector<FormStructure> form_structures1; 373 form_structures1.push_back(form_structure); 374 375 // Add another slightly different form, which should also result in a 376 // different request. 377 field.label = ASCIIToUTF16("email2"); 378 field.name = ASCIIToUTF16("email2"); 379 form.fields.push_back(field); 380 form_structure = new FormStructure(form); 381 ScopedVector<FormStructure> form_structures2; 382 form_structures2.push_back(form_structure); 383 384 // Limit cache to two forms. 385 LimitCache(2); 386 387 const char *responses[] = { 388 "<autofillqueryresponse>" 389 "<field autofilltype=\"0\" />" 390 "<field autofilltype=\"3\" />" 391 "<field autofilltype=\"5\" />" 392 "</autofillqueryresponse>", 393 "<autofillqueryresponse>" 394 "<field autofilltype=\"0\" />" 395 "<field autofilltype=\"3\" />" 396 "<field autofilltype=\"5\" />" 397 "<field autofilltype=\"9\" />" 398 "</autofillqueryresponse>", 399 "<autofillqueryresponse>" 400 "<field autofilltype=\"0\" />" 401 "<field autofilltype=\"3\" />" 402 "<field autofilltype=\"5\" />" 403 "<field autofilltype=\"9\" />" 404 "<field autofilltype=\"0\" />" 405 "</autofillqueryresponse>", 406 }; 407 408 // Request with id 0. 409 MockAutofillMetrics mock_metric_logger; 410 EXPECT_CALL(mock_metric_logger, 411 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); 412 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures0.get(), 413 mock_metric_logger)); 414 // No responses yet 415 EXPECT_EQ(static_cast<size_t>(0), responses_.size()); 416 417 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); 418 ASSERT_TRUE(fetcher); 419 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[0])); 420 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); 421 EXPECT_EQ(responses[0], responses_.front().response); 422 423 responses_.clear(); 424 425 // No actual request - should be a cache hit. 426 EXPECT_CALL(mock_metric_logger, 427 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); 428 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures0.get(), 429 mock_metric_logger)); 430 // Data is available immediately from cache - no over-the-wire trip. 431 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); 432 EXPECT_EQ(responses[0], responses_.front().response); 433 responses_.clear(); 434 435 // Request with id 1. 436 EXPECT_CALL(mock_metric_logger, 437 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); 438 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures1.get(), 439 mock_metric_logger)); 440 // No responses yet 441 EXPECT_EQ(static_cast<size_t>(0), responses_.size()); 442 443 fetcher = factory.GetFetcherByID(1); 444 ASSERT_TRUE(fetcher); 445 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[1])); 446 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); 447 EXPECT_EQ(responses[1], responses_.front().response); 448 449 responses_.clear(); 450 451 // Request with id 2. 452 EXPECT_CALL(mock_metric_logger, 453 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); 454 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures2.get(), 455 mock_metric_logger)); 456 457 fetcher = factory.GetFetcherByID(2); 458 ASSERT_TRUE(fetcher); 459 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[2])); 460 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); 461 EXPECT_EQ(responses[2], responses_.front().response); 462 463 responses_.clear(); 464 465 // No actual requests - should be a cache hit. 466 EXPECT_CALL(mock_metric_logger, 467 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); 468 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures1.get(), 469 mock_metric_logger)); 470 471 EXPECT_CALL(mock_metric_logger, 472 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); 473 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures2.get(), 474 mock_metric_logger)); 475 476 ASSERT_EQ(static_cast<size_t>(2), responses_.size()); 477 EXPECT_EQ(responses[1], responses_.front().response); 478 EXPECT_EQ(responses[2], responses_.back().response); 479 responses_.clear(); 480 481 // The first structure should've expired. 482 // Request with id 3. 483 EXPECT_CALL(mock_metric_logger, 484 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); 485 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures0.get(), 486 mock_metric_logger)); 487 // No responses yet 488 EXPECT_EQ(static_cast<size_t>(0), responses_.size()); 489 490 fetcher = factory.GetFetcherByID(3); 491 ASSERT_TRUE(fetcher); 492 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[0])); 493 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); 494 EXPECT_EQ(responses[0], responses_.front().response); 495} 496 497} // namespace autofill 498