blob: b48076b9a1dd9afca0563135392bb118fc1b7225 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <set>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/raw_ptr.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/payments/credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/local_card_migration_manager.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/payments/virtual_card_enrollment_flow.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/variations/net/variations_http_headers.h"
#include "components/variations/scoped_variations_ids_provider.h"
#include "components/variations/variations_associated_data.h"
#include "components/variations/variations_ids_provider.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "services/network/test/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace autofill {
namespace payments {
namespace {
int kAllDetectableValues =
CreditCardSaveManager::DetectedValue::CVC |
CreditCardSaveManager::DetectedValue::CARDHOLDER_NAME |
CreditCardSaveManager::DetectedValue::ADDRESS_NAME |
CreditCardSaveManager::DetectedValue::ADDRESS_LINE |
CreditCardSaveManager::DetectedValue::LOCALITY |
CreditCardSaveManager::DetectedValue::ADMINISTRATIVE_AREA |
CreditCardSaveManager::DetectedValue::POSTAL_CODE |
CreditCardSaveManager::DetectedValue::COUNTRY_CODE |
CreditCardSaveManager::DetectedValue::HAS_GOOGLE_PAYMENTS_ACCOUNT;
struct CardUnmaskOptions {
CardUnmaskOptions& with_fido() {
use_fido = true;
use_cvc = false;
return *this;
}
CardUnmaskOptions& with_cvc(std::string c) {
use_cvc = true;
cvc = c;
return *this;
}
CardUnmaskOptions& with_virtual_card() {
virtual_card = true;
return *this;
}
CardUnmaskOptions& with_virtual_card_risk_based() {
with_virtual_card();
use_cvc = false;
return *this;
}
CardUnmaskOptions& with_virtual_card_risk_based_then_fido() {
with_virtual_card();
use_fido = true;
use_cvc = false;
set_context_token = true;
return *this;
}
CardUnmaskOptions& with_virtual_card_risk_based_then_otp(std::string o) {
with_virtual_card();
use_otp = true;
use_cvc = false;
set_context_token = true;
otp = o;
return *this;
}
// By default, use cvc authentication.
bool use_cvc = true;
// If true, use FIDO authentication.
bool use_fido = false;
// If true, use otp authentication.
bool use_otp = false;
// If CVC authentication is chosen, default CVC value the user entered, to be
// sent to Google Payments.
std::string cvc = "123";
// If OTP authentication is chosen, default OTP value the user entered.
std::string otp = "654321";
// If true, mock that the unmasking is for a virtual card.
bool virtual_card = false;
// If true, set context_token in the request.
bool set_context_token = true;
};
} // namespace
class PaymentsClientTest : public testing::Test {
public:
PaymentsClientTest() = default;
PaymentsClientTest(const PaymentsClientTest&) = delete;
PaymentsClientTest& operator=(const PaymentsClientTest&) = delete;
~PaymentsClientTest() override = default;
void SetUp() override {
// Silence the warning for mismatching sync and Payments servers.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kWalletServiceUseSandbox, "0");
result_ = AutofillClient::PaymentsRpcResult::kNone;
upload_card_response_details_.server_id.clear();
unmask_response_details_ = nullptr;
legal_message_.reset();
has_variations_header_ = false;
factory()->SetInterceptor(base::BindLambdaForTesting(
[&](const network::ResourceRequest& request) {
intercepted_headers_ = request.headers;
intercepted_body_ = network::GetUploadData(request);
has_variations_header_ = variations::HasVariationsHeader(request);
}));
test_shared_loader_factory_ =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
client_ = std::make_unique<PaymentsClient>(
test_shared_loader_factory_, identity_test_env_.identity_manager(),
&test_personal_data_);
test_personal_data_.SetAccountInfoForPayments(
identity_test_env_.MakePrimaryAccountAvailable(
"example@gmail.com", signin::ConsentLevel::kSync));
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillEnableVirtualCardsRiskBasedAuthentication);
}
void TearDown() override { client_.reset(); }
// Registers a field trial with the specified name and group and an associated
// google web property variation id.
void CreateFieldTrialWithId(const std::string& trial_name,
const std::string& group_name,
int variation_id) {
variations::AssociateGoogleVariationID(
variations::GOOGLE_WEB_PROPERTIES_ANY_CONTEXT, trial_name, group_name,
static_cast<variations::VariationID>(variation_id));
base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group();
}
void OnDidGetUnmaskDetails(
AutofillClient::PaymentsRpcResult result,
payments::PaymentsClient::UnmaskDetails& unmask_details) {
result_ = result;
unmask_details_ = &unmask_details;
}
void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
PaymentsClient::UnmaskResponseDetails& response) {
result_ = result;
unmask_response_details_ = &response;
}
void OnDidGetOptChangeResult(
AutofillClient::PaymentsRpcResult result,
PaymentsClient::OptChangeResponseDetails& response) {
result_ = result;
opt_change_response_.user_is_opted_in = response.user_is_opted_in;
opt_change_response_.fido_creation_options =
std::move(response.fido_creation_options);
opt_change_response_.fido_request_options =
std::move(response.fido_request_options);
}
void OnDidGetUploadDetails(
AutofillClient::PaymentsRpcResult result,
const std::u16string& context_token,
std::unique_ptr<base::Value> legal_message,
std::vector<std::pair<int, int>> supported_card_bin_ranges) {
result_ = result;
legal_message_ = std::move(legal_message);
supported_card_bin_ranges_ = supported_card_bin_ranges;
}
void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
const PaymentsClient::UploadCardResponseDetails&
upload_card_respone_details) {
result_ = result;
upload_card_response_details_ = upload_card_respone_details;
}
#if !defined(OS_ANDROID) && !defined(OS_IOS)
void OnDidMigrateLocalCards(
AutofillClient::PaymentsRpcResult result,
std::unique_ptr<std::unordered_map<std::string, std::string>>
migration_save_results,
const std::string& display_text) {
result_ = result;
migration_save_results_ = std::move(migration_save_results);
display_text_ = display_text;
}
#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
void OnDidSelectChallengeOption(AutofillClient::PaymentsRpcResult result,
const std::string& updated_context_token) {
result_ = result;
context_token_ = updated_context_token;
}
void OnDidGetUpdateVirtualCardEnrollmentResponse(
AutofillClient::PaymentsRpcResult result) {
result_ = result;
}
protected:
base::test::ScopedFeatureList scoped_feature_list_;
// Issue a GetUnmaskDetails request. This requires an OAuth token before
// starting the request.
void StartGettingUnmaskDetails() {
client_->GetUnmaskDetails(
base::BindOnce(&PaymentsClientTest::OnDidGetUnmaskDetails,
weak_ptr_factory_.GetWeakPtr()),
"language-LOCALE");
}
// Issue an UnmaskCard request. This requires an OAuth token before starting
// the request.
void StartUnmasking(CardUnmaskOptions options) {
PaymentsClient::UnmaskRequestDetails request_details;
request_details.billing_customer_number = 111222333444;
request_details.card = test::GetMaskedServerCard();
request_details.risk_data = "some risk data";
if (options.use_fido) {
request_details.fido_assertion_info =
base::Value(base::Value::Type::DICTIONARY);
}
if (options.use_cvc)
request_details.user_response.cvc = base::ASCIIToUTF16(options.cvc);
if (options.virtual_card) {
request_details.card.set_record_type(CreditCard::VIRTUAL_CARD);
request_details.last_committed_url_origin =
GURL("https://www.example.com");
}
if (options.set_context_token)
request_details.context_token = "fake context token";
if (options.use_otp)
request_details.otp = base::ASCIIToUTF16(options.otp);
client_->UnmaskCard(request_details,
base::BindOnce(&PaymentsClientTest::OnDidGetRealPan,
weak_ptr_factory_.GetWeakPtr()));
}
// If |opt_in| is set to true, then opts the user in to use FIDO
// authentication for card unmasking. Otherwise opts the user out.
void StartOptChangeRequest(
PaymentsClient::OptChangeRequestDetails::Reason reason) {
PaymentsClient::OptChangeRequestDetails request_details;
request_details.reason = reason;
client_->OptChange(
request_details,
base::BindOnce(&PaymentsClientTest::OnDidGetOptChangeResult,
weak_ptr_factory_.GetWeakPtr()));
}
// Issue a GetUploadDetails request.
void StartGettingUploadDetails(
PaymentsClient::UploadCardSource upload_card_source =
PaymentsClient::UploadCardSource::UNKNOWN_UPLOAD_CARD_SOURCE) {
client_->GetUploadDetails(
BuildTestProfiles(), kAllDetectableValues, std::vector<const char*>(),
"language-LOCALE",
base::BindOnce(&PaymentsClientTest::OnDidGetUploadDetails,
weak_ptr_factory_.GetWeakPtr()),
/*billable_service_number=*/12345, upload_card_source);
}
// Issue an UploadCard request. This requires an OAuth token before starting
// the request.
void StartUploading(bool include_cvc, bool include_nickname = false) {
PaymentsClient::UploadRequestDetails request_details;
request_details.billing_customer_number = 111222333444;
request_details.card = test::GetCreditCard();
if (include_cvc)
request_details.cvc = u"123";
if (include_nickname) {
upstream_nickname_ = u"grocery";
request_details.card.SetNickname(upstream_nickname_);
}
request_details.context_token = u"context token";
request_details.risk_data = "some risk data";
request_details.app_locale = "language-LOCALE";
request_details.profiles = BuildTestProfiles();
client_->UploadCard(request_details,
base::BindOnce(&PaymentsClientTest::OnDidUploadCard,
weak_ptr_factory_.GetWeakPtr()));
}
#if !defined(OS_ANDROID) && !defined(OS_IOS)
void StartMigrating(bool has_cardholder_name,
bool set_nickname_for_first_card = false) {
PaymentsClient::MigrationRequestDetails request_details;
request_details.context_token = u"context token";
request_details.risk_data = "some risk data";
request_details.app_locale = "language-LOCALE";
migratable_credit_cards_.clear();
CreditCard card1 = test::GetCreditCard();
if (set_nickname_for_first_card)
card1.SetNickname(u"grocery");
CreditCard card2 = test::GetCreditCard2();
if (!has_cardholder_name) {
card1.SetRawInfo(CREDIT_CARD_NAME_FULL, u"");
card2.SetRawInfo(CREDIT_CARD_NAME_FULL, u"");
}
migratable_credit_cards_.push_back(MigratableCreditCard(card1));
migratable_credit_cards_.push_back(MigratableCreditCard(card2));
client_->MigrateCards(
request_details, migratable_credit_cards_,
base::BindOnce(&PaymentsClientTest::OnDidMigrateLocalCards,
weak_ptr_factory_.GetWeakPtr()));
}
#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
void StartSelectingChallengeOption(
CardUnmaskChallengeOptionType challenge_type =
CardUnmaskChallengeOptionType::kSmsOtp,
std::string challenge_id = "arbitrary id") {
PaymentsClient::SelectChallengeOptionRequestDetails request_details;
request_details.billing_customer_number = 555666777888;
request_details.context_token = "fake context token";
CardUnmaskChallengeOption selected_challenge_option;
selected_challenge_option.type = challenge_type;
selected_challenge_option.id = challenge_id;
selected_challenge_option.challenge_info = u"(***)-***-5678";
request_details.selected_challenge_option = selected_challenge_option;
client_->SelectChallengeOption(
request_details,
base::BindOnce(&PaymentsClientTest::OnDidSelectChallengeOption,
weak_ptr_factory_.GetWeakPtr()));
}
network::TestURLLoaderFactory* factory() { return &test_url_loader_factory_; }
const std::string& GetUploadData() { return intercepted_body_; }
bool HasVariationsHeader() { return has_variations_header_; }
// Issues access token in response to any access token request. This will
// start the Payments Request which requires the authentication.
void IssueOAuthToken() {
identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"totally_real_token", AutofillClock::Now() + base::Days(10));
// Verify the auth header.
std::string auth_header_value;
EXPECT_TRUE(intercepted_headers_.GetHeader(
net::HttpRequestHeaders::kAuthorization, &auth_header_value))
<< intercepted_headers_.ToString();
EXPECT_EQ("Bearer totally_real_token", auth_header_value);
}
void ReturnResponse(net::HttpStatusCode response_code,
const std::string& response_body) {
client_->OnSimpleLoaderCompleteInternal(response_code, response_body);
}
void assertCvcIncludedInRequest(std::string cvc) {
EXPECT_TRUE(!GetUploadData().empty());
// Verify that the encrypted_cvc and s7e_13_cvc parameters were both
// included in the request.
EXPECT_TRUE(GetUploadData().find("encrypted_cvc") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("__param:s7e_13_cvc") !=
std::string::npos);
EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=" + cvc) !=
std::string::npos);
}
void assertOtpIncludedInRequest(std::string otp) {
EXPECT_TRUE(!GetUploadData().empty());
// Verify that the otp and s7e_263_otp parameters were both included in the
// request.
EXPECT_TRUE(GetUploadData().find("otp") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("__param:s7e_263_otp") !=
std::string::npos);
EXPECT_TRUE(GetUploadData().find("&s7e_263_otp=" + otp) !=
std::string::npos);
}
void assertCvcNotIncludedInRequest() {
EXPECT_TRUE(!GetUploadData().empty());
// Verify that the encrypted_cvc and s7e_13_cvc parameters were NOT included
// in the request.
EXPECT_TRUE(GetUploadData().find("encrypted_cvc") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("__param:s7e_13_cvc") ==
std::string::npos);
EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=") == std::string::npos);
}
void assertOtpNotIncludedInRequest() {
EXPECT_TRUE(!GetUploadData().empty());
// Verify that the otp and s7e_263_otp parameters were NOT included in the
// request.
EXPECT_TRUE(GetUploadData().find("otp") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("__param:s7e_263_otp") ==
std::string::npos);
EXPECT_TRUE(GetUploadData().find("&s7e_263_otp=") == std::string::npos);
}
void assertIncludedInRequest(std::string field_name_or_value) {
EXPECT_TRUE(GetUploadData().find(field_name_or_value) != std::string::npos);
}
void assertNotIncludedInRequest(std::string field_name_or_value) {
EXPECT_TRUE(GetUploadData().find(field_name_or_value) == std::string::npos);
}
AutofillClient::PaymentsRpcResult result_ =
AutofillClient::PaymentsRpcResult::kNone;
raw_ptr<payments::PaymentsClient::UnmaskDetails> unmask_details_;
// Server ID of a saved card via credit card upload save.
PaymentsClient::UploadCardResponseDetails upload_card_response_details_;
// The OptChangeResponseDetails retrieved from an OptChangeRequest.
PaymentsClient::OptChangeResponseDetails opt_change_response_;
// The UnmaskResponseDetails retrieved from an UnmaskRequest. Includes PAN.
raw_ptr<PaymentsClient::UnmaskResponseDetails> unmask_response_details_ =
nullptr;
// The legal message returned from a GetDetails upload save preflight call.
std::unique_ptr<base::Value> legal_message_;
// A list of card BIN ranges supported by Google Payments, returned from a
// GetDetails upload save preflight call.
std::vector<std::pair<int, int>> supported_card_bin_ranges_;
// The nickname name in the UploadRequest that was supposed to be saved.
std::u16string upstream_nickname_;
// The opaque token used to chain consecutive payments requests together.
std::string context_token_;
#if !defined(OS_ANDROID) && !defined(OS_IOS)
// Credit cards to be upload saved during a local credit card migration call.
std::vector<MigratableCreditCard> migratable_credit_cards_;
// A mapping of results from a local credit card migration call.
std::unique_ptr<std::unordered_map<std::string, std::string>>
migration_save_results_;
// A tip message to be displayed during local card migration.
std::string display_text_;
#endif // !defined(OS_ANDROID) && !defined(OS_IOS)
base::test::TaskEnvironment task_environment_;
variations::ScopedVariationsIdsProvider scoped_variations_ids_provider_{
variations::VariationsIdsProvider::Mode::kUseSignedInState};
network::TestURLLoaderFactory test_url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
TestPersonalDataManager test_personal_data_;
std::unique_ptr<PaymentsClient> client_;
signin::IdentityTestEnvironment identity_test_env_;
net::HttpRequestHeaders intercepted_headers_;
bool has_variations_header_;
std::string intercepted_body_;
base::WeakPtrFactory<PaymentsClientTest> weak_ptr_factory_{this};
private:
std::vector<AutofillProfile> BuildTestProfiles() {
std::vector<AutofillProfile> profiles;
profiles.push_back(BuildProfile("John", "Smith", "1234 Main St.", "Miami",
"FL", "32006", "212-555-0162"));
profiles.push_back(BuildProfile("Pat", "Jones", "432 Oak Lane", "Lincoln",
"OH", "43005", "(834)555-0090"));
return profiles;
}
AutofillProfile BuildProfile(base::StringPiece first_name,
base::StringPiece last_name,
base::StringPiece address_line,
base::StringPiece city,
base::StringPiece state,
base::StringPiece zip,
base::StringPiece phone_number) {
AutofillProfile profile;
profile.SetInfo(NAME_FIRST, base::ASCIIToUTF16(first_name), "en-US");
profile.SetInfo(NAME_LAST, base::ASCIIToUTF16(last_name), "en-US");
profile.SetInfo(ADDRESS_HOME_LINE1, base::ASCIIToUTF16(address_line),
"en-US");
profile.SetInfo(ADDRESS_HOME_CITY, base::ASCIIToUTF16(city), "en-US");
profile.SetInfo(ADDRESS_HOME_STATE, base::ASCIIToUTF16(state), "en-US");
profile.SetInfo(ADDRESS_HOME_ZIP, base::ASCIIToUTF16(zip), "en-US");
profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, base::ASCIIToUTF16(phone_number),
"en-US");
profile.FinalizeAfterImport();
return profile;
}
};
TEST_F(PaymentsClientTest, GetUnmaskDetailsSuccess) {
StartGettingUnmaskDetails();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"offer_fido_opt_in\": \"false\", "
"\"authentication_method\": \"CVC\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ(false, unmask_details_->offer_fido_opt_in);
EXPECT_EQ(AutofillClient::UnmaskAuthMethod::kCvc,
unmask_details_->unmask_auth_method);
}
TEST_F(PaymentsClientTest, GetUnmaskDetailsIncludesChromeUserContext) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
features::kAutofillEnableAccountWalletStorage);
StartGettingUnmaskDetails();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest, OAuthError) {
StartUnmasking(CardUnmaskOptions());
identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
EXPECT_TRUE(unmask_response_details_->real_pan.empty());
}
TEST_F(PaymentsClientTest,
UnmaskRequestIncludesBillingCustomerNumberInRequest) {
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
// Verify that the billing customer number is included in the request.
EXPECT_TRUE(
GetUploadData().find("%22external_customer_id%22:%22111222333444%22") !=
std::string::npos);
}
TEST_F(PaymentsClientTest, UnmaskSuccessViaCVC) {
StartUnmasking(CardUnmaskOptions().with_cvc("111"));
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
assertCvcIncludedInRequest("111");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("1234", unmask_response_details_->real_pan);
}
TEST_F(PaymentsClientTest, UnmaskSuccessViaFIDO) {
StartUnmasking(CardUnmaskOptions().with_fido());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
assertCvcNotIncludedInRequest();
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("1234", unmask_response_details_->real_pan);
}
TEST_F(PaymentsClientTest, UnmaskSuccessViaCVCWithCreationOptions) {
StartUnmasking(CardUnmaskOptions().with_cvc("111"));
IssueOAuthToken();
ReturnResponse(
net::HTTP_OK,
"{ \"pan\": \"1234\", \"dcvv\": \"321\", \"fido_creation_options\": "
"{\"relying_party_id\": \"google.com\"}}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("1234", unmask_response_details_->real_pan);
EXPECT_EQ("321", unmask_response_details_->dcvv);
EXPECT_EQ("google.com",
*unmask_response_details_->fido_creation_options->FindStringKey(
"relying_party_id"));
}
TEST_F(PaymentsClientTest, UnmaskSuccessAccountFromSyncTest) {
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("1234", unmask_response_details_->real_pan);
}
TEST_F(PaymentsClientTest, UnmaskSuccessWithVirtualCardCvcAuth) {
StartUnmasking(CardUnmaskOptions().with_virtual_card().with_cvc("222"));
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"pan\": \"4111111111111111\", \"dcvv\": \"999\", "
"\"expiration\": { \"month\":12, \"year\":2099 } }");
assertCvcIncludedInRequest("222");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("4111111111111111", unmask_response_details_->real_pan);
EXPECT_EQ("999", unmask_response_details_->dcvv);
EXPECT_EQ("12", unmask_response_details_->expiration_month);
EXPECT_EQ("2099", unmask_response_details_->expiration_year);
}
TEST_F(PaymentsClientTest, UnmaskSuccessWithVirtualCardFidoAuth) {
StartUnmasking(CardUnmaskOptions().with_virtual_card().with_fido());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"pan\": \"4111111111111111\", \"dcvv\": \"999\", "
"\"expiration\": { \"month\":12, \"year\":2099 } }");
assertCvcNotIncludedInRequest();
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("4111111111111111", unmask_response_details_->real_pan);
EXPECT_EQ("999", unmask_response_details_->dcvv);
EXPECT_EQ("12", unmask_response_details_->expiration_month);
EXPECT_EQ("2099", unmask_response_details_->expiration_year);
}
TEST_F(PaymentsClientTest, VirtualCardRiskBasedGreenPathResponse) {
StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"pan\": \"4111111111111111\", \"dcvv\": \"999\", "
"\"expiration\": { \"month\":12, \"year\":2099 } }");
// Verify that Cvc/FIDO/OTP are not included in the request.
assertCvcNotIncludedInRequest();
assertOtpNotIncludedInRequest();
EXPECT_TRUE(GetUploadData().find("fido_assertion_info") == std::string::npos);
// Only merchant_domain is included.
EXPECT_TRUE(GetUploadData().find("merchant_domain") != std::string::npos);
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("4111111111111111", unmask_response_details_->real_pan);
EXPECT_EQ("999", unmask_response_details_->dcvv);
EXPECT_EQ("12", unmask_response_details_->expiration_month);
EXPECT_EQ("2099", unmask_response_details_->expiration_year);
EXPECT_TRUE(unmask_response_details_->card_unmask_challenge_options.empty());
}
TEST_F(PaymentsClientTest, VirtualCardRiskBasedRedPathResponse_Error) {
StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"error\": { \"code\": \"NON-INTERNAL\", "
"\"api_error_reason\": \"virtual_card_permanent_error\"} }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure,
result_);
}
TEST_F(PaymentsClientTest,
VirtualCardRiskBasedRedPathResponse_NoOptionProvided) {
StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"fake_context_token\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
}
TEST_F(PaymentsClientTest, VirtualCardRiskBasedYellowPathResponse) {
StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
IssueOAuthToken();
ReturnResponse(
net::HTTP_OK,
"{ \"fido_request_options\": { \"challenge\": \"fake_fido_challenge\" }, "
"\"context_token\": \"fake_context_token\", \"idv_challenge_options\": "
"[{ \"sms_otp_challenge_option\": { \"challenge_id\": "
"\"fake_challenge_id_1\", \"masked_phone_number\": \"(***)-***-1234\" } "
"}, { \"sms_otp_challenge_option\": { \"challenge_id\": "
"\"fake_challenge_id_2\", \"masked_phone_number\": \"(***)-***-5678\" } "
"}] }");
// Ensure that it's not treated as failure when no pan is returned.
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("fake_context_token", unmask_response_details_->context_token);
// Verify the FIDO request challenge is correctly parsed.
EXPECT_EQ("fake_fido_challenge",
*unmask_response_details_->fido_request_options->FindStringKey(
"challenge"));
// Verify the two idv challenge options are both sms challenge and fields can
// be correctly parsed.
EXPECT_EQ(2u, unmask_response_details_->card_unmask_challenge_options.size());
const CardUnmaskChallengeOption& challenge_option_1 =
unmask_response_details_->card_unmask_challenge_options[0];
EXPECT_EQ(CardUnmaskChallengeOptionType::kSmsOtp, challenge_option_1.type);
EXPECT_EQ("fake_challenge_id_1", challenge_option_1.id);
EXPECT_EQ(u"(***)-***-1234", challenge_option_1.challenge_info);
const CardUnmaskChallengeOption& challenge_option_2 =
unmask_response_details_->card_unmask_challenge_options[1];
EXPECT_EQ(CardUnmaskChallengeOptionType::kSmsOtp, challenge_option_2.type);
EXPECT_EQ("fake_challenge_id_2", challenge_option_2.id);
EXPECT_EQ(u"(***)-***-5678", challenge_option_2.challenge_info);
}
TEST_F(PaymentsClientTest,
VirtualCardRiskBasedYellowPathResponseWithUnknownType) {
StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based());
IssueOAuthToken();
ReturnResponse(
net::HTTP_OK,
"{ \"fido_request_options\": { \"challenge\": \"fake_fido_challenge\" }, "
"\"context_token\": \"fake_context_token\", \"idv_challenge_options\": "
"[{ \"sms_otp_challenge_option\": { \"challenge_id\": "
"\"fake_challenge_id_1\", \"masked_phone_number\": \"(***)-***-1234\" } "
"}, { \"unknown_new_challenge_option\": { \"challenge_id\": "
"\"fake_challenge_id_2\" } }] }");
// Ensure that it's not treated as failure when no pan is returned.
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("fake_context_token", unmask_response_details_->context_token);
// Verify the FIDO request challenge is correctly parsed.
EXPECT_EQ("fake_fido_challenge",
*unmask_response_details_->fido_request_options->FindStringKey(
"challenge"));
// Verify that the unknow new challenge option type won't break the parsing.
// We ignore the unknown new type, and only return the supported challenge
// option.
EXPECT_EQ(1u, unmask_response_details_->card_unmask_challenge_options.size());
const CardUnmaskChallengeOption& sms_challenge_option =
unmask_response_details_->card_unmask_challenge_options[0];
EXPECT_EQ(CardUnmaskChallengeOptionType::kSmsOtp, sms_challenge_option.type);
EXPECT_EQ("fake_challenge_id_1", sms_challenge_option.id);
EXPECT_EQ(u"(***)-***-1234", sms_challenge_option.challenge_info);
}
TEST_F(PaymentsClientTest, VirtualCardRiskBasedThenFido) {
StartUnmasking(CardUnmaskOptions().with_virtual_card_risk_based_then_fido());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"pan\": \"4111111111111111\", \"dcvv\": \"999\", "
"\"expiration\": { \"month\":12, \"year\":2099 } }");
// Verify that Cvc/OTP are not included in the request.
assertCvcNotIncludedInRequest();
assertOtpNotIncludedInRequest();
// Verify the fido assertion and context token is included.
EXPECT_TRUE(GetUploadData().find("fido_assertion_info") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("context_token") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("merchant_domain") != std::string::npos);
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("4111111111111111", unmask_response_details_->real_pan);
EXPECT_EQ("999", unmask_response_details_->dcvv);
EXPECT_EQ("12", unmask_response_details_->expiration_month);
EXPECT_EQ("2099", unmask_response_details_->expiration_year);
}
TEST_F(PaymentsClientTest, VirtualCardRiskBasedThenOtpSuccess) {
const std::string otp = "111111";
StartUnmasking(
CardUnmaskOptions().with_virtual_card_risk_based_then_otp(otp));
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"pan\": \"4111111111111111\", \"dcvv\": \"999\", "
"\"expiration\": { \"month\":12, \"year\":2099 } }");
assertOtpIncludedInRequest(otp);
// Verify that Cvc/FIDO are not included in the request.
assertCvcNotIncludedInRequest();
EXPECT_TRUE(GetUploadData().find("fido_assertion_info") == std::string::npos);
// Verify the context token is also included.
EXPECT_TRUE(GetUploadData().find("context_token") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("merchant_domain") != std::string::npos);
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("4111111111111111", unmask_response_details_->real_pan);
EXPECT_EQ("999", unmask_response_details_->dcvv);
EXPECT_EQ("12", unmask_response_details_->expiration_month);
EXPECT_EQ("2099", unmask_response_details_->expiration_year);
}
TEST_F(PaymentsClientTest, ExpiredOtp) {
const std::string otp = "222222";
StartUnmasking(
CardUnmaskOptions().with_virtual_card_risk_based_then_otp(otp));
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"context_token\": \"fake_context_token\", "
"\"flow_status\": \"FLOW_STATUS_EXPIRED_OTP\" }");
assertOtpIncludedInRequest(otp);
// Verify the context token is also included.
EXPECT_TRUE(GetUploadData().find("context_token") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("merchant_domain") != std::string::npos);
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("FLOW_STATUS_EXPIRED_OTP", unmask_response_details_->flow_status);
}
TEST_F(PaymentsClientTest, IncorrectOtp) {
const std::string otp = "333333";
StartUnmasking(
CardUnmaskOptions().with_virtual_card_risk_based_then_otp(otp));
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"context_token\": \"fake_context_token\", "
"\"flow_status\": \"FLOW_STATUS_INCORRECT_OTP\" }");
assertOtpIncludedInRequest(otp);
// Verify the context token is also included.
EXPECT_TRUE(GetUploadData().find("context_token") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("merchant_domain") != std::string::npos);
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("FLOW_STATUS_INCORRECT_OTP", unmask_response_details_->flow_status);
}
TEST_F(PaymentsClientTest, UnmaskIncludesChromeUserContext) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
features::kAutofillEnableAccountWalletStorage);
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest,
UnmaskIncludesChromeUserContextIfWalletStorageFlagEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kAutofillEnableAccountWalletStorage);
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest, UnmaskIncludesMerchantDomain) {
StartUnmasking(CardUnmaskOptions().with_virtual_card());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
// last_committed_url_origin was set.
EXPECT_TRUE(GetUploadData().find("merchant_domain") != std::string::npos);
}
TEST_F(PaymentsClientTest, OptInSuccess) {
StartOptChangeRequest(
PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"fido_authentication_info\": { \"user_status\": "
"\"FIDO_AUTH_ENABLED\"}}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_TRUE(opt_change_response_.user_is_opted_in.value());
}
TEST_F(PaymentsClientTest, OptInServerUnresponsive) {
StartOptChangeRequest(
PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH);
IssueOAuthToken();
ReturnResponse(net::HTTP_REQUEST_TIMEOUT, "");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kNetworkError, result_);
EXPECT_FALSE(opt_change_response_.user_is_opted_in.has_value());
}
TEST_F(PaymentsClientTest, OptOutSuccess) {
StartOptChangeRequest(
PaymentsClient::OptChangeRequestDetails::DISABLE_FIDO_AUTH);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"fido_authentication_info\": { \"user_status\": "
"\"FIDO_AUTH_DISABLED\"}}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_FALSE(opt_change_response_.user_is_opted_in.value());
}
TEST_F(PaymentsClientTest, EnrollAttemptReturnsCreationOptions) {
StartOptChangeRequest(
PaymentsClient::OptChangeRequestDetails::ENABLE_FIDO_AUTH);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"fido_authentication_info\": { \"user_status\": "
"\"FIDO_AUTH_DISABLED\","
"\"fido_creation_options\": {"
"\"relying_party_id\": \"google.com\"}}}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_FALSE(opt_change_response_.user_is_opted_in.value());
EXPECT_EQ("google.com",
*opt_change_response_.fido_creation_options->FindStringKey(
"relying_party_id"));
}
TEST_F(PaymentsClientTest, GetDetailsSuccess) {
StartGettingUploadDetails();
ReturnResponse(
net::HTTP_OK,
"{ \"context_token\": \"some_token\", \"legal_message\": {} }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_NE(nullptr, legal_message_.get());
}
TEST_F(PaymentsClientTest, GetDetailsRemovesNonLocationData) {
StartGettingUploadDetails();
// Verify that the recipient name field and test names appear nowhere in the
// upload data.
EXPECT_TRUE(GetUploadData().find(PaymentsClient::kRecipientName) ==
std::string::npos);
EXPECT_TRUE(GetUploadData().find("John") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("Smith") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("Pat") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("Jones") == std::string::npos);
// Verify that the phone number field and test numbers appear nowhere in the
// upload data.
EXPECT_TRUE(GetUploadData().find(PaymentsClient::kPhoneNumber) ==
std::string::npos);
EXPECT_TRUE(GetUploadData().find("212") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("555") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("0162") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("834") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("0090") == std::string::npos);
}
TEST_F(PaymentsClientTest, GetDetailsIncludesDetectedValuesInRequest) {
StartGettingUploadDetails();
// Verify that the detected values were included in the request.
std::string detected_values_string =
"\"detected_values\":" + std::to_string(kAllDetectableValues);
EXPECT_TRUE(GetUploadData().find(detected_values_string) !=
std::string::npos);
}
TEST_F(PaymentsClientTest, GetDetailsIncludesChromeUserContext) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
features::kAutofillEnableAccountWalletStorage);
StartGettingUploadDetails();
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest,
GetDetailsIncludesChromeUserContextIfWalletStorageFlagEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kAutofillEnableAccountWalletStorage);
StartGettingUploadDetails();
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest,
GetDetailsIncludesUpstreamCheckoutFlowUploadCardSourceInRequest) {
StartGettingUploadDetails(
PaymentsClient::UploadCardSource::UPSTREAM_CHECKOUT_FLOW);
// Verify that the correct upload card source was included in the request.
EXPECT_TRUE(GetUploadData().find("UPSTREAM_CHECKOUT_FLOW") !=
std::string::npos);
}
TEST_F(PaymentsClientTest,
GetDetailsIncludesUpstreamSettingsPageUploadCardSourceInRequest) {
StartGettingUploadDetails(
PaymentsClient::UploadCardSource::UPSTREAM_SETTINGS_PAGE);
// Verify that the correct upload card source was included in the request.
EXPECT_TRUE(GetUploadData().find("UPSTREAM_SETTINGS_PAGE") !=
std::string::npos);
}
TEST_F(PaymentsClientTest,
GetDetailsIncludesUpstreamCardOcrUploadCardSourceInRequest) {
StartGettingUploadDetails(
PaymentsClient::UploadCardSource::UPSTREAM_CARD_OCR);
// Verify that the correct upload card source was included in the request.
EXPECT_TRUE(GetUploadData().find("UPSTREAM_CARD_OCR") != std::string::npos);
}
TEST_F(
PaymentsClientTest,
GetDetailsIncludesLocalCardMigrationCheckoutFlowUploadCardSourceInRequest) {
StartGettingUploadDetails(
PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_CHECKOUT_FLOW);
// Verify that the correct upload card source was included in the request.
EXPECT_TRUE(GetUploadData().find("LOCAL_CARD_MIGRATION_CHECKOUT_FLOW") !=
std::string::npos);
}
TEST_F(
PaymentsClientTest,
GetDetailsIncludesLocalCardMigrationSettingsPageUploadCardSourceInRequest) {
StartGettingUploadDetails(
PaymentsClient::UploadCardSource::LOCAL_CARD_MIGRATION_SETTINGS_PAGE);
// Verify that the correct upload card source was included in the request.
EXPECT_TRUE(GetUploadData().find("LOCAL_CARD_MIGRATION_SETTINGS_PAGE") !=
std::string::npos);
}
TEST_F(PaymentsClientTest, GetDetailsIncludesUnknownUploadCardSourceInRequest) {
StartGettingUploadDetails();
// Verify that the absence of an upload card source results in UNKNOWN.
EXPECT_TRUE(GetUploadData().find("UNKNOWN_UPLOAD_CARD_SOURCE") !=
std::string::npos);
}
TEST_F(PaymentsClientTest, GetUploadDetailsVariationsTest) {
// Register a trial and variation id, so that there is data in variations
// headers.
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartGettingUploadDetails();
// Note that experiment information is stored in X-Client-Data.
EXPECT_TRUE(HasVariationsHeader());
}
TEST_F(PaymentsClientTest, GetDetailsIncludeBillableServiceNumber) {
StartGettingUploadDetails();
// Verify that billable service number was included in the request.
EXPECT_TRUE(GetUploadData().find("\"billable_service\":12345") !=
std::string::npos);
}
TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) {
StartGettingUploadDetails();
ReturnResponse(
net::HTTP_OK,
"{ \"context_token\": \"some_token\", \"legal_message\": {} }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
result_ = AutofillClient::PaymentsRpcResult::kNone;
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
}
TEST_F(PaymentsClientTest, GetDetailsMissingContextToken) {
StartGettingUploadDetails();
ReturnResponse(net::HTTP_OK, "{ \"legal_message\": {} }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
}
TEST_F(PaymentsClientTest, GetDetailsMissingLegalMessage) {
StartGettingUploadDetails();
ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"some_token\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
EXPECT_EQ(nullptr, legal_message_.get());
}
TEST_F(PaymentsClientTest, SupportedCardBinRangesParsesCorrectly) {
StartGettingUploadDetails();
ReturnResponse(
net::HTTP_OK,
"{"
" \"context_token\" : \"some_token\","
" \"legal_message\" : {},"
" \"supported_card_bin_ranges_string\" : \"1234,300000-555555,765\""
"}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
// Check that |supported_card_bin_ranges_| has the two entries specified in
// ReturnResponse(~) above.
ASSERT_EQ(3U, supported_card_bin_ranges_.size());
EXPECT_EQ(1234, supported_card_bin_ranges_[0].first);
EXPECT_EQ(1234, supported_card_bin_ranges_[0].second);
EXPECT_EQ(300000, supported_card_bin_ranges_[1].first);
EXPECT_EQ(555555, supported_card_bin_ranges_[1].second);
EXPECT_EQ(765, supported_card_bin_ranges_[2].first);
EXPECT_EQ(765, supported_card_bin_ranges_[2].second);
}
TEST_F(PaymentsClientTest, GetUploadAccountFromSyncTest) {
// Set up a different account.
const AccountInfo& secondary_account_info =
identity_test_env_.MakeAccountAvailable("secondary@gmail.com");
test_personal_data_.SetAccountInfoForPayments(secondary_account_info);
StartUploading(/*include_cvc=*/true);
ReturnResponse(net::HTTP_OK, "{}");
// Issue a token for the secondary account.
identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
secondary_account_info.account_id, "secondary_account_token",
AutofillClock::Now() + base::Days(10));
// Verify the auth header.
std::string auth_header_value;
EXPECT_TRUE(intercepted_headers_.GetHeader(
net::HttpRequestHeaders::kAuthorization, &auth_header_value))
<< intercepted_headers_.ToString();
EXPECT_EQ("Bearer secondary_account_token", auth_header_value);
}
TEST_F(PaymentsClientTest, UploadCardVariationsTest) {
// Register a trial and variation id, so that there is data in variations
// headers.
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
// Note that experiment information is stored in X-Client-Data.
EXPECT_TRUE(HasVariationsHeader());
}
TEST_F(PaymentsClientTest, UnmaskCardVariationsTest) {
// Register a trial and variation id, so that there is data in variations
// headers.
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
// Note that experiment information is stored in X-Client-Data.
EXPECT_TRUE(HasVariationsHeader());
}
TEST_F(PaymentsClientTest, UploadSuccessWithoutServerId) {
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_TRUE(upload_card_response_details_.server_id.empty());
}
TEST_F(PaymentsClientTest, UploadSuccessWithServerId) {
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"credit_card_id\": \"InstrumentData:1\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("InstrumentData:1", upload_card_response_details_.server_id);
}
TEST_F(PaymentsClientTest, UploadIncludesNonLocationData) {
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
// Verify that the recipient name field and test names do appear in the upload
// data.
EXPECT_TRUE(GetUploadData().find(PaymentsClient::kRecipientName) !=
std::string::npos);
EXPECT_TRUE(GetUploadData().find("John") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("Smith") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("Pat") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("Jones") != std::string::npos);
// Verify that the phone number field and test numbers do appear in the upload
// data.
EXPECT_TRUE(GetUploadData().find(PaymentsClient::kPhoneNumber) !=
std::string::npos);
EXPECT_TRUE(GetUploadData().find("212") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("555") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("0162") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("834") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("0090") != std::string::npos);
}
TEST_F(PaymentsClientTest,
UploadRequestIncludesBillingCustomerNumberInRequest) {
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
// Verify that the billing customer number is included in the request.
EXPECT_TRUE(
GetUploadData().find("%22external_customer_id%22:%22111222333444%22") !=
std::string::npos);
}
TEST_F(PaymentsClientTest, UploadIncludesCvcInRequestIfProvided) {
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
// Verify that the encrypted_cvc and s7e_13_cvc parameters were included in
// the request.
EXPECT_TRUE(GetUploadData().find("encrypted_cvc") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("__param:s7e_13_cvc") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=") != std::string::npos);
}
TEST_F(PaymentsClientTest, UploadIncludesChromeUserContext) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
features::kAutofillEnableAccountWalletStorage);
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest,
UploadIncludesChromeUserContextIfWalletStorageFlagEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kAutofillEnableAccountWalletStorage);
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest, UploadDoesNotIncludeCvcInRequestIfNotProvided) {
StartUploading(/*include_cvc=*/false);
IssueOAuthToken();
EXPECT_TRUE(!GetUploadData().empty());
// Verify that the encrypted_cvc and s7e_13_cvc parameters were not included
// in the request.
EXPECT_TRUE(GetUploadData().find("encrypted_cvc") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("__param:s7e_13_cvc") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=") == std::string::npos);
}
TEST_F(PaymentsClientTest, UploadIncludesCardNickname) {
StartUploading(/*include_cvc=*/true, /*include_nickname=*/true);
IssueOAuthToken();
// Card nickname was set.
EXPECT_TRUE(GetUploadData().find("nickname") != std::string::npos);
EXPECT_TRUE(GetUploadData().find(base::UTF16ToUTF8(upstream_nickname_)) !=
std::string::npos);
}
TEST_F(PaymentsClientTest, UploadDoesNotIncludeCardNicknameEmptyNickname) {
StartUploading(/*include_cvc=*/true, /*include_nickname=*/false);
IssueOAuthToken();
// Card nickname was not set.
EXPECT_FALSE(GetUploadData().find("nickname") != std::string::npos);
}
TEST_F(PaymentsClientTest, UnmaskMissingPan) {
StartUnmasking(CardUnmaskOptions());
ReturnResponse(net::HTTP_OK, "{}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
}
TEST_F(PaymentsClientTest, UnmaskRetryFailure) {
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"error\": { \"code\": \"INTERNAL\" } }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kTryAgainFailure, result_);
EXPECT_EQ("", unmask_response_details_->real_pan);
}
TEST_F(PaymentsClientTest, UnmaskPermanentFailure) {
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"error\": { \"code\": \"ANYTHING_ELSE\" } }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
EXPECT_EQ("", unmask_response_details_->real_pan);
}
TEST_F(PaymentsClientTest, UnmaskMalformedResponse) {
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"error_code\": \"WRONG_JSON_FORMAT\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
EXPECT_EQ("", unmask_response_details_->real_pan);
}
TEST_F(PaymentsClientTest, ReauthNeeded) {
{
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
ReturnResponse(net::HTTP_UNAUTHORIZED, "");
// No response yet.
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kNone, result_);
EXPECT_EQ(nullptr, unmask_response_details_.get());
// Second HTTP_UNAUTHORIZED causes permanent failure.
IssueOAuthToken();
ReturnResponse(net::HTTP_UNAUTHORIZED, "");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
EXPECT_EQ("", unmask_response_details_->real_pan);
}
result_ = AutofillClient::PaymentsRpcResult::kNone;
unmask_response_details_ = nullptr;
{
StartUnmasking(CardUnmaskOptions());
// NOTE: Don't issue an access token here: the issuing of an access token
// first waits for the access token request to be received, but here there
// should be no access token request because PaymentsClient should reuse the
// access token from the previous request.
ReturnResponse(net::HTTP_UNAUTHORIZED, "");
// No response yet.
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kNone, result_);
EXPECT_EQ(nullptr, unmask_response_details_.get());
// HTTP_OK after first HTTP_UNAUTHORIZED results in success.
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("1234", unmask_response_details_->real_pan);
}
}
TEST_F(PaymentsClientTest, NetworkError) {
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
ReturnResponse(net::HTTP_REQUEST_TIMEOUT, std::string());
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kNetworkError, result_);
EXPECT_EQ("", unmask_response_details_->real_pan);
}
TEST_F(PaymentsClientTest, OtherError) {
StartUnmasking(CardUnmaskOptions());
IssueOAuthToken();
ReturnResponse(net::HTTP_FORBIDDEN, std::string());
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
EXPECT_EQ("", unmask_response_details_->real_pan);
}
TEST_F(PaymentsClientTest, VcnRetrievalTryAgainFailure) {
StartUnmasking(CardUnmaskOptions().with_virtual_card());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
"\"api_error_reason\": \"virtual_card_temporary_error\" } }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure,
result_);
}
TEST_F(PaymentsClientTest, VcnRetrievalPermanentFailure) {
StartUnmasking(CardUnmaskOptions().with_virtual_card());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
"\"api_error_reason\": \"virtual_card_permanent_error\"} }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure,
result_);
}
TEST_F(PaymentsClientTest, UnmaskPermanentFailureWhenVcnMissingExpiration) {
StartUnmasking(CardUnmaskOptions().with_virtual_card());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"pan\": \"4111111111111111\", \"dcvv\": \"999\" }");
EXPECT_EQ("4111111111111111", unmask_response_details_->real_pan);
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
}
TEST_F(PaymentsClientTest, UnmaskPermanentFailureWhenVcnMissingCvv) {
StartUnmasking(CardUnmaskOptions().with_virtual_card());
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"pan\": \"4111111111111111\", \"expiration\": { "
"\"month\":12, \"year\":2099 } }");
EXPECT_EQ("4111111111111111", unmask_response_details_->real_pan);
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
}
// Tests for the local card migration flow. Desktop only.
#if !defined(OS_ANDROID) && !defined(OS_IOS)
TEST_F(PaymentsClientTest, GetDetailsFollowedByMigrationSuccess) {
StartGettingUploadDetails();
ReturnResponse(
net::HTTP_OK,
"{ \"context_token\": \"some_token\", \"legal_message\": {} }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
result_ = AutofillClient::PaymentsRpcResult::kNone;
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
ReturnResponse(
net::HTTP_OK,
"{\"save_result\":[],\"value_prop_display_text\":\"display text\"}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
}
TEST_F(PaymentsClientTest, MigrateCardsVariationsTest) {
// Register a trial and variation id, so that there is data in variations
// headers.
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
// Note that experiment information is stored in X-Client-Data.
EXPECT_TRUE(HasVariationsHeader());
}
TEST_F(PaymentsClientTest, MigrationRequestIncludesUniqueId) {
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
// Verify that the unique id was included in the request.
EXPECT_TRUE(GetUploadData().find("unique_id") != std::string::npos);
EXPECT_TRUE(
GetUploadData().find(migratable_credit_cards_[0].credit_card().guid()) !=
std::string::npos);
EXPECT_TRUE(
GetUploadData().find(migratable_credit_cards_[1].credit_card().guid()) !=
std::string::npos);
}
TEST_F(PaymentsClientTest, MigrationRequestIncludesEncryptedPan) {
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
// Verify that the encrypted_pan and s7e_1_pan parameters were included
// in the request.
EXPECT_TRUE(GetUploadData().find("encrypted_pan") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("__param:s7e_1_pan0") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("&s7e_1_pan0=4111111111111111") !=
std::string::npos);
EXPECT_TRUE(GetUploadData().find("__param:s7e_1_pan1") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("&s7e_1_pan1=378282246310005") !=
std::string::npos);
}
TEST_F(PaymentsClientTest, MigrationRequestIncludesCardholderNameWhenItExists) {
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
EXPECT_TRUE(!GetUploadData().empty());
// Verify that the cardholder name is sent if it exists.
EXPECT_TRUE(GetUploadData().find("cardholder_name") != std::string::npos);
}
TEST_F(PaymentsClientTest,
MigrationRequestExcludesCardholderNameWhenItDoesNotExist) {
StartMigrating(/*has_cardholder_name=*/false);
IssueOAuthToken();
EXPECT_TRUE(!GetUploadData().empty());
// Verify that the cardholder name is not sent if it doesn't exist.
EXPECT_TRUE(GetUploadData().find("cardholder_name") == std::string::npos);
}
TEST_F(PaymentsClientTest, MigrationRequestIncludesChromeUserContext) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndDisableFeature(
features::kAutofillEnableAccountWalletStorage);
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest,
MigrationRequestIncludesChromeUserContextIfWalletStorageFlagEnabled) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
features::kAutofillEnableAccountWalletStorage);
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
// ChromeUserContext was set.
EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
}
TEST_F(PaymentsClientTest, MigrationRequestIncludesCardNickname) {
StartMigrating(/*has_cardholder_name=*/true,
/*set_nickname_to_first_card=*/true);
IssueOAuthToken();
// Nickname was set for the first card.
std::size_t pos = GetUploadData().find("nickname");
EXPECT_TRUE(pos != std::string::npos);
EXPECT_TRUE(GetUploadData().find(base::UTF16ToUTF8(
migratable_credit_cards_[0].credit_card().nickname())) !=
std::string::npos);
// Nickname was not set for the second card.
EXPECT_FALSE(GetUploadData().find("nickname", pos + 1) != std::string::npos);
}
TEST_F(PaymentsClientTest, MigrationSuccessWithSaveResult) {
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{\"save_result\":[{\"unique_id\":\"0\",\"status\":"
"\"SUCCESS\"},{\"unique_id\":\"1\",\"status\":\"TEMPORARY_"
"FAILURE\"}],\"value_prop_display_text\":\"display text\"}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_TRUE(migration_save_results_.get());
EXPECT_TRUE(migration_save_results_->find("0") !=
migration_save_results_->end());
EXPECT_TRUE(migration_save_results_->at("0") == "SUCCESS");
EXPECT_TRUE(migration_save_results_->find("1") !=
migration_save_results_->end());
EXPECT_TRUE(migration_save_results_->at("1") == "TEMPORARY_FAILURE");
}
TEST_F(PaymentsClientTest, MigrationMissingSaveResult) {
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{\"value_prop_display_text\":\"display text\"}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
EXPECT_EQ(nullptr, migration_save_results_.get());
}
TEST_F(PaymentsClientTest, MigrationSuccessWithDisplayText) {
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{\"save_result\":[{\"unique_id\":\"0\",\"status\":"
"\"SUCCESS\"}],\"value_prop_display_text\":\"display text\"}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("display text", display_text_);
}
#endif
TEST_F(PaymentsClientTest, SelectChallengeOptionWithSmsOtpMethod) {
StartSelectingChallengeOption(CardUnmaskChallengeOptionType::kSmsOtp,
"arbitrary id for sms otp");
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"new context token\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
assertIncludedInRequest("context_token");
assertIncludedInRequest("external_customer_id");
assertIncludedInRequest("selected_idv_challenge_option");
assertIncludedInRequest("sms_otp_challenge_option");
// We should only set the challenge id. No need to send the masked phone
// number.
assertIncludedInRequest("challenge_id");
assertIncludedInRequest("arbitrary id for sms otp");
assertNotIncludedInRequest("masked_phone_number");
}
TEST_F(PaymentsClientTest, SelectChallengeOptionSuccess) {
StartSelectingChallengeOption();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"new context token\" }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kSuccess, result_);
EXPECT_EQ("new context token", context_token_);
}
TEST_F(PaymentsClientTest, SelectChallengeOptionTemporaryFailure) {
StartSelectingChallengeOption();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
"\"api_error_reason\": \"virtual_card_temporary_error\"} }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure,
result_);
}
TEST_F(PaymentsClientTest, SelectChallengeOptionVcnFlowPermanentFailure) {
StartSelectingChallengeOption();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
"\"api_error_reason\": \"virtual_card_permanent_error\"} }");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure,
result_);
}
TEST_F(PaymentsClientTest, SelectChallengeOptionResponseMissingContextToken) {
StartSelectingChallengeOption();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
EXPECT_EQ(AutofillClient::PaymentsRpcResult::kPermanentFailure, result_);
}
typedef std::tuple<VirtualCardEnrollmentSource,
VirtualCardEnrollmentRequestType,
AutofillClient::PaymentsRpcResult>
UpdateVirtualCardEnrollmentTestData;
class UpdateVirtualCardEnrollmentTest
: public PaymentsClientTest,
public ::testing::WithParamInterface<
UpdateVirtualCardEnrollmentTestData> {
public:
UpdateVirtualCardEnrollmentTest() = default;
~UpdateVirtualCardEnrollmentTest() override = default;
void TriggerFlow() {
VirtualCardEnrollmentSource virtual_card_enrollment_source =
std::get<0>(GetParam());
VirtualCardEnrollmentRequestType virtual_card_enrollment_request_type =
std::get<1>(GetParam());
StartUpdateVirtualCardEnrollment(virtual_card_enrollment_source,
virtual_card_enrollment_request_type);
IssueOAuthToken();
// |response_type_for_test| is the AutofillClient::PaymentsRpcResult
// response type we want to test for the combination of
// |virtual_card_enrollment_source| and
// |virtual_card_enrollment_request_type| we are currently on.
AutofillClient::PaymentsRpcResult response_type_for_test =
std::get<2>(GetParam());
switch (response_type_for_test) {
case AutofillClient::PaymentsRpcResult::kSuccess:
if (virtual_card_enrollment_request_type ==
VirtualCardEnrollmentRequestType::kEnroll) {
ReturnResponse(net::HTTP_OK,
"{ \"enroll_result\": \"ENROLL_SUCCESS\" }");
} else if (virtual_card_enrollment_request_type ==
VirtualCardEnrollmentRequestType::kUnenroll) {
ReturnResponse(net::HTTP_OK, "{}");
}
break;
case AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure:
ReturnResponse(
net::HTTP_OK,
"{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
"\"api_error_reason\": \"virtual_card_temporary_error\"} }");
break;
case AutofillClient::PaymentsRpcResult::kTryAgainFailure:
ReturnResponse(net::HTTP_OK,
"{ \"error\": { \"code\": \"INTERNAL\", "
"\"api_error_reason\": \"ANYTHING_ELSE\"} }");
break;
case AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure:
ReturnResponse(
net::HTTP_OK,
"{ \"error\": { \"code\": \"ANYTHING_ELSE\", "
"\"api_error_reason\": \"virtual_card_permanent_error\"} }");
break;
case AutofillClient::PaymentsRpcResult::kPermanentFailure:
ReturnResponse(net::HTTP_OK,
"{ \"error\": { \"code\": \"ANYTHING_ELSE\" } }");
break;
case AutofillClient::PaymentsRpcResult::kNetworkError:
ReturnResponse(net::HTTP_REQUEST_TIMEOUT, "");
break;
case AutofillClient::PaymentsRpcResult::kNone:
NOTREACHED();
break;
}
EXPECT_EQ(response_type_for_test, result_);
}
private:
void StartUpdateVirtualCardEnrollment(
VirtualCardEnrollmentSource virtual_card_enrollment_source,
VirtualCardEnrollmentRequestType virtual_card_enrollment_request_type) {
PaymentsClient::UpdateVirtualCardEnrollmentRequestDetails request_details;
request_details.virtual_card_enrollment_request_type =
virtual_card_enrollment_request_type;
request_details.virtual_card_enrollment_source =
virtual_card_enrollment_source;
request_details.billing_customer_number = 555666777888;
if (virtual_card_enrollment_request_type ==
VirtualCardEnrollmentRequestType::kEnroll) {
request_details.vcn_context_token = "fake context token";
} else if (virtual_card_enrollment_request_type ==
VirtualCardEnrollmentRequestType::kUnenroll) {
request_details.instrument_id = 12345678;
}
client_->UpdateVirtualCardEnrollment(
request_details,
base::BindOnce(
&PaymentsClientTest::OnDidGetUpdateVirtualCardEnrollmentResponse,
weak_ptr_factory_.GetWeakPtr()));
}
};
// Initializes the parameterized test suite with all possible values of
// VirtualCardEnrollmentSource, VirtualCardEnrollmentRequestType, and
// AutofillClient::PaymentsRpcResult.
INSTANTIATE_TEST_SUITE_P(
,
UpdateVirtualCardEnrollmentTest,
testing::Combine(
testing::Values(VirtualCardEnrollmentSource::kUpstream,
VirtualCardEnrollmentSource::kDownstream,
VirtualCardEnrollmentSource::kSettingsPage),
testing::Values(VirtualCardEnrollmentRequestType::kEnroll,
VirtualCardEnrollmentRequestType::kUnenroll),
testing::Values(
AutofillClient::PaymentsRpcResult::kSuccess,
AutofillClient::PaymentsRpcResult::kVcnRetrievalTryAgainFailure,
AutofillClient::PaymentsRpcResult::kTryAgainFailure,
AutofillClient::PaymentsRpcResult::kVcnRetrievalPermanentFailure,
AutofillClient::PaymentsRpcResult::kPermanentFailure,
AutofillClient::PaymentsRpcResult::kNetworkError)));
// Parameterized test that tests all combinations of
// VirtualCardEnrollmentSource and VirtualCardEnrollmentRequestType against all
// possible server responses in the UpdateVirtualCardEnrollmentFlow. This test
// will be run once for each combination.
TEST_P(UpdateVirtualCardEnrollmentTest,
UpdateVirtualCardEnrollmentTest_TestAllFlows) {
TriggerFlow();
}
} // namespace payments
} // namespace autofill