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