OLD | NEW |
| (Empty) |
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: | |
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. | |
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: | |
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 | |
75 void LimitCache(size_t cache_size) { | |
76 download_manager_.set_max_form_cache_size(cache_size); | |
77 } | |
78 | |
79 // AutofillDownloadManager::Observer implementation. | |
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 | |
88 virtual void OnUploadedPossibleFieldTypes() OVERRIDE { | |
89 ResponseData response; | |
90 response.type_of_response = UPLOAD_SUCCESSFULL; | |
91 responses_.push_back(response); | |
92 } | |
93 | |
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 | |
120 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 | |
131 TEST_F(AutofillDownloadTest, QueryAndUploadTest) { | |
132 // Create and register factory. | |
133 net::TestURLFetcherFactory factory; | |
134 | |
135 FormData form; | |
136 | |
137 FormFieldData field; | |
138 field.label = ASCIIToUTF16("username"); | |
139 field.name = ASCIIToUTF16("username"); | |
140 field.form_control_type = "text"; | |
141 form.fields.push_back(field); | |
142 | |
143 field.label = ASCIIToUTF16("First Name"); | |
144 field.name = ASCIIToUTF16("firstname"); | |
145 field.form_control_type = "text"; | |
146 form.fields.push_back(field); | |
147 | |
148 field.label = ASCIIToUTF16("Last Name"); | |
149 field.name = ASCIIToUTF16("lastname"); | |
150 field.form_control_type = "text"; | |
151 form.fields.push_back(field); | |
152 | |
153 field.label = ASCIIToUTF16("email"); | |
154 field.name = ASCIIToUTF16("email"); | |
155 field.form_control_type = "text"; | |
156 form.fields.push_back(field); | |
157 | |
158 field.label = ASCIIToUTF16("email2"); | |
159 field.name = ASCIIToUTF16("email2"); | |
160 field.form_control_type = "text"; | |
161 form.fields.push_back(field); | |
162 | |
163 field.label = ASCIIToUTF16("password"); | |
164 field.name = ASCIIToUTF16("password"); | |
165 field.form_control_type = "password"; | |
166 form.fields.push_back(field); | |
167 | |
168 field.label = base::string16(); | |
169 field.name = ASCIIToUTF16("Submit"); | |
170 field.form_control_type = "submit"; | |
171 form.fields.push_back(field); | |
172 | |
173 FormStructure *form_structure = new FormStructure(form); | |
174 ScopedVector<FormStructure> form_structures; | |
175 form_structures.push_back(form_structure); | |
176 | |
177 form.fields.clear(); | |
178 | |
179 field.label = ASCIIToUTF16("address"); | |
180 field.name = ASCIIToUTF16("address"); | |
181 field.form_control_type = "text"; | |
182 form.fields.push_back(field); | |
183 | |
184 field.label = ASCIIToUTF16("address2"); | |
185 field.name = ASCIIToUTF16("address2"); | |
186 field.form_control_type = "text"; | |
187 form.fields.push_back(field); | |
188 | |
189 field.label = ASCIIToUTF16("city"); | |
190 field.name = ASCIIToUTF16("city"); | |
191 field.form_control_type = "text"; | |
192 form.fields.push_back(field); | |
193 | |
194 field.label = base::string16(); | |
195 field.name = ASCIIToUTF16("Submit"); | |
196 field.form_control_type = "submit"; | |
197 form.fields.push_back(field); | |
198 | |
199 form_structure = new FormStructure(form); | |
200 form_structures.push_back(form_structure); | |
201 | |
202 // Request with id 0. | |
203 MockAutofillMetrics mock_metric_logger; | |
204 EXPECT_CALL(mock_metric_logger, | |
205 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); | |
206 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures.get(), | |
207 mock_metric_logger)); | |
208 // Set upload to 100% so requests happen. | |
209 download_manager_.SetPositiveUploadRate(1.0); | |
210 download_manager_.SetNegativeUploadRate(1.0); | |
211 // Request with id 1. | |
212 EXPECT_TRUE(download_manager_.StartUploadRequest( | |
213 *(form_structures[0]), true, ServerFieldTypeSet())); | |
214 // Request with id 2. | |
215 EXPECT_TRUE(download_manager_.StartUploadRequest( | |
216 *(form_structures[1]), false, ServerFieldTypeSet())); | |
217 | |
218 const char *responses[] = { | |
219 "<autofillqueryresponse>" | |
220 "<field autofilltype=\"0\" />" | |
221 "<field autofilltype=\"3\" />" | |
222 "<field autofilltype=\"5\" />" | |
223 "<field autofilltype=\"9\" />" | |
224 "<field autofilltype=\"0\" />" | |
225 "<field autofilltype=\"30\" />" | |
226 "<field autofilltype=\"31\" />" | |
227 "<field autofilltype=\"33\" />" | |
228 "</autofillqueryresponse>", | |
229 "<autofilluploadresponse positiveuploadrate=\"0.5\" " | |
230 "negativeuploadrate=\"0.3\"/>", | |
231 "<html></html>", | |
232 }; | |
233 | |
234 // Return them out of sequence. | |
235 net::TestURLFetcher* fetcher = factory.GetFetcherByID(1); | |
236 ASSERT_TRUE(fetcher); | |
237 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[1])); | |
238 | |
239 // After that upload rates would be adjusted to 0.5/0.3 | |
240 EXPECT_DOUBLE_EQ(0.5, download_manager_.GetPositiveUploadRate()); | |
241 EXPECT_DOUBLE_EQ(0.3, download_manager_.GetNegativeUploadRate()); | |
242 | |
243 fetcher = factory.GetFetcherByID(2); | |
244 ASSERT_TRUE(fetcher); | |
245 FakeOnURLFetchComplete(fetcher, 404, std::string(responses[2])); | |
246 | |
247 fetcher = factory.GetFetcherByID(0); | |
248 ASSERT_TRUE(fetcher); | |
249 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[0])); | |
250 EXPECT_EQ(static_cast<size_t>(3), responses_.size()); | |
251 | |
252 EXPECT_EQ(AutofillDownloadTest::UPLOAD_SUCCESSFULL, | |
253 responses_.front().type_of_response); | |
254 EXPECT_EQ(0, responses_.front().error); | |
255 EXPECT_EQ(std::string(), responses_.front().signature); | |
256 // Expected response on non-query request is an empty string. | |
257 EXPECT_EQ(std::string(), responses_.front().response); | |
258 responses_.pop_front(); | |
259 | |
260 EXPECT_EQ(AutofillDownloadTest::REQUEST_UPLOAD_FAILED, | |
261 responses_.front().type_of_response); | |
262 EXPECT_EQ(404, responses_.front().error); | |
263 EXPECT_EQ(form_structures[1]->FormSignature(), | |
264 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(responses_.front().type_of_response, | |
270 AutofillDownloadTest::QUERY_SUCCESSFULL); | |
271 EXPECT_EQ(0, responses_.front().error); | |
272 EXPECT_EQ(std::string(), responses_.front().signature); | |
273 EXPECT_EQ(responses[0], responses_.front().response); | |
274 responses_.pop_front(); | |
275 | |
276 // Set upload to 0% so no new requests happen. | |
277 download_manager_.SetPositiveUploadRate(0.0); | |
278 download_manager_.SetNegativeUploadRate(0.0); | |
279 // No actual requests for the next two calls, as we set upload rate to 0%. | |
280 EXPECT_FALSE(download_manager_.StartUploadRequest( | |
281 *(form_structures[0]), true, ServerFieldTypeSet())); | |
282 EXPECT_FALSE(download_manager_.StartUploadRequest( | |
283 *(form_structures[1]), false, ServerFieldTypeSet())); | |
284 fetcher = factory.GetFetcherByID(3); | |
285 EXPECT_EQ(NULL, fetcher); | |
286 | |
287 // Modify form structures to miss the cache. | |
288 field.label = ASCIIToUTF16("Address line 2"); | |
289 field.name = ASCIIToUTF16("address2"); | |
290 field.form_control_type = "text"; | |
291 form.fields.push_back(field); | |
292 form_structure = new FormStructure(form); | |
293 form_structures.push_back(form_structure); | |
294 | |
295 // Request with id 3. | |
296 EXPECT_CALL(mock_metric_logger, | |
297 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); | |
298 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures.get(), | |
299 mock_metric_logger)); | |
300 fetcher = factory.GetFetcherByID(3); | |
301 ASSERT_TRUE(fetcher); | |
302 fetcher->set_backoff_delay(TestTimeouts::action_max_timeout()); | |
303 FakeOnURLFetchComplete(fetcher, 500, std::string(responses[0])); | |
304 | |
305 EXPECT_EQ(AutofillDownloadTest::REQUEST_QUERY_FAILED, | |
306 responses_.front().type_of_response); | |
307 EXPECT_EQ(500, responses_.front().error); | |
308 // Expected response on non-query request is an empty string. | |
309 EXPECT_EQ(std::string(), responses_.front().response); | |
310 responses_.pop_front(); | |
311 | |
312 // Query requests should be ignored for the next 10 seconds. | |
313 EXPECT_CALL(mock_metric_logger, | |
314 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(0); | |
315 EXPECT_FALSE(download_manager_.StartQueryRequest(form_structures.get(), | |
316 mock_metric_logger)); | |
317 fetcher = factory.GetFetcherByID(4); | |
318 EXPECT_EQ(NULL, fetcher); | |
319 | |
320 // Set upload required to true so requests happen. | |
321 form_structures[0]->upload_required_ = UPLOAD_REQUIRED; | |
322 // Request with id 4. | |
323 EXPECT_TRUE(download_manager_.StartUploadRequest( | |
324 *(form_structures[0]), true, ServerFieldTypeSet())); | |
325 fetcher = factory.GetFetcherByID(4); | |
326 ASSERT_TRUE(fetcher); | |
327 fetcher->set_backoff_delay(TestTimeouts::action_max_timeout()); | |
328 FakeOnURLFetchComplete(fetcher, 503, std::string(responses[2])); | |
329 EXPECT_EQ(AutofillDownloadTest::REQUEST_UPLOAD_FAILED, | |
330 responses_.front().type_of_response); | |
331 EXPECT_EQ(503, responses_.front().error); | |
332 responses_.pop_front(); | |
333 | |
334 // Upload requests should be ignored for the next 10 seconds. | |
335 EXPECT_FALSE(download_manager_.StartUploadRequest( | |
336 *(form_structures[0]), true, ServerFieldTypeSet())); | |
337 fetcher = factory.GetFetcherByID(5); | |
338 EXPECT_EQ(NULL, fetcher); | |
339 } | |
340 | |
341 TEST_F(AutofillDownloadTest, CacheQueryTest) { | |
342 // Create and register factory. | |
343 net::TestURLFetcherFactory factory; | |
344 | |
345 FormData form; | |
346 | |
347 FormFieldData field; | |
348 field.form_control_type = "text"; | |
349 | |
350 field.label = ASCIIToUTF16("username"); | |
351 field.name = ASCIIToUTF16("username"); | |
352 form.fields.push_back(field); | |
353 | |
354 field.label = ASCIIToUTF16("First Name"); | |
355 field.name = ASCIIToUTF16("firstname"); | |
356 form.fields.push_back(field); | |
357 | |
358 field.label = ASCIIToUTF16("Last Name"); | |
359 field.name = ASCIIToUTF16("lastname"); | |
360 form.fields.push_back(field); | |
361 | |
362 FormStructure *form_structure = new FormStructure(form); | |
363 ScopedVector<FormStructure> form_structures0; | |
364 form_structures0.push_back(form_structure); | |
365 | |
366 // Add a slightly different form, which should result in a different request. | |
367 field.label = ASCIIToUTF16("email"); | |
368 field.name = ASCIIToUTF16("email"); | |
369 form.fields.push_back(field); | |
370 form_structure = new FormStructure(form); | |
371 ScopedVector<FormStructure> form_structures1; | |
372 form_structures1.push_back(form_structure); | |
373 | |
374 // Add another slightly different form, which should also result in a | |
375 // different request. | |
376 field.label = ASCIIToUTF16("email2"); | |
377 field.name = ASCIIToUTF16("email2"); | |
378 form.fields.push_back(field); | |
379 form_structure = new FormStructure(form); | |
380 ScopedVector<FormStructure> form_structures2; | |
381 form_structures2.push_back(form_structure); | |
382 | |
383 // Limit cache to two forms. | |
384 LimitCache(2); | |
385 | |
386 const char *responses[] = { | |
387 "<autofillqueryresponse>" | |
388 "<field autofilltype=\"0\" />" | |
389 "<field autofilltype=\"3\" />" | |
390 "<field autofilltype=\"5\" />" | |
391 "</autofillqueryresponse>", | |
392 "<autofillqueryresponse>" | |
393 "<field autofilltype=\"0\" />" | |
394 "<field autofilltype=\"3\" />" | |
395 "<field autofilltype=\"5\" />" | |
396 "<field autofilltype=\"9\" />" | |
397 "</autofillqueryresponse>", | |
398 "<autofillqueryresponse>" | |
399 "<field autofilltype=\"0\" />" | |
400 "<field autofilltype=\"3\" />" | |
401 "<field autofilltype=\"5\" />" | |
402 "<field autofilltype=\"9\" />" | |
403 "<field autofilltype=\"0\" />" | |
404 "</autofillqueryresponse>", | |
405 }; | |
406 | |
407 // Request with id 0. | |
408 MockAutofillMetrics mock_metric_logger; | |
409 EXPECT_CALL(mock_metric_logger, | |
410 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); | |
411 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures0.get(), | |
412 mock_metric_logger)); | |
413 // No responses yet | |
414 EXPECT_EQ(static_cast<size_t>(0), responses_.size()); | |
415 | |
416 net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); | |
417 ASSERT_TRUE(fetcher); | |
418 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[0])); | |
419 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); | |
420 EXPECT_EQ(responses[0], responses_.front().response); | |
421 | |
422 responses_.clear(); | |
423 | |
424 // No actual request - should be a cache hit. | |
425 EXPECT_CALL(mock_metric_logger, | |
426 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); | |
427 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures0.get(), | |
428 mock_metric_logger)); | |
429 // Data is available immediately from cache - no over-the-wire trip. | |
430 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); | |
431 EXPECT_EQ(responses[0], responses_.front().response); | |
432 responses_.clear(); | |
433 | |
434 // Request with id 1. | |
435 EXPECT_CALL(mock_metric_logger, | |
436 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); | |
437 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures1.get(), | |
438 mock_metric_logger)); | |
439 // No responses yet | |
440 EXPECT_EQ(static_cast<size_t>(0), responses_.size()); | |
441 | |
442 fetcher = factory.GetFetcherByID(1); | |
443 ASSERT_TRUE(fetcher); | |
444 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[1])); | |
445 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); | |
446 EXPECT_EQ(responses[1], responses_.front().response); | |
447 | |
448 responses_.clear(); | |
449 | |
450 // Request with id 2. | |
451 EXPECT_CALL(mock_metric_logger, | |
452 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); | |
453 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures2.get(), | |
454 mock_metric_logger)); | |
455 | |
456 fetcher = factory.GetFetcherByID(2); | |
457 ASSERT_TRUE(fetcher); | |
458 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[2])); | |
459 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); | |
460 EXPECT_EQ(responses[2], responses_.front().response); | |
461 | |
462 responses_.clear(); | |
463 | |
464 // No actual requests - should be a cache hit. | |
465 EXPECT_CALL(mock_metric_logger, | |
466 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); | |
467 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures1.get(), | |
468 mock_metric_logger)); | |
469 | |
470 EXPECT_CALL(mock_metric_logger, | |
471 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); | |
472 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures2.get(), | |
473 mock_metric_logger)); | |
474 | |
475 ASSERT_EQ(static_cast<size_t>(2), responses_.size()); | |
476 EXPECT_EQ(responses[1], responses_.front().response); | |
477 EXPECT_EQ(responses[2], responses_.back().response); | |
478 responses_.clear(); | |
479 | |
480 // The first structure should've expired. | |
481 // Request with id 3. | |
482 EXPECT_CALL(mock_metric_logger, | |
483 LogServerQueryMetric(AutofillMetrics::QUERY_SENT)).Times(1); | |
484 EXPECT_TRUE(download_manager_.StartQueryRequest(form_structures0.get(), | |
485 mock_metric_logger)); | |
486 // No responses yet | |
487 EXPECT_EQ(static_cast<size_t>(0), responses_.size()); | |
488 | |
489 fetcher = factory.GetFetcherByID(3); | |
490 ASSERT_TRUE(fetcher); | |
491 FakeOnURLFetchComplete(fetcher, 200, std::string(responses[0])); | |
492 ASSERT_EQ(static_cast<size_t>(1), responses_.size()); | |
493 EXPECT_EQ(responses[0], responses_.front().response); | |
494 } | |
495 | |
496 } // namespace autofill | |
OLD | NEW |