• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/prefs/pref_service.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/test/test_timeouts.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_test_utils.h"
16 #include "components/autofill/core/browser/autofill_type.h"
17 #include "components/autofill/core/browser/form_structure.h"
18 #include "components/autofill/core/browser/test_autofill_driver.h"
19 #include "components/autofill/core/common/form_data.h"
20 #include "net/url_request/test_url_fetcher_factory.h"
21 #include "net/url_request/url_request_status.h"
22 #include "net/url_request/url_request_test_util.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 
26 using base::ASCIIToUTF16;
27 
28 namespace autofill {
29 
30 namespace {
31 
32 class MockAutofillMetrics : public AutofillMetrics {
33  public:
MockAutofillMetrics()34   MockAutofillMetrics() {}
35   MOCK_CONST_METHOD1(LogServerQueryMetric, void(ServerQueryMetric metric));
36 
37  private:
38   DISALLOW_COPY_AND_ASSIGN(MockAutofillMetrics);
39 };
40 
41 // Call |fetcher->OnURLFetchComplete()| as the URLFetcher would when
42 // a response is received.  Params allow caller to set fake status.
FakeOnURLFetchComplete(net::TestURLFetcher * fetcher,int response_code,const std::string & response_body)43 void FakeOnURLFetchComplete(net::TestURLFetcher* fetcher,
44                             int response_code,
45                             const std::string& response_body) {
46   fetcher->set_url(GURL());
47   fetcher->set_status(net::URLRequestStatus());
48   fetcher->set_response_code(response_code);
49   fetcher->SetResponseString(response_body);
50 
51   fetcher->delegate()->OnURLFetchComplete(fetcher);
52 }
53 
54 }  // namespace
55 
56 // This tests AutofillDownloadManager. AutofillDownloadTest implements
57 // AutofillDownloadManager::Observer and creates an instance of
58 // AutofillDownloadManager. Then it records responses to different initiated
59 // requests, which are verified later. To mock network requests
60 // TestURLFetcherFactory is used, which creates URLFetchers that do not
61 // go over the wire, but allow calling back HTTP responses directly.
62 // The responses in test are out of order and verify: successful query request,
63 // successful upload request, failed upload request.
64 class AutofillDownloadTest : public AutofillDownloadManager::Observer,
65                              public testing::Test {
66  public:
AutofillDownloadTest()67   AutofillDownloadTest()
68       : prefs_(test::PrefServiceForTesting()),
69         request_context_(new net::TestURLRequestContextGetter(
70             base::MessageLoopProxy::current())),
71         download_manager_(&driver_, prefs_.get(), this) {
72     driver_.SetURLRequestContext(request_context_);
73   }
74 
LimitCache(size_t cache_size)75   void LimitCache(size_t cache_size) {
76     download_manager_.set_max_form_cache_size(cache_size);
77   }
78 
79   // AutofillDownloadManager::Observer implementation.
OnLoadedServerPredictions(const std::string & response_xml)80   virtual void OnLoadedServerPredictions(
81       const std::string& response_xml) OVERRIDE {
82     ResponseData response;
83     response.response = response_xml;
84     response.type_of_response = QUERY_SUCCESSFULL;
85     responses_.push_back(response);
86   }
87 
OnUploadedPossibleFieldTypes()88   virtual void OnUploadedPossibleFieldTypes() OVERRIDE {
89     ResponseData response;
90     response.type_of_response = UPLOAD_SUCCESSFULL;
91     responses_.push_back(response);
92   }
93 
OnServerRequestError(const std::string & form_signature,AutofillDownloadManager::RequestType request_type,int http_error)94   virtual void OnServerRequestError(
95       const std::string& form_signature,
96       AutofillDownloadManager::RequestType request_type,
97       int http_error) OVERRIDE {
98     ResponseData response;
99     response.signature = form_signature;
100     response.error = http_error;
101     response.type_of_response =
102         request_type == AutofillDownloadManager::REQUEST_QUERY ?
103             REQUEST_QUERY_FAILED : REQUEST_UPLOAD_FAILED;
104     responses_.push_back(response);
105   }
106 
107   enum ResponseType {
108     QUERY_SUCCESSFULL,
109     UPLOAD_SUCCESSFULL,
110     REQUEST_QUERY_FAILED,
111     REQUEST_UPLOAD_FAILED,
112   };
113 
114   struct ResponseData {
115     ResponseType type_of_response;
116     int error;
117     std::string signature;
118     std::string response;
119 
ResponseDataautofill::AutofillDownloadTest::ResponseData120     ResponseData() : type_of_response(REQUEST_QUERY_FAILED), error(0) {}
121   };
122 
123   base::MessageLoop message_loop_;
124   std::list<ResponseData> responses_;
125   scoped_ptr<PrefService> prefs_;
126   scoped_refptr<net::TestURLRequestContextGetter> request_context_;
127   TestAutofillDriver driver_;
128   AutofillDownloadManager download_manager_;
129 };
130 
TEST_F(AutofillDownloadTest,QueryAndUploadTest)131 TEST_F(AutofillDownloadTest, QueryAndUploadTest) {
132   // Create and register factory.
133   net::TestURLFetcherFactory factory;
134 
135   FormData form;
136   form.method = ASCIIToUTF16("post");
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 
TEST_F(AutofillDownloadTest,CacheQueryTest)342 TEST_F(AutofillDownloadTest, CacheQueryTest) {
343   // Create and register factory.
344   net::TestURLFetcherFactory factory;
345 
346   FormData form;
347   form.method = ASCIIToUTF16("post");
348 
349   FormFieldData field;
350   field.form_control_type = "text";
351 
352   field.label = ASCIIToUTF16("username");
353   field.name = ASCIIToUTF16("username");
354   form.fields.push_back(field);
355 
356   field.label = ASCIIToUTF16("First Name");
357   field.name = ASCIIToUTF16("firstname");
358   form.fields.push_back(field);
359 
360   field.label = ASCIIToUTF16("Last Name");
361   field.name = ASCIIToUTF16("lastname");
362   form.fields.push_back(field);
363 
364   FormStructure *form_structure = new FormStructure(form);
365   ScopedVector<FormStructure> form_structures0;
366   form_structures0.push_back(form_structure);
367 
368   // Add a slightly different form, which should result in a different request.
369   field.label = ASCIIToUTF16("email");
370   field.name = ASCIIToUTF16("email");
371   form.fields.push_back(field);
372   form_structure = new FormStructure(form);
373   ScopedVector<FormStructure> form_structures1;
374   form_structures1.push_back(form_structure);
375 
376   // Add another slightly different form, which should also result in a
377   // different request.
378   field.label = ASCIIToUTF16("email2");
379   field.name = ASCIIToUTF16("email2");
380   form.fields.push_back(field);
381   form_structure = new FormStructure(form);
382   ScopedVector<FormStructure> form_structures2;
383   form_structures2.push_back(form_structure);
384 
385   // Limit cache to two forms.
386   LimitCache(2);
387 
388   const char *responses[] = {
389     "<autofillqueryresponse>"
390       "<field autofilltype=\"0\" />"
391       "<field autofilltype=\"3\" />"
392       "<field autofilltype=\"5\" />"
393     "</autofillqueryresponse>",
394     "<autofillqueryresponse>"
395       "<field autofilltype=\"0\" />"
396       "<field autofilltype=\"3\" />"
397       "<field autofilltype=\"5\" />"
398       "<field autofilltype=\"9\" />"
399     "</autofillqueryresponse>",
400     "<autofillqueryresponse>"
401       "<field autofilltype=\"0\" />"
402       "<field autofilltype=\"3\" />"
403       "<field autofilltype=\"5\" />"
404       "<field autofilltype=\"9\" />"
405       "<field autofilltype=\"0\" />"
406     "</autofillqueryresponse>",
407   };
408 
409   // Request with id 0.
410   MockAutofillMetrics mock_metric_logger;
411   EXPECT_CALL(mock_metric_logger,
412               LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1);
413   EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures0.get(),
414                                                   mock_metric_logger));
415   // No responses yet
416   EXPECT_EQ(static_cast<size_t>(0), responses_.size());
417 
418   net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
419   ASSERT_TRUE(fetcher);
420   FakeOnURLFetchComplete(fetcher, 200, std::string(responses[0]));
421   ASSERT_EQ(static_cast<size_t>(1), responses_.size());
422   EXPECT_EQ(responses[0], responses_.front().response);
423 
424   responses_.clear();
425 
426   // No actual request - should be a cache hit.
427   EXPECT_CALL(mock_metric_logger,
428               LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1);
429   EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures0.get(),
430                                                   mock_metric_logger));
431   // Data is available immediately from cache - no over-the-wire trip.
432   ASSERT_EQ(static_cast<size_t>(1), responses_.size());
433   EXPECT_EQ(responses[0], responses_.front().response);
434   responses_.clear();
435 
436   // Request with id 1.
437   EXPECT_CALL(mock_metric_logger,
438               LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1);
439   EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures1.get(),
440                                                   mock_metric_logger));
441   // No responses yet
442   EXPECT_EQ(static_cast<size_t>(0), responses_.size());
443 
444   fetcher = factory.GetFetcherByID(1);
445   ASSERT_TRUE(fetcher);
446   FakeOnURLFetchComplete(fetcher, 200, std::string(responses[1]));
447   ASSERT_EQ(static_cast<size_t>(1), responses_.size());
448   EXPECT_EQ(responses[1], responses_.front().response);
449 
450   responses_.clear();
451 
452   // Request with id 2.
453   EXPECT_CALL(mock_metric_logger,
454               LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1);
455   EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures2.get(),
456                                                   mock_metric_logger));
457 
458   fetcher = factory.GetFetcherByID(2);
459   ASSERT_TRUE(fetcher);
460   FakeOnURLFetchComplete(fetcher, 200, std::string(responses[2]));
461   ASSERT_EQ(static_cast<size_t>(1), responses_.size());
462   EXPECT_EQ(responses[2], responses_.front().response);
463 
464   responses_.clear();
465 
466   // No actual requests - should be a cache hit.
467   EXPECT_CALL(mock_metric_logger,
468               LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1);
469   EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures1.get(),
470                                                   mock_metric_logger));
471 
472   EXPECT_CALL(mock_metric_logger,
473               LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1);
474   EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures2.get(),
475                                                   mock_metric_logger));
476 
477   ASSERT_EQ(static_cast<size_t>(2), responses_.size());
478   EXPECT_EQ(responses[1], responses_.front().response);
479   EXPECT_EQ(responses[2], responses_.back().response);
480   responses_.clear();
481 
482   // The first structure should've expired.
483   // Request with id 3.
484   EXPECT_CALL(mock_metric_logger,
485               LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1);
486   EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures0.get(),
487                                                   mock_metric_logger));
488   // No responses yet
489   EXPECT_EQ(static_cast<size_t>(0), responses_.size());
490 
491   fetcher = factory.GetFetcherByID(3);
492   ASSERT_TRUE(fetcher);
493   FakeOnURLFetchComplete(fetcher, 200, std::string(responses[0]));
494   ASSERT_EQ(static_cast<size_t>(1), responses_.size());
495   EXPECT_EQ(responses[0], responses_.front().response);
496 }
497 
498 }  // namespace autofill
499