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