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
25 using webkit_glue::FormData;
26 using WebKit::WebInputElement;
27
28 namespace {
29
30 class MockAutofillMetrics : public AutofillMetrics {
31 public:
MockAutofillMetrics()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.
49 class AutofillDownloadTestHelper : public AutofillDownloadManager::Observer {
50 public:
AutofillDownloadTestHelper()51 AutofillDownloadTestHelper()
52 : download_manager(&profile),
53 request_context_getter(new TestURLRequestContextGetter()) {
54 download_manager.SetObserver(this);
55 }
~AutofillDownloadTestHelper()56 ~AutofillDownloadTestHelper() {
57 Profile::set_default_request_context(NULL);
58 download_manager.SetObserver(NULL);
59 }
60
InitContextGetter()61 void InitContextGetter() {
62 Profile::set_default_request_context(request_context_getter.get());
63 }
64
LimitCache(size_t cache_size)65 void LimitCache(size_t cache_size) {
66 download_manager.set_max_form_cache_size(cache_size);
67 }
68
69 // AutofillDownloadManager::Observer overridables:
OnLoadedAutofillHeuristics(const std::string & heuristic_xml)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 };
OnUploadedAutofillHeuristics(const std::string & form_signature)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 }
OnHeuristicsRequestError(const std::string & form_signature,AutofillDownloadManager::AutofillRequestType request_type,int http_error)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;
ResponseDataAutofillDownloadTestHelper::ResponseData107 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
117 typedef TestingBrowserProcessTest AutofillDownloadTest;
118
TEST_F(AutofillDownloadTest,QueryAndUploadTest)119 TEST_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
TEST_F(AutofillDownloadTest,CacheQueryTest)362 TEST_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