blob: 8e42bff27b02f93352200a773c05398399b9d6d0 [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 <utility>
#include <vector>
#include "base/command_line.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/credit_card_save_manager.h"
#include "components/autofill/core/browser/local_card_migration_manager.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/test_personal_data_manager.h"
#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "components/variations/variations_associated_data.h"
#include "components/variations/variations_http_header_provider.h"
#include "services/identity/public/cpp/identity_test_environment.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;
} // namespace
class PaymentsClientTest : public testing::Test {
public:
PaymentsClientTest()
: result_(AutofillClient::NONE), weak_ptr_factory_(this) {}
~PaymentsClientTest() override {}
void SetUp() override {
// Silence the warning for mismatching sync and Payments servers.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kWalletServiceUseSandbox, "0");
result_ = AutofillClient::NONE;
server_id_.clear();
real_pan_.clear();
legal_message_.reset();
factory()->SetInterceptor(base::BindLambdaForTesting(
[&](const network::ResourceRequest& request) {
intercepted_headers_ = request.headers;
intercepted_body_ = network::GetUploadData(request);
}));
test_shared_loader_factory_ =
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
TestingPrefServiceSimple pref_service_;
client_ = std::make_unique<PaymentsClient>(
test_shared_loader_factory_, &pref_service_,
identity_test_env_.identity_manager(), &test_personal_data_);
test_personal_data_.SetAccountInfoForPayments(
identity_test_env_.MakePrimaryAccountAvailable("example@gmail.com"));
}
void TearDown() override { client_.reset(); }
void EnableAutofillSendExperimentIdsInPaymentsRPCs() {
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillSendExperimentIdsInPaymentsRPCs);
}
void EnableAutofillGetPaymentsIdentityFromSync() {
scoped_feature_list_.InitAndEnableFeature(
features::kAutofillGetPaymentsIdentityFromSync);
}
void DisableAutofillSendExperimentIdsInPaymentsRPCs() {
scoped_feature_list_.InitAndDisableFeature(
features::kAutofillSendExperimentIdsInPaymentsRPCs);
}
// 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, trial_name, group_name,
static_cast<variations::VariationID>(variation_id));
base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group();
}
void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
const std::string& real_pan) {
result_ = result;
real_pan_ = real_pan;
}
void OnDidGetUploadDetails(
AutofillClient::PaymentsRpcResult result,
const base::string16& context_token,
std::unique_ptr<base::DictionaryValue> legal_message) {
result_ = result;
legal_message_ = std::move(legal_message);
}
void OnDidUploadCard(AutofillClient::PaymentsRpcResult result,
const std::string& server_id) {
result_ = result;
server_id_ = server_id;
}
void OnDidMigrateLocalCards(
AutofillClient::PaymentsRpcResult result,
std::unique_ptr<std::unordered_map<std::string, std::string>> save_result,
const std::string& display_text) {
result_ = result;
save_result_ = std::move(save_result);
display_text_ = display_text;
}
protected:
base::test::ScopedFeatureList scoped_feature_list_;
// Issue an UnmaskCard request. This requires an OAuth token before starting
// the request.
void StartUnmasking() {
PaymentsClient::UnmaskRequestDetails request_details;
request_details.billing_customer_number = 111222333444;
request_details.card = test::GetMaskedServerCard();
request_details.user_response.cvc = base::ASCIIToUTF16("123");
request_details.risk_data = "some risk data";
client_->UnmaskCard(request_details,
base::BindOnce(&PaymentsClientTest::OnDidGetRealPan,
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) {
PaymentsClient::UploadRequestDetails request_details;
request_details.billing_customer_number = 111222333444;
request_details.card = test::GetCreditCard();
if (include_cvc)
request_details.cvc = base::ASCIIToUTF16("123");
request_details.context_token = base::ASCIIToUTF16("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()));
}
void StartMigrating(bool has_cardholder_name) {
PaymentsClient::MigrationRequestDetails request_details;
request_details.context_token = base::ASCIIToUTF16("context token");
request_details.risk_data = "some risk data";
request_details.app_locale = "language-LOCALE";
migratable_credit_cards_.clear();
CreditCard card1 = test::GetCreditCard();
CreditCard card2 = test::GetCreditCard2();
if (!has_cardholder_name) {
card1.SetRawInfo(CREDIT_CARD_NAME_FULL, base::UTF8ToUTF16(""));
card2.SetRawInfo(CREDIT_CARD_NAME_FULL, base::UTF8ToUTF16(""));
}
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()));
}
network::TestURLLoaderFactory* factory() { return &test_url_loader_factory_; }
const std::string& GetUploadData() { return intercepted_body_; }
net::HttpRequestHeaders* GetRequestHeaders() { return &intercepted_headers_; }
// 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",
base::Time::Now() + base::TimeDelta::FromDays(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);
}
AutofillClient::PaymentsRpcResult result_;
std::string server_id_;
std::string real_pan_;
std::unique_ptr<base::DictionaryValue> legal_message_;
std::vector<MigratableCreditCard> migratable_credit_cards_;
std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_;
std::string display_text_;
base::test::ScopedTaskEnvironment scoped_task_environment_;
network::TestURLLoaderFactory test_url_loader_factory_;
scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
TestPersonalDataManager test_personal_data_;
std::unique_ptr<PaymentsClient> client_;
identity::IdentityTestEnvironment identity_test_env_;
net::HttpRequestHeaders intercepted_headers_;
std::string intercepted_body_;
base::WeakPtrFactory<PaymentsClientTest> weak_ptr_factory_;
private:
DISALLOW_COPY_AND_ASSIGN(PaymentsClientTest);
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, ASCIIToUTF16(first_name), "en-US");
profile.SetInfo(NAME_LAST, ASCIIToUTF16(last_name), "en-US");
profile.SetInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16(address_line), "en-US");
profile.SetInfo(ADDRESS_HOME_CITY, ASCIIToUTF16(city), "en-US");
profile.SetInfo(ADDRESS_HOME_STATE, ASCIIToUTF16(state), "en-US");
profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16(zip), "en-US");
profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, ASCIIToUTF16(phone_number),
"en-US");
return profile;
}
};
TEST_F(PaymentsClientTest, OAuthError) {
StartUnmasking();
identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
EXPECT_TRUE(real_pan_.empty());
}
TEST_F(PaymentsClientTest,
UnmaskRequestIncludesBillingCustomerNumberInRequest) {
StartUnmasking();
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, UnmaskSuccess) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
EXPECT_EQ("1234", real_pan_);
}
TEST_F(PaymentsClientTest, UnmaskSuccessAccountFromSyncTest) {
EnableAutofillGetPaymentsIdentityFromSync();
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
EXPECT_EQ("1234", real_pan_);
}
TEST_F(PaymentsClientTest, UnmaskIncludesChromeUserContext) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillGetPaymentsIdentityFromSync}, // Enabled
{features::kAutofillEnableAccountWalletStorage}); // Disabled
StartUnmasking();
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) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillEnableAccountWalletStorage}, // Enabled
{features::kAutofillGetPaymentsIdentityFromSync}); // Disabled
StartUnmasking();
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, UnmaskExcludesChromeUserContextIfExperimentsOff) {
scoped_feature_list_.InitWithFeatures(
{}, // Enabled
{features::kAutofillEnableAccountWalletStorage,
features::kAutofillGetPaymentsIdentityFromSync}); // Disabled
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
// ChromeUserContext was not set.
EXPECT_TRUE(!GetUploadData().empty());
EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos);
}
TEST_F(PaymentsClientTest, GetDetailsSuccess) {
StartGettingUploadDetails();
ReturnResponse(
net::HTTP_OK,
"{ \"context_token\": \"some_token\", \"legal_message\": {} }");
EXPECT_EQ(AutofillClient::SUCCESS, 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) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillGetPaymentsIdentityFromSync}, // Enabled
{features::kAutofillEnableAccountWalletStorage}); // Disabled
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) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillEnableAccountWalletStorage}, // Enabled
{features::kAutofillGetPaymentsIdentityFromSync}); // Disabled
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,
GetDetailsExcludesChromeUserContextIfExperimentsOff) {
scoped_feature_list_.InitWithFeatures(
{}, // Enabled
{features::kAutofillEnableAccountWalletStorage,
features::kAutofillGetPaymentsIdentityFromSync}); // Disabled
StartGettingUploadDetails();
// ChromeUserContext was not set.
EXPECT_TRUE(!GetUploadData().empty());
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, GetUploadAccountFromSyncTest) {
EnableAutofillGetPaymentsIdentityFromSync();
// 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",
base::Time::Now() + base::TimeDelta::FromDays(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, GetUploadDetailsVariationsTest) {
// Register a trial and variation id, so that there is data in variations
// headers. Also, the variations header provider may have been registered to
// observe some other field trial list, so reset it.
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
base::FieldTrialList field_trial_list_(nullptr);
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartGettingUploadDetails();
std::string value;
EXPECT_TRUE(GetRequestHeaders()->GetHeader("X-Client-Data", &value));
// Note that experiment information is stored in X-Client-Data.
EXPECT_FALSE(value.empty());
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
}
TEST_F(PaymentsClientTest, GetUploadDetailsVariationsTestExperimentFlagOff) {
// Register a trial and variation id, so that there is data in variations
// headers. Also, the variations header provider may have been registered to
// observe some other field trial list, so reset it.
DisableAutofillSendExperimentIdsInPaymentsRPCs();
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
base::FieldTrialList field_trial_list_(nullptr);
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartGettingUploadDetails();
std::string value;
EXPECT_FALSE(GetRequestHeaders()->GetHeader("X-Client-Data", &value));
// Note that experiment information is stored in X-Client-Data.
EXPECT_TRUE(value.empty());
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
}
TEST_F(PaymentsClientTest, UploadCardVariationsTest) {
// Register a trial and variation id, so that there is data in variations
// headers. Also, the variations header provider may have been registered to
// observe some other field trial list, so reset it.
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
base::FieldTrialList field_trial_list_(nullptr);
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
std::string value;
EXPECT_TRUE(GetRequestHeaders()->GetHeader("X-Client-Data", &value));
// Note that experiment information is stored in X-Client-Data.
EXPECT_FALSE(value.empty());
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
}
TEST_F(PaymentsClientTest, UploadCardVariationsTestExperimentFlagOff) {
// Register a trial and variation id, so that there is data in variations
// headers. Also, the variations header provider may have been registered to
// observe some other field trial list, so reset it.
DisableAutofillSendExperimentIdsInPaymentsRPCs();
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
base::FieldTrialList field_trial_list_(nullptr);
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartUploading(/*include_cvc=*/true);
std::string value;
EXPECT_FALSE(GetRequestHeaders()->GetHeader("X-Client-Data", &value));
// Note that experiment information is stored in X-Client-Data.
EXPECT_TRUE(value.empty());
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
}
TEST_F(PaymentsClientTest, UnmaskCardVariationsTest) {
// Register a trial and variation id, so that there is data in variations
// headers. Also, the variations header provider may have been registered to
// observe some other field trial list, so reset it.
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
base::FieldTrialList field_trial_list_(nullptr);
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartUnmasking();
IssueOAuthToken();
std::string value;
EXPECT_TRUE(GetRequestHeaders()->GetHeader("X-Client-Data", &value));
// Note that experiment information is stored in X-Client-Data.
EXPECT_FALSE(value.empty());
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
}
TEST_F(PaymentsClientTest, UnmaskCardVariationsTestExperimentOff) {
// Register a trial and variation id, so that there is data in variations
// headers. Also, the variations header provider may have been registered to
// observe some other field trial list, so reset it.
DisableAutofillSendExperimentIdsInPaymentsRPCs();
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
base::FieldTrialList field_trial_list_(nullptr);
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartUnmasking();
std::string value;
EXPECT_FALSE(GetRequestHeaders()->GetHeader("X-Client-Data", &value));
// Note that experiment information is stored in X-Client-Data.
EXPECT_TRUE(value.empty());
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
}
TEST_F(PaymentsClientTest, MigrateCardsVariationsTest) {
// Register a trial and variation id, so that there is data in variations
// headers. Also, the variations header provider may have been registered to
// observe some other field trial list, so reset it.
EnableAutofillSendExperimentIdsInPaymentsRPCs();
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
base::FieldTrialList field_trial_list_(nullptr);
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
std::string value;
EXPECT_TRUE(GetRequestHeaders()->GetHeader("X-Client-Data", &value));
// Note that experiment information is stored in X-Client-Data.
EXPECT_FALSE(value.empty());
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
}
TEST_F(PaymentsClientTest, MigrateCardsVariationsTestExperimentFlagOff) {
// Register a trial and variation id, so that there is data in variations
// headers. Also, the variations header provider may have been registered to
// observe some other field trial list, so reset it.
DisableAutofillSendExperimentIdsInPaymentsRPCs();
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
base::FieldTrialList field_trial_list_(nullptr);
CreateFieldTrialWithId("AutofillTest", "Group", 369);
StartMigrating(/*has_cardholder_name=*/true);
std::string value;
EXPECT_FALSE(GetRequestHeaders()->GetHeader("X-Client-Data", &value));
// Note that experiment information is stored in X-Client-Data.
EXPECT_TRUE(value.empty());
variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
}
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, UploadSuccessWithoutServerId) {
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
EXPECT_TRUE(server_id_.empty());
}
TEST_F(PaymentsClientTest, UploadSuccessWithServerId) {
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"credit_card_id\": \"InstrumentData:1\" }");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
EXPECT_EQ("InstrumentData:1", 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) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillGetPaymentsIdentityFromSync}, // Enabled
{features::kAutofillEnableAccountWalletStorage}); // Disabled
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) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillEnableAccountWalletStorage}, // Enabled
{features::kAutofillGetPaymentsIdentityFromSync}); // Disabled
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, UploadExcludesChromeUserContextIfExperimentsOff) {
scoped_feature_list_.InitWithFeatures(
{}, // Enabled
{features::kAutofillEnableAccountWalletStorage,
features::kAutofillGetPaymentsIdentityFromSync}); // Disabled
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
// ChromeUserContext was not set.
EXPECT_TRUE(!GetUploadData().empty());
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, 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) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillGetPaymentsIdentityFromSync}, // Enabled
{features::kAutofillEnableAccountWalletStorage}); // Disabled
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) {
scoped_feature_list_.InitWithFeatures(
{features::kAutofillEnableAccountWalletStorage}, // Enabled
{features::kAutofillGetPaymentsIdentityFromSync}); // Disabled
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,
MigrationRequestExcludesChromeUserContextIfExperimentsOff) {
scoped_feature_list_.InitWithFeatures(
{}, // Enabled
{features::kAutofillEnableAccountWalletStorage,
features::kAutofillGetPaymentsIdentityFromSync}); // Disabled
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
// ChromeUserContext was not set.
EXPECT_TRUE(!GetUploadData().empty());
EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos);
EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == 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::SUCCESS, result_);
EXPECT_TRUE(save_result_.get());
EXPECT_TRUE(save_result_->find("0") != save_result_->end());
EXPECT_TRUE(save_result_->at("0") == "SUCCESS");
EXPECT_TRUE(save_result_->find("1") != save_result_->end());
EXPECT_TRUE(save_result_->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::PERMANENT_FAILURE, result_);
EXPECT_EQ(nullptr, save_result_.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::SUCCESS, result_);
EXPECT_EQ("display text", display_text_);
}
TEST_F(PaymentsClientTest, GetDetailsFollowedByUploadSuccess) {
StartGettingUploadDetails();
ReturnResponse(
net::HTTP_OK,
"{ \"context_token\": \"some_token\", \"legal_message\": {} }");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
result_ = AutofillClient::NONE;
StartUploading(/*include_cvc=*/true);
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{}");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
}
TEST_F(PaymentsClientTest, GetDetailsFollowedByMigrationSuccess) {
StartGettingUploadDetails();
ReturnResponse(
net::HTTP_OK,
"{ \"context_token\": \"some_token\", \"legal_message\": {} }");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
result_ = AutofillClient::NONE;
StartMigrating(/*has_cardholder_name=*/true);
IssueOAuthToken();
ReturnResponse(
net::HTTP_OK,
"{\"save_result\":[],\"value_prop_display_text\":\"display text\"}");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
}
TEST_F(PaymentsClientTest, UnmaskMissingPan) {
StartUnmasking();
ReturnResponse(net::HTTP_OK, "{}");
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
}
TEST_F(PaymentsClientTest, GetDetailsMissingContextToken) {
StartGettingUploadDetails();
ReturnResponse(net::HTTP_OK, "{ \"legal_message\": {} }");
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
}
TEST_F(PaymentsClientTest, GetDetailsMissingLegalMessage) {
StartGettingUploadDetails();
ReturnResponse(net::HTTP_OK, "{ \"context_token\": \"some_token\" }");
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
EXPECT_EQ(nullptr, legal_message_.get());
}
TEST_F(PaymentsClientTest, RetryFailure) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"error\": { \"code\": \"INTERNAL\" } }");
EXPECT_EQ(AutofillClient::TRY_AGAIN_FAILURE, result_);
EXPECT_EQ("", real_pan_);
}
TEST_F(PaymentsClientTest, PermanentFailure) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK,
"{ \"error\": { \"code\": \"ANYTHING_ELSE\" } }");
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
EXPECT_EQ("", real_pan_);
}
TEST_F(PaymentsClientTest, MalformedResponse) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"error_code\": \"WRONG_JSON_FORMAT\" }");
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
EXPECT_EQ("", real_pan_);
}
TEST_F(PaymentsClientTest, ReauthNeeded) {
{
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_UNAUTHORIZED, "");
// No response yet.
EXPECT_EQ(AutofillClient::NONE, result_);
EXPECT_EQ("", real_pan_);
// Second HTTP_UNAUTHORIZED causes permanent failure.
IssueOAuthToken();
ReturnResponse(net::HTTP_UNAUTHORIZED, "");
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
EXPECT_EQ("", real_pan_);
}
result_ = AutofillClient::NONE;
real_pan_.clear();
{
StartUnmasking();
// 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::NONE, result_);
EXPECT_EQ("", real_pan_);
// HTTP_OK after first HTTP_UNAUTHORIZED results in success.
IssueOAuthToken();
ReturnResponse(net::HTTP_OK, "{ \"pan\": \"1234\" }");
EXPECT_EQ(AutofillClient::SUCCESS, result_);
EXPECT_EQ("1234", real_pan_);
}
}
TEST_F(PaymentsClientTest, NetworkError) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_REQUEST_TIMEOUT, std::string());
EXPECT_EQ(AutofillClient::NETWORK_ERROR, result_);
EXPECT_EQ("", real_pan_);
}
TEST_F(PaymentsClientTest, OtherError) {
StartUnmasking();
IssueOAuthToken();
ReturnResponse(net::HTTP_FORBIDDEN, std::string());
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
EXPECT_EQ("", real_pan_);
}
} // namespace payments
} // namespace autofill