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