1 // Copyright (c) 2015 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.
5 #include "chrome/browser/ui/autofill/card_unmask_prompt_controller_impl.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/test/histogram_tester.h"
12 #include "chrome/browser/autofill/risk_util.h"
13 #include "chrome/browser/ui/autofill/card_unmask_prompt_view.h"
14 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
15 #include "components/autofill/core/browser/autofill_client.h"
16 #include "components/autofill/core/browser/autofill_metrics.h"
17 #include "components/autofill/core/browser/autofill_test_utils.h"
18 #include "components/autofill/core/common/autofill_pref_names.h"
19 #include "components/user_prefs/user_prefs.h"
20 #include "content/public/browser/browser_context.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/test/test_utils.h"
26 using base::ASCIIToUTF16
;
28 class TestCardUnmaskDelegate
: public CardUnmaskDelegate
{
30 TestCardUnmaskDelegate() : weak_factory_(this) {}
32 virtual ~TestCardUnmaskDelegate() {}
34 // CardUnmaskDelegate implementation.
35 void OnUnmaskResponse(const UnmaskResponse
& response
) override
{
38 void OnUnmaskPromptClosed() override
{}
40 const UnmaskResponse
& response() { return response_
; }
42 base::WeakPtr
<TestCardUnmaskDelegate
> GetWeakPtr() {
43 return weak_factory_
.GetWeakPtr();
47 UnmaskResponse response_
;
48 base::WeakPtrFactory
<TestCardUnmaskDelegate
> weak_factory_
;
50 DISALLOW_COPY_AND_ASSIGN(TestCardUnmaskDelegate
);
53 class TestCardUnmaskPromptView
: public CardUnmaskPromptView
{
55 void ControllerGone() override
{}
56 void DisableAndWaitForVerification() override
{}
57 void GotVerificationResult(const base::string16
& error_message
,
58 bool allow_retry
) override
{}
61 class TestCardUnmaskPromptController
: public CardUnmaskPromptControllerImpl
{
63 TestCardUnmaskPromptController(
64 content::WebContents
* contents
,
65 TestCardUnmaskPromptView
* test_unmask_prompt_view
,
66 scoped_refptr
<content::MessageLoopRunner
> runner
)
67 : CardUnmaskPromptControllerImpl(contents
,
68 base::Bind(&LoadRiskData
, 0, contents
),
69 user_prefs::UserPrefs::Get(contents
->GetBrowserContext()), false),
70 test_unmask_prompt_view_(test_unmask_prompt_view
),
71 can_store_locally_(true),
73 weak_factory_(this) {}
75 CardUnmaskPromptView
* CreateAndShowView() override
{
76 return test_unmask_prompt_view_
;
78 void LoadRiskFingerprint() override
{
79 OnDidLoadRiskFingerprint("risk aversion");
81 bool CanStoreLocally() const override
{ return can_store_locally_
; }
83 void set_can_store_locally(bool can
) { can_store_locally_
= can
; }
85 base::WeakPtr
<TestCardUnmaskPromptController
> GetWeakPtr() {
86 return weak_factory_
.GetWeakPtr();
90 TestCardUnmaskPromptView
* test_unmask_prompt_view_
;
91 bool can_store_locally_
;
92 scoped_refptr
<content::MessageLoopRunner
> runner_
;
93 base::WeakPtrFactory
<TestCardUnmaskPromptController
> weak_factory_
;
95 DISALLOW_COPY_AND_ASSIGN(TestCardUnmaskPromptController
);
98 class CardUnmaskPromptControllerImplTest
99 : public ChromeRenderViewHostTestHarness
{
101 CardUnmaskPromptControllerImplTest() {}
102 ~CardUnmaskPromptControllerImplTest() override
{}
104 void SetUp() override
{
105 ChromeRenderViewHostTestHarness::SetUp();
106 test_unmask_prompt_view_
.reset(new TestCardUnmaskPromptView());
107 controller_
.reset(new TestCardUnmaskPromptController(
108 web_contents(), test_unmask_prompt_view_
.get(), runner_
));
109 delegate_
.reset(new TestCardUnmaskDelegate());
110 SetImportCheckboxState(false);
113 void TearDown() override
{
114 ChromeRenderViewHostTestHarness::TearDown();
118 controller_
->ShowPrompt(test::GetMaskedServerCard(),
119 delegate_
->GetWeakPtr());
122 void ShowPromptAmex() {
123 controller_
->ShowPrompt(test::GetMaskedServerCardAmex(),
124 delegate_
->GetWeakPtr());
127 void ShowPromptAndSimulateResponse(bool should_store_pan
) {
129 controller_
->OnUnmaskResponse(ASCIIToUTF16("444"),
131 ASCIIToUTF16("2015"),
135 user_prefs::UserPrefs::Get(web_contents()->GetBrowserContext())
136 ->GetBoolean(prefs::kAutofillWalletImportStorageCheckboxState
));
140 void SetImportCheckboxState(bool value
) {
141 user_prefs::UserPrefs::Get(web_contents()->GetBrowserContext())
142 ->SetBoolean(prefs::kAutofillWalletImportStorageCheckboxState
, value
);
145 // This member must outlive the controller.
146 scoped_refptr
<content::MessageLoopRunner
> runner_
;
148 scoped_ptr
<TestCardUnmaskPromptView
> test_unmask_prompt_view_
;
149 scoped_ptr
<TestCardUnmaskPromptController
> controller_
;
150 scoped_ptr
<TestCardUnmaskDelegate
> delegate_
;
153 DISALLOW_COPY_AND_ASSIGN(CardUnmaskPromptControllerImplTest
);
156 TEST_F(CardUnmaskPromptControllerImplTest
, LogShown
) {
157 base::HistogramTester histogram_tester
;
160 histogram_tester
.ExpectUniqueSample(
161 "Autofill.UnmaskPrompt.Events",
162 AutofillMetrics::UNMASK_PROMPT_SHOWN
, 1);
165 TEST_F(CardUnmaskPromptControllerImplTest
, LogClosedNoAttempts
) {
167 base::HistogramTester histogram_tester
;
168 controller_
->OnUnmaskDialogClosed();
170 histogram_tester
.ExpectBucketCount(
171 "Autofill.UnmaskPrompt.Events",
172 AutofillMetrics::UNMASK_PROMPT_CLOSED_NO_ATTEMPTS
, 1);
175 TEST_F(CardUnmaskPromptControllerImplTest
, LogClosedAbandonUnmasking
) {
176 ShowPromptAndSimulateResponse(false);
177 base::HistogramTester histogram_tester
;
179 controller_
->OnUnmaskDialogClosed();
181 histogram_tester
.ExpectBucketCount(
182 "Autofill.UnmaskPrompt.Events",
183 AutofillMetrics::UNMASK_PROMPT_CLOSED_ABANDON_UNMASKING
, 1);
186 TEST_F(CardUnmaskPromptControllerImplTest
, LogClosedFailedToUnmaskRetriable
) {
187 ShowPromptAndSimulateResponse(false);
188 controller_
->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE
);
189 base::HistogramTester histogram_tester
;
191 controller_
->OnUnmaskDialogClosed();
193 histogram_tester
.ExpectBucketCount(
194 "Autofill.UnmaskPrompt.Events",
196 ::UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_RETRIABLE_FAILURE
,
200 TEST_F(CardUnmaskPromptControllerImplTest
, LogClosedFailedToUnmaskNonRetriable
)
202 ShowPromptAndSimulateResponse(false);
203 controller_
->OnVerificationResult(AutofillClient::PERMANENT_FAILURE
);
204 base::HistogramTester histogram_tester
;
206 controller_
->OnUnmaskDialogClosed();
208 histogram_tester
.ExpectBucketCount(
209 "Autofill.UnmaskPrompt.Events",
211 ::UNMASK_PROMPT_CLOSED_FAILED_TO_UNMASK_NON_RETRIABLE_FAILURE
,
215 TEST_F(CardUnmaskPromptControllerImplTest
, LogUnmaskedCardFirstAttempt
) {
216 ShowPromptAndSimulateResponse(false);
217 base::HistogramTester histogram_tester
;
219 controller_
->OnVerificationResult(AutofillClient::SUCCESS
);
220 controller_
->OnUnmaskDialogClosed();
222 histogram_tester
.ExpectBucketCount(
223 "Autofill.UnmaskPrompt.Events",
224 AutofillMetrics::UNMASK_PROMPT_UNMASKED_CARD_FIRST_ATTEMPT
, 1);
227 TEST_F(CardUnmaskPromptControllerImplTest
, LogUnmaskedCardAfterFailure
) {
228 ShowPromptAndSimulateResponse(false);
229 controller_
->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE
);
230 controller_
->OnUnmaskResponse(ASCIIToUTF16("444"),
232 ASCIIToUTF16("2015"),
233 false /* should_store_pan */);
234 base::HistogramTester histogram_tester
;
236 controller_
->OnVerificationResult(AutofillClient::SUCCESS
);
237 controller_
->OnUnmaskDialogClosed();
239 histogram_tester
.ExpectBucketCount(
240 "Autofill.UnmaskPrompt.Events",
241 AutofillMetrics::UNMASK_PROMPT_UNMASKED_CARD_AFTER_FAILED_ATTEMPTS
, 1);
244 TEST_F(CardUnmaskPromptControllerImplTest
, LogSavedCardLocally
) {
245 ShowPromptAndSimulateResponse(true);
246 base::HistogramTester histogram_tester
;
248 controller_
->OnVerificationResult(AutofillClient::SUCCESS
);
249 controller_
->OnUnmaskDialogClosed();
251 histogram_tester
.ExpectBucketCount(
252 "Autofill.UnmaskPrompt.Events",
253 AutofillMetrics::UNMASK_PROMPT_SAVED_CARD_LOCALLY
, 1);
256 TEST_F(CardUnmaskPromptControllerImplTest
, LogDidOptIn
) {
257 SetImportCheckboxState(false);
258 ShowPromptAndSimulateResponse(true);
259 base::HistogramTester histogram_tester
;
260 controller_
->OnUnmaskDialogClosed();
262 histogram_tester
.ExpectBucketCount(
263 "Autofill.UnmaskPrompt.Events",
264 AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_IN
, 1);
267 TEST_F(CardUnmaskPromptControllerImplTest
, LogDidNotOptIn
) {
268 SetImportCheckboxState(false);
269 ShowPromptAndSimulateResponse(false);
270 base::HistogramTester histogram_tester
;
271 controller_
->OnUnmaskDialogClosed();
273 histogram_tester
.ExpectBucketCount(
274 "Autofill.UnmaskPrompt.Events",
275 AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_IN
, 1);
278 TEST_F(CardUnmaskPromptControllerImplTest
, LogDidOptOut
) {
279 SetImportCheckboxState(true);
280 ShowPromptAndSimulateResponse(false);
281 base::HistogramTester histogram_tester
;
282 controller_
->OnUnmaskDialogClosed();
284 histogram_tester
.ExpectBucketCount(
285 "Autofill.UnmaskPrompt.Events",
286 AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_OUT
, 1);
289 TEST_F(CardUnmaskPromptControllerImplTest
, LogDidNotOptOut
) {
290 SetImportCheckboxState(true);
291 ShowPromptAndSimulateResponse(true);
292 base::HistogramTester histogram_tester
;
293 controller_
->OnUnmaskDialogClosed();
295 histogram_tester
.ExpectBucketCount(
296 "Autofill.UnmaskPrompt.Events",
297 AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_OUT
, 1);
300 TEST_F(CardUnmaskPromptControllerImplTest
, DontLogForHiddenCheckbox
) {
301 controller_
->set_can_store_locally(false);
302 ShowPromptAndSimulateResponse(false);
303 base::HistogramTester histogram_tester
;
304 controller_
->OnUnmaskDialogClosed();
306 histogram_tester
.ExpectBucketCount(
307 "Autofill.UnmaskPrompt.Events",
308 AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_IN
, 0);
309 histogram_tester
.ExpectBucketCount(
310 "Autofill.UnmaskPrompt.Events",
311 AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_IN
, 0);
312 histogram_tester
.ExpectBucketCount(
313 "Autofill.UnmaskPrompt.Events",
314 AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_OPT_OUT
, 0);
315 histogram_tester
.ExpectBucketCount(
316 "Autofill.UnmaskPrompt.Events",
317 AutofillMetrics::UNMASK_PROMPT_LOCAL_SAVE_DID_NOT_OPT_OUT
, 0);
320 TEST_F(CardUnmaskPromptControllerImplTest
, LogDurationNoAttempts
) {
322 base::HistogramTester histogram_tester
;
324 controller_
->OnUnmaskDialogClosed();
326 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration", 1);
327 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration.NoAttempts",
331 TEST_F(CardUnmaskPromptControllerImplTest
, LogDurationAbandonUnmasking
) {
332 ShowPromptAndSimulateResponse(false);
333 base::HistogramTester histogram_tester
;
335 controller_
->OnUnmaskDialogClosed();
337 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration", 1);
338 histogram_tester
.ExpectTotalCount(
339 "Autofill.UnmaskPrompt.Duration.AbandonUnmasking", 1);
342 TEST_F(CardUnmaskPromptControllerImplTest
, LogDurationFailedToUnmaskRetriable
) {
343 ShowPromptAndSimulateResponse(false);
344 controller_
->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE
);
345 base::HistogramTester histogram_tester
;
347 controller_
->OnUnmaskDialogClosed();
349 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration", 1);
350 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration.Failure",
354 TEST_F(CardUnmaskPromptControllerImplTest
,
355 LogDurationFailedToUnmaskNonRetriable
) {
356 ShowPromptAndSimulateResponse(false);
357 controller_
->OnVerificationResult(AutofillClient::PERMANENT_FAILURE
);
358 base::HistogramTester histogram_tester
;
360 controller_
->OnUnmaskDialogClosed();
362 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration", 1);
363 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration.Failure",
367 TEST_F(CardUnmaskPromptControllerImplTest
, LogDurationCardFirstAttempt
) {
368 ShowPromptAndSimulateResponse(false);
369 base::HistogramTester histogram_tester
;
371 controller_
->OnVerificationResult(AutofillClient::SUCCESS
);
372 controller_
->OnUnmaskDialogClosed();
374 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration", 1);
375 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration.Success",
379 TEST_F(CardUnmaskPromptControllerImplTest
,
380 LogDurationUnmaskedCardAfterFailure
) {
381 ShowPromptAndSimulateResponse(false);
382 controller_
->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE
);
383 controller_
->OnUnmaskResponse(
384 base::ASCIIToUTF16("444"), base::ASCIIToUTF16("01"),
385 base::ASCIIToUTF16("2015"), false /* should_store_pan */);
386 base::HistogramTester histogram_tester
;
388 controller_
->OnVerificationResult(AutofillClient::SUCCESS
);
389 controller_
->OnUnmaskDialogClosed();
391 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration", 1);
392 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.Duration.Success",
396 TEST_F(CardUnmaskPromptControllerImplTest
, LogTimeBeforeAbandonUnmasking
) {
397 ShowPromptAndSimulateResponse(false);
398 base::HistogramTester histogram_tester
;
400 controller_
->OnUnmaskDialogClosed();
402 histogram_tester
.ExpectTotalCount(
403 "Autofill.UnmaskPrompt.TimeBeforeAbandonUnmasking", 1);
406 TEST_F(CardUnmaskPromptControllerImplTest
, LogRealPanResultSuccess
) {
407 ShowPromptAndSimulateResponse(false);
408 base::HistogramTester histogram_tester
;
409 controller_
->OnVerificationResult(AutofillClient::SUCCESS
);
411 histogram_tester
.ExpectBucketCount(
412 "Autofill.UnmaskPrompt.GetRealPanResult",
413 AutofillMetrics::GET_REAL_PAN_RESULT_SUCCESS
, 1);
416 TEST_F(CardUnmaskPromptControllerImplTest
, LogRealPanTryAgainFailure
) {
417 ShowPromptAndSimulateResponse(false);
418 base::HistogramTester histogram_tester
;
420 controller_
->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE
);
422 histogram_tester
.ExpectBucketCount(
423 "Autofill.UnmaskPrompt.GetRealPanResult",
424 AutofillMetrics::GET_REAL_PAN_RESULT_TRY_AGAIN_FAILURE
, 1);
427 TEST_F(CardUnmaskPromptControllerImplTest
, LogUnmaskingDurationResultSuccess
) {
428 ShowPromptAndSimulateResponse(false);
429 base::HistogramTester histogram_tester
;
431 controller_
->OnVerificationResult(AutofillClient::SUCCESS
);
433 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.UnmaskingDuration",
435 histogram_tester
.ExpectTotalCount(
436 "Autofill.UnmaskPrompt.UnmaskingDuration.Success", 1);
439 TEST_F(CardUnmaskPromptControllerImplTest
,
440 LogUnmaskingDurationTryAgainFailure
) {
441 ShowPromptAndSimulateResponse(false);
442 base::HistogramTester histogram_tester
;
444 controller_
->OnVerificationResult(AutofillClient::TRY_AGAIN_FAILURE
);
446 histogram_tester
.ExpectTotalCount("Autofill.UnmaskPrompt.UnmaskingDuration",
448 histogram_tester
.ExpectTotalCount(
449 "Autofill.UnmaskPrompt.UnmaskingDuration.Failure", 1);
452 TEST_F(CardUnmaskPromptControllerImplTest
, CvcInputValidation
) {
456 // null when |valid| is false.
457 const char* canonicalized_input
;
459 CvcCase cvc_cases
[] = {
460 { "123", true, "123" },
461 { "123 ", true, "123" },
468 for (size_t i
= 0; i
< arraysize(cvc_cases
); ++i
) {
469 EXPECT_EQ(cvc_cases
[i
].valid
,
470 controller_
->InputCvcIsValid(ASCIIToUTF16(cvc_cases
[i
].input
)));
471 if (!cvc_cases
[i
].valid
)
474 controller_
->OnUnmaskResponse(ASCIIToUTF16(cvc_cases
[i
].input
),
475 base::string16(), base::string16(), false);
476 EXPECT_EQ(ASCIIToUTF16(cvc_cases
[i
].canonicalized_input
),
477 delegate_
->response().cvc
);
480 CvcCase cvc_cases_amex
[] = {
483 { "1234", true, "1234" },
484 { "\t1234 ", true, "1234" },
485 { " 1234", true, "1234" },
491 for (size_t i
= 0; i
< arraysize(cvc_cases_amex
); ++i
) {
493 cvc_cases_amex
[i
].valid
,
494 controller_
->InputCvcIsValid(ASCIIToUTF16(cvc_cases_amex
[i
].input
)));
495 if (!cvc_cases_amex
[i
].valid
)
498 controller_
->OnUnmaskResponse(ASCIIToUTF16(cvc_cases_amex
[i
].input
),
499 base::string16(), base::string16(), false);
500 EXPECT_EQ(ASCIIToUTF16(cvc_cases_amex
[i
].canonicalized_input
),
501 delegate_
->response().cvc
);
505 TEST_F(CardUnmaskPromptControllerImplTest
, ExpirationDateValidation
) {
507 const char* input_month
;
508 const char* input_year
;
511 {"01", "2040", true},
515 {"01", "1940", false},
516 {"13", "2040", false},
521 for (size_t i
= 0; i
< arraysize(exp_cases
); ++i
) {
522 EXPECT_EQ(exp_cases
[i
].valid
, controller_
->InputExpirationIsValid(
523 ASCIIToUTF16(exp_cases
[i
].input_month
),
524 ASCIIToUTF16(exp_cases
[i
].input_year
)));
528 } // namespace autofill