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