chromium/components/autofill/core/browser/payments/mandatory_reauth_manager_unittest.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/autofill/core/browser/payments/mandatory_reauth_manager.h"

#include "base/memory/scoped_refptr.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/payments_data_manager.h"
#include "components/autofill/core/browser/test_autofill_client.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "components/device_reauth/mock_device_authenticator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

#if BUILDFLAG(IS_ANDROID)
#include "base/android/build_info.h"
#endif

namespace autofill::payments {

using autofill_metrics::MandatoryReauthOfferOptInDecision;

class MandatoryReauthManagerTest : public testing::Test {
 public:
  void SetUp() override {
    autofill_client_ = std::make_unique<TestAutofillClient>();
    std::unique_ptr<device_reauth::MockDeviceAuthenticator>
        mock_device_authenticator =
            std::make_unique<device_reauth::MockDeviceAuthenticator>();

    ON_CALL(*mock_device_authenticator,
            CanAuthenticateWithBiometricOrScreenLock)
        .WillByDefault(testing::Return(true));

    autofill_client_->SetDeviceAuthenticator(
        std::move(mock_device_authenticator));
    mandatory_reauth_manager_ =
        std::make_unique<MandatoryReauthManager>(autofill_client_.get());
    autofill_client_->GetPersonalDataManager()->SetPrefService(
        autofill_client_->GetPrefs());
    test::SetCreditCardInfo(&server_card_, "Test User", "1111" /* Visa */,
                            test::NextMonth().c_str(), test::NextYear().c_str(),
                            "1");
  }

  device_reauth::MockDeviceAuthenticator& device_authenticator() {
    return *static_cast<device_reauth::MockDeviceAuthenticator*>(
        mandatory_reauth_manager_->GetDeviceAuthenticatorPtrForTesting());
  }

 protected:
  void ExpectUniqueOfferOptInDecision(
      MandatoryReauthOfferOptInDecision opt_in_decision) {
    histogram_tester_.ExpectUniqueSample(
        "Autofill.PaymentMethods.MandatoryReauth.CheckoutFlow."
        "ReauthOfferOptInDecision2",
        opt_in_decision, 1);
  }

  base::test::TaskEnvironment task_environment_;
  std::unique_ptr<TestAutofillClient> autofill_client_;
  std::unique_ptr<MandatoryReauthManager> mandatory_reauth_manager_;
  base::HistogramTester histogram_tester_;
  CreditCard local_card_ = test::GetCreditCard();
  CreditCard server_card_ = test::GetMaskedServerCard();
  CreditCard virtual_card_ = test::GetVirtualCard();
};

// Test that `MandatoryReauthManager::Authenticate()` triggers
// `DeviceAuthenticator::AuthenticateWithMessage()`.
TEST_F(MandatoryReauthManagerTest, Authenticate) {
  EXPECT_CALL(device_authenticator(), AuthenticateWithMessage).Times(1);

  mandatory_reauth_manager_->Authenticate(
      /*callback=*/base::DoNothing());
}

// Test that `MandatoryReauthManager::AuthenticateWithMessage()` triggers
// `DeviceAuthenticator::AuthenticateWithMessage()`.
TEST_F(MandatoryReauthManagerTest, AuthenticateWithMessage) {
  EXPECT_CALL(device_authenticator(), AuthenticateWithMessage).Times(1);

  mandatory_reauth_manager_->AuthenticateWithMessage(
      /*message=*/u"Test", /*callback=*/base::DoNothing());
}

TEST_F(MandatoryReauthManagerTest, GetAuthenticationMethod_Biometric) {
  ON_CALL(device_authenticator(), CanAuthenticateWithBiometrics)
      .WillByDefault(testing::Return(true));

  EXPECT_EQ(mandatory_reauth_manager_->GetAuthenticationMethod(),
            MandatoryReauthAuthenticationMethod::kBiometric);
}

TEST_F(MandatoryReauthManagerTest, GetAuthenticationMethod_ScreenLock) {
  ON_CALL(device_authenticator(), CanAuthenticateWithBiometrics)
      .WillByDefault(testing::Return(false));
  ON_CALL(device_authenticator(), CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(testing::Return(true));

  EXPECT_EQ(mandatory_reauth_manager_->GetAuthenticationMethod(),
            MandatoryReauthAuthenticationMethod::kScreenLock);
}

TEST_F(MandatoryReauthManagerTest, GetAuthenticationMethod_UnsupportedMethod) {
  ON_CALL(device_authenticator(), CanAuthenticateWithBiometrics)
      .WillByDefault(testing::Return(false));
  ON_CALL(device_authenticator(), CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(testing::Return(false));

  EXPECT_EQ(mandatory_reauth_manager_->GetAuthenticationMethod(),
            MandatoryReauthAuthenticationMethod::kUnsupportedMethod);
}

// Test that the MandatoryReauthManager returns that we should offer re-auth
// opt-in if the conditions for offering it are all met for local cards.
TEST_F(MandatoryReauthManagerTest, ShouldOfferOptin_LocalCard) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  autofill_client_->GetPersonalDataManager()
      ->payments_data_manager()
      .AddCreditCard(local_card_);

  EXPECT_TRUE(mandatory_reauth_manager_->ShouldOfferOptin(
      NonInteractivePaymentMethodType::kLocalCard));
  ExpectUniqueOfferOptInDecision(MandatoryReauthOfferOptInDecision::kOffered);
}

// Test that the MandatoryReauthManager returns that we should not offer re-auth
// opt-in if the conditions for offering it are all met but we are in off the
// record mode.
TEST_F(MandatoryReauthManagerTest, ShouldOfferOptin_Incognito) {
  autofill_client_->GetPersonalDataManager()
      ->payments_data_manager()
      .AddCreditCard(local_card_);

  autofill_client_->set_is_off_the_record(true);

  EXPECT_FALSE(mandatory_reauth_manager_->ShouldOfferOptin(
      NonInteractivePaymentMethodType::kLocalCard));
  ExpectUniqueOfferOptInDecision(
      MandatoryReauthOfferOptInDecision::kIncognitoMode);
}

// Test that the MandatoryReauthManager returns that we should offer re-auth
// opt-in if the conditions for offering it are all met for virtual cards.
TEST_F(MandatoryReauthManagerTest, ShouldOfferOptin_VirtualCard) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  EXPECT_TRUE(mandatory_reauth_manager_->ShouldOfferOptin(
      NonInteractivePaymentMethodType::kVirtualCard));
  ExpectUniqueOfferOptInDecision(MandatoryReauthOfferOptInDecision::kOffered);
}

// Test that the MandatoryReauthManager returns that we should offer re-auth
// opt-in if the conditions for offering it are all met for masked server cards.
TEST_F(MandatoryReauthManagerTest, ShouldOfferOptin_MaskedServerCard) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  EXPECT_TRUE(mandatory_reauth_manager_->ShouldOfferOptin(
      NonInteractivePaymentMethodType::kMaskedServerCard));
  ExpectUniqueOfferOptInDecision(MandatoryReauthOfferOptInDecision::kOffered);
}

// Test that the MandatoryReauthManager returns that we should not offer re-auth
// opt-in if the user has already made a decision on opting in or out of
// re-auth.
TEST_F(MandatoryReauthManagerTest, ShouldOfferOptin_UserAlreadyMadeDecision) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  mandatory_reauth_manager_->OnUserCancelledOptInPrompt();

  autofill_client_->GetPersonalDataManager()
      ->payments_data_manager()
      .AddCreditCard(local_card_);

  EXPECT_FALSE(mandatory_reauth_manager_->ShouldOfferOptin(
      NonInteractivePaymentMethodType::kLocalCard));
  EXPECT_TRUE(autofill_client_->GetPrefs()->GetUserPrefValue(
      prefs::kAutofillPaymentMethodsMandatoryReauth));
}

// Test that the MandatoryReauthManager returns that we should not offer re-auth
// opt-in if authentication is not available on the device.
TEST_F(MandatoryReauthManagerTest,
       ShouldOfferOptin_AuthenticationNotAvailable) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  ON_CALL(device_authenticator(), CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(testing::Return(false));

  autofill_client_->GetPersonalDataManager()
      ->payments_data_manager()
      .AddCreditCard(local_card_);

  EXPECT_FALSE(mandatory_reauth_manager_->ShouldOfferOptin(
      NonInteractivePaymentMethodType::kLocalCard));
  ExpectUniqueOfferOptInDecision(
      MandatoryReauthOfferOptInDecision::kNoSupportedReauthMethod);
}

// Test that the MandatoryReauthManager returns that we should not offer re-auth
// opt-in if the conditions for offering re-auth are met, but the most recent
// filled card went through interactive authentication (or no card was
// autofilled at all).
TEST_F(
    MandatoryReauthManagerTest,
    ShouldOfferOptin_FilledCardWentThroughInteractiveAuthenticationOrNoAutofill) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  autofill_client_->GetPersonalDataManager()
      ->payments_data_manager()
      .AddCreditCard(local_card_);

  // 'card_identifier_if_non_interactive_authentication_flow_completed' is not
  // present, implying interactive authentication happened.
  EXPECT_FALSE(mandatory_reauth_manager_->ShouldOfferOptin(std::nullopt));
  ExpectUniqueOfferOptInDecision(
      MandatoryReauthOfferOptInDecision::kWentThroughInteractiveAuthentication);
}

// Test that the MandatoryReauthManager returns that we should offer re-auth
// opt-in if we have a matching local card for a server card extracted from the
// form, and the matching local card was the last filled card. This also tests
// that the metrics logged correctly.
TEST_F(
    MandatoryReauthManagerTest,
    ShouldOfferOptin_ServerCardWithMatchingLocalCard_LastFilledCardWasLocalCard) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  autofill_client_->GetPersonalDataManager()
      ->payments_data_manager()
      .AddCreditCard(local_card_);

  // Test that if the last filled card is the matching local card, we offer
  // re-auth opt-in.
  EXPECT_TRUE(mandatory_reauth_manager_->ShouldOfferOptin(
      NonInteractivePaymentMethodType::kLocalCard));
  ExpectUniqueOfferOptInDecision(MandatoryReauthOfferOptInDecision::kOffered);
}

// Test that starting the re-auth opt-in flow will trigger the re-auth opt-in
// prompt to be shown.
TEST_F(MandatoryReauthManagerTest, StartOptInFlow) {
  mandatory_reauth_manager_->StartOptInFlow();
  EXPECT_TRUE(autofill_client_->GetPaymentsAutofillClient()
                  ->GetMandatoryReauthOptInPromptWasShown());
}

// Test that the MandatoryReauthManager correctly handles the case where the
// user accepts the re-auth prompt.
TEST_F(MandatoryReauthManagerTest, OnUserAcceptedOptInPrompt) {
#if BUILDFLAG(IS_ANDROID)
  // Opt-in prompts are not shown on automotive as mandatory reauth is always
  // enabled.
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  ON_CALL(device_authenticator(), AuthenticateWithMessage)
      .WillByDefault(
          testing::WithArg<1>([](base::OnceCallback<void(bool)> callback) {
            std::move(callback).Run(false);
          }));

  // We need to call `StartOptInFlow()` here to ensure the device
  // authenticator gets set.
  static_cast<MandatoryReauthManager*>(mandatory_reauth_manager_.get())
      ->StartOptInFlow();
  mandatory_reauth_manager_->OnUserAcceptedOptInPrompt();

  EXPECT_FALSE(autofill_client_->GetPrefs()->GetBoolean(
      prefs::kAutofillPaymentMethodsMandatoryReauth));
  EXPECT_FALSE(autofill_client_->GetPaymentsAutofillClient()
                   ->GetMandatoryReauthOptInPromptWasReshown());
  // Counter is increased by 1 since device authentication fails during opt in.
  EXPECT_EQ(autofill_client_->GetPrefs()->GetInteger(
                prefs::kAutofillPaymentMethodsMandatoryReauthPromoShownCounter),
            1);

  auto mock_device_authenticator2 =
      std::make_unique<device_reauth::MockDeviceAuthenticator>();

  mandatory_reauth_manager_->SetDeviceAuthenticatorPtrForTesting(
      std::move(mock_device_authenticator2));

  ON_CALL(device_authenticator(), AuthenticateWithMessage)
      .WillByDefault(
          testing::WithArg<1>([](base::OnceCallback<void(bool)> callback) {
            std::move(callback).Run(true);
          }));

  // We need to call `StartOptInFlow()` here to ensure the device
  // authenticator gets set.
  static_cast<MandatoryReauthManager*>(mandatory_reauth_manager_.get())
      ->StartOptInFlow();
  mandatory_reauth_manager_->OnUserAcceptedOptInPrompt();

  EXPECT_TRUE(autofill_client_->GetPrefs()->GetBoolean(
      prefs::kAutofillPaymentMethodsMandatoryReauth));
  EXPECT_TRUE(autofill_client_->GetPaymentsAutofillClient()
                  ->GetMandatoryReauthOptInPromptWasReshown());
  EXPECT_TRUE(autofill_client_->GetPrefs()->GetUserPrefValue(
      prefs::kAutofillPaymentMethodsMandatoryReauth));
}

// Test that the MandatoryReauthManager correctly handles the case where the
// user cancels the re-auth prompt.
TEST_F(MandatoryReauthManagerTest, OnUserCancelledOptInPrompt) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  EXPECT_FALSE(autofill_client_->GetPrefs()->GetUserPrefValue(
      prefs::kAutofillPaymentMethodsMandatoryReauth));

  mandatory_reauth_manager_->OnUserCancelledOptInPrompt();

  EXPECT_TRUE(autofill_client_->GetPrefs()->GetUserPrefValue(
      prefs::kAutofillPaymentMethodsMandatoryReauth));
  EXPECT_FALSE(autofill_client_->GetPrefs()->GetBoolean(
      prefs::kAutofillPaymentMethodsMandatoryReauth));
}

// Test that the MandatoryReauthManager correctly handles the case where the
// user closed the re-auth prompt.
TEST_F(MandatoryReauthManagerTest, OnUserClosedOptInPrompt) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  EXPECT_EQ(autofill_client_->GetPrefs()->GetInteger(
                prefs::kAutofillPaymentMethodsMandatoryReauthPromoShownCounter),
            0);

  mandatory_reauth_manager_->OnUserClosedOptInPrompt();

  EXPECT_EQ(autofill_client_->GetPrefs()->GetInteger(
                prefs::kAutofillPaymentMethodsMandatoryReauthPromoShownCounter),
            1);
}

// Params of the MandatoryReauthManagerOptInFlowTest:
// -- NonInteractivePaymentMethodType non-interactive payment method type
class MandatoryReauthManagerOptInFlowTest
    : public MandatoryReauthManagerTest,
      public testing::WithParamInterface<NonInteractivePaymentMethodType> {
 protected:
  void SetUp() override {
    MandatoryReauthManagerTest::SetUp();
    mandatory_reauth_manager_->SetDeviceAuthenticatorPtrForTesting(
        std::make_unique<device_reauth::MockDeviceAuthenticator>());
    ON_CALL(device_authenticator(), CanAuthenticateWithBiometricOrScreenLock)
        .WillByDefault(testing::Return(true));
  }

  std::string GetOptInSource() {
    switch (GetParam()) {
      case NonInteractivePaymentMethodType::kLocalCard:
        return "CheckoutLocalCard";
      case NonInteractivePaymentMethodType::kFullServerCard:
        return "CheckoutFullServerCard";
      case NonInteractivePaymentMethodType::kVirtualCard:
        return "CheckoutVirtualCard";
      case NonInteractivePaymentMethodType::kMaskedServerCard:
        return "CheckoutMaskedServerCard";
      case NonInteractivePaymentMethodType::kLocalIban:
        return "CheckoutLocalIban";
      case NonInteractivePaymentMethodType::kServerIban:
        return "CheckoutServerIban";
    }
  }

  std::string GetHistogramStringForNonInteractivePaymentMethodType() {
    switch (GetParam()) {
      case NonInteractivePaymentMethodType::kLocalCard:
        return "LocalCard";
      case NonInteractivePaymentMethodType::kFullServerCard:
      case NonInteractivePaymentMethodType::kMaskedServerCard:
        return "ServerCard";
      case NonInteractivePaymentMethodType::kVirtualCard:
        return "VirtualCard";
      case NonInteractivePaymentMethodType::kLocalIban:
        return "LocalIban";
      case NonInteractivePaymentMethodType::kServerIban:
        return "ServerIban";
    }
  }

  void SetUpDeviceAuthenticator(bool success) {
    ON_CALL(device_authenticator(), AuthenticateWithMessage)
        .WillByDefault(testing::WithArg<1>(
            [success](base::OnceCallback<void(bool)> callback) {
              std::move(callback).Run(success);
            }));
  }
};

TEST_P(MandatoryReauthManagerOptInFlowTest,
       StartDeviceAuthentication_Biometric) {
  base::HistogramTester histogram_tester;
  ON_CALL(device_authenticator(), CanAuthenticateWithBiometrics)
      .WillByDefault(testing::Return(true));

  EXPECT_CALL(device_authenticator(), AuthenticateWithMessage);
  mandatory_reauth_manager_->StartDeviceAuthentication(GetParam(),
                                                       base::DoNothing());
  histogram_tester.ExpectBucketCount(
      "Autofill.PaymentMethods.CheckoutFlow.ReauthUsage." +
          GetHistogramStringForNonInteractivePaymentMethodType() + ".Biometric",
      autofill_metrics::MandatoryReauthAuthenticationFlowEvent::kFlowStarted,
      1);
}

TEST_P(MandatoryReauthManagerOptInFlowTest,
       StartDeviceAuthentication_ScreenLock) {
  base::HistogramTester histogram_tester;

  ON_CALL(device_authenticator(), CanAuthenticateWithBiometrics)
      .WillByDefault(testing::Return(false));
  ON_CALL(device_authenticator(), CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(testing::Return(true));

  mandatory_reauth_manager_->StartDeviceAuthentication(GetParam(),
                                                       base::DoNothing());
  histogram_tester.ExpectBucketCount(
      "Autofill.PaymentMethods.CheckoutFlow.ReauthUsage." +
          GetHistogramStringForNonInteractivePaymentMethodType() +
          ".ScreenLock",
      autofill_metrics::MandatoryReauthAuthenticationFlowEvent::kFlowStarted,
      1);
}

TEST_P(MandatoryReauthManagerOptInFlowTest,
       StartDeviceAuthentication_Unsupported) {
  base::HistogramTester histogram_tester;
  ON_CALL(device_authenticator(), CanAuthenticateWithBiometrics)
      .WillByDefault(testing::Return(false));
  ON_CALL(device_authenticator(), CanAuthenticateWithBiometricOrScreenLock)
      .WillByDefault(testing::Return(false));

  base::MockCallback<base::OnceCallback<void(bool)>> callback;
  EXPECT_CALL(callback, Run(true));
  mandatory_reauth_manager_->StartDeviceAuthentication(GetParam(),
                                                       callback.Get());
  histogram_tester.ExpectBucketCount(
      "Autofill.PaymentMethods.CheckoutFlow.ReauthUsage." +
          GetHistogramStringForNonInteractivePaymentMethodType() +
          ".UnsupportedMethod",
      autofill_metrics::MandatoryReauthAuthenticationFlowEvent::kFlowSkipped,
      1);
}

TEST_P(MandatoryReauthManagerOptInFlowTest, OptInSuccess) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  base::HistogramTester histogram_tester;

  // Verify that we shall offer opt in.
  EXPECT_TRUE(mandatory_reauth_manager_->ShouldOfferOptin(GetParam()));

  auto mock_device_authenticator2 =
      std::make_unique<device_reauth::MockDeviceAuthenticator>();

  mandatory_reauth_manager_->SetDeviceAuthenticatorPtrForTesting(
      std::move(mock_device_authenticator2));

  SetUpDeviceAuthenticator(/*success=*/true);

  // Start OptIn flow.
  static_cast<MandatoryReauthManager*>(mandatory_reauth_manager_.get())
      ->StartOptInFlow();
  // Simulate user accepts the opt in prompt.
  mandatory_reauth_manager_->OnUserAcceptedOptInPrompt();

  EXPECT_TRUE(autofill_client_->GetPrefs()->GetBoolean(
      prefs::kAutofillPaymentMethodsMandatoryReauth));
  EXPECT_TRUE(autofill_client_->GetPaymentsAutofillClient()
                  ->GetMandatoryReauthOptInPromptWasShown());
  // Counter is not changed since it's a successful opt in.
  EXPECT_EQ(autofill_client_->GetPrefs()->GetInteger(
                prefs::kAutofillPaymentMethodsMandatoryReauthPromoShownCounter),
            0);
  EXPECT_TRUE(autofill_client_->GetPrefs()->GetUserPrefValue(
      prefs::kAutofillPaymentMethodsMandatoryReauth));

  // Ensures the metrics have been logged correctly.
  histogram_tester.ExpectBucketCount(
      "Autofill.PaymentMethods.MandatoryReauth.OptChangeEvent." +
          GetOptInSource() + ".OptIn",
      autofill_metrics::MandatoryReauthAuthenticationFlowEvent::kFlowStarted,
      1);
  histogram_tester.ExpectBucketCount(
      "Autofill.PaymentMethods.MandatoryReauth.OptChangeEvent." +
          GetOptInSource() + ".OptIn",
      autofill_metrics::MandatoryReauthAuthenticationFlowEvent::kFlowSucceeded,
      1);
}

TEST_P(MandatoryReauthManagerOptInFlowTest, OptInShownButAuthFailure) {
#if BUILDFLAG(IS_ANDROID)
  if (base::android::BuildInfo::GetInstance()->is_automotive()) {
    // Skip the test for automotive as Mandatory Re-auth should always be turned
    // on for automotive users.
    GTEST_SKIP() << "This test should not run on automotive.";
  }
#endif  // BUILDFLAG(IS_ANDROID)

  base::HistogramTester histogram_tester;

  // Verify that we shall offer opt in.
  EXPECT_TRUE(mandatory_reauth_manager_->ShouldOfferOptin(GetParam()));

  auto mock_device_authenticator2 =
      std::make_unique<device_reauth::MockDeviceAuthenticator>();

  mandatory_reauth_manager_->SetDeviceAuthenticatorPtrForTesting(
      std::move(mock_device_authenticator2));

  // Simulate authentication failure.
  SetUpDeviceAuthenticator(/*success=*/false);

  // Start OptIn flow.
  static_cast<MandatoryReauthManager*>(mandatory_reauth_manager_.get())
      ->StartOptInFlow();
  // Simulate user accepts the opt in prompt. But the device authentication
  // fails.
  mandatory_reauth_manager_->OnUserAcceptedOptInPrompt();

  EXPECT_TRUE(autofill_client_->GetPaymentsAutofillClient()
                  ->GetMandatoryReauthOptInPromptWasShown());
  // Counter is increased by 1 since device authentication fails during opt in.
  EXPECT_EQ(autofill_client_->GetPrefs()->GetInteger(
                prefs::kAutofillPaymentMethodsMandatoryReauthPromoShownCounter),
            1);
  // The reauth pref is still off since authentication fails.
  EXPECT_FALSE(autofill_client_->GetPrefs()->GetBoolean(
      prefs::kAutofillPaymentMethodsMandatoryReauth));

  // Ensures the metrics have been logged correctly.
  histogram_tester.ExpectBucketCount(
      "Autofill.PaymentMethods.MandatoryReauth.OptChangeEvent." +
          GetOptInSource() + ".OptIn",
      autofill_metrics::MandatoryReauthAuthenticationFlowEvent::kFlowStarted,
      1);
  histogram_tester.ExpectBucketCount(
      "Autofill.PaymentMethods.MandatoryReauth.OptChangeEvent." +
          GetOptInSource() + ".OptIn",
      autofill_metrics::MandatoryReauthAuthenticationFlowEvent::kFlowFailed, 1);
}

INSTANTIATE_TEST_SUITE_P(
    ,
    MandatoryReauthManagerOptInFlowTest,
    testing::ValuesIn(MandatoryReauthManager::
                          GetAllNonInteractivePaymentMethodTypesForTesting()));

}  // namespace autofill::payments