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