blob: 98836ee81db5356710a4e2efca3d6350595be114 [file] [log] [blame]
// Copyright (c) 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 "base/command_line.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/sync/test/integration/autofill_helper.h"
#include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
#include "chrome/browser/sync/test/integration/single_client_status_change_checker.h"
#include "chrome/browser/sync/test/integration/sync_integration_test_util.h"
#include "chrome/browser/sync/test/integration/sync_test.h"
#include "chrome/browser/web_data_service_factory.h"
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/browser_sync/browser/profile_sync_service.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/notification_service.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/test/fake_server/fake_server_entity.h"
#include "sync/test/fake_server/unique_client_entity.h"
using autofill_helper::GetPersonalDataManager;
using sync_integration_test_util::AwaitCommitActivityCompletion;
namespace {
// Setting the Preferences files contents to this string (before Profile is
// created) will bypass the Sync experiment logic for enabling this feature.
const char kWalletSyncEnabledPreferencesContents[] =
"{\"autofill\": { \"wallet_import_sync_experiment_enabled\": true } }";
const char kWalletSyncExperimentTag[] = "wallet_sync";
const char kDefaultCardID[] = "wallet entity ID";
const int kDefaultCardExpMonth = 8;
const int kDefaultCardExpYear = 2087;
const char kDefaultCardLastFour[] = "1234";
const char kDefaultCardName[] = "Patrick Valenzuela";
const sync_pb::WalletMaskedCreditCard_WalletCardType kDefaultCardType =
sync_pb::WalletMaskedCreditCard::AMEX;
void AddDefaultCard(fake_server::FakeServer* server) {
sync_pb::EntitySpecifics specifics;
sync_pb::AutofillWalletSpecifics* wallet_specifics =
specifics.mutable_autofill_wallet();
wallet_specifics->set_type(
sync_pb::AutofillWalletSpecifics::MASKED_CREDIT_CARD);
sync_pb::WalletMaskedCreditCard* credit_card =
wallet_specifics->mutable_masked_card();
credit_card->set_id(kDefaultCardID);
credit_card->set_exp_month(kDefaultCardExpMonth);
credit_card->set_exp_year(kDefaultCardExpYear);
credit_card->set_last_four(kDefaultCardLastFour);
credit_card->set_name_on_card(kDefaultCardName);
credit_card->set_status(sync_pb::WalletMaskedCreditCard::VALID);
credit_card->set_type(kDefaultCardType);
server->InjectEntity(fake_server::UniqueClientEntity::CreateForInjection(
kDefaultCardID,
specifics));
}
} // namespace
class SingleClientWalletSyncTest : public SyncTest {
public:
SingleClientWalletSyncTest() : SyncTest(SINGLE_CLIENT) {}
~SingleClientWalletSyncTest() override {}
void TriggerSyncCycle() {
// Note: we use the experiments type here as we want to be able to trigger a
// sync cycle even when wallet is not enabled yet.
const syncer::ModelTypeSet kExperimentsType(syncer::EXPERIMENTS);
TriggerSyncForModelTypes(0, kExperimentsType);
}
private:
DISALLOW_COPY_AND_ASSIGN(SingleClientWalletSyncTest);
};
// Checker that will wait until an asynchronous Wallet datatype enable event
// happens, or times out.
class WalletEnabledChecker : public SingleClientStatusChangeChecker {
public:
WalletEnabledChecker()
: SingleClientStatusChangeChecker(
sync_datatype_helper::test()->GetSyncService(0)) {}
~WalletEnabledChecker() override {}
// SingleClientStatusChangeChecker overrides.
bool IsExitConditionSatisfied() override {
return service()->GetActiveDataTypes().Has(syncer::AUTOFILL_WALLET_DATA);
}
std::string GetDebugMessage() const override {
return "Waiting for wallet enable event.";
}
};
// Checker that will wait until an asynchronous Wallet datatype disable event
// happens, or times out
class WalletDisabledChecker : public SingleClientStatusChangeChecker {
public:
WalletDisabledChecker()
: SingleClientStatusChangeChecker(
sync_datatype_helper::test()->GetSyncService(0)) {}
~WalletDisabledChecker() override {}
// SingleClientStatusChangeChecker overrides.
bool IsExitConditionSatisfied() override {
return !service()->GetActiveDataTypes().Has(syncer::AUTOFILL_WALLET_DATA);
}
std::string GetDebugMessage() const override {
return "Waiting for wallet disable event.";
}
};
IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, DisabledByDefault) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
// The type should not be enabled without the experiment enabled.
ASSERT_FALSE(GetClient(0)->service()->GetActiveDataTypes().Has(
syncer::AUTOFILL_WALLET_DATA));
ASSERT_FALSE(GetClient(0)->service()->GetActiveDataTypes().Has(
syncer::AUTOFILL_WALLET_METADATA));
}
IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, EnabledViaPreference) {
SetPreexistingPreferencesFileContents(kWalletSyncEnabledPreferencesContents);
ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
// The type should not be enabled without the experiment enabled.
ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
syncer::AUTOFILL_WALLET_DATA));
// TODO(pvalenzuela): Assert that the local root node for AUTOFILL_WALLET_DATA
// exists.
ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
syncer::AUTOFILL_WALLET_METADATA));
}
// Tests that an experiment received at sync startup time (during sign-in)
// enables the wallet datatype.
IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
EnabledViaExperimentStartup) {
sync_pb::EntitySpecifics experiment_entity;
sync_pb::ExperimentsSpecifics* experiment_specifics =
experiment_entity.mutable_experiments();
experiment_specifics->mutable_wallet_sync()->set_enabled(true);
GetFakeServer()->InjectEntity(
fake_server::UniqueClientEntity::CreateForInjection(
kWalletSyncExperimentTag,
experiment_entity));
ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
syncer::AUTOFILL_WALLET_DATA));
ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
syncer::AUTOFILL_WALLET_METADATA));
}
// Tests receiving an enable experiment at runtime, followed by a disabled
// experiment, and verifies the datatype is enabled/disabled as necessary.
IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
EnabledDisabledViaExperiment) {
ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
ASSERT_FALSE(GetClient(0)->service()->GetActiveDataTypes().
Has(syncer::AUTOFILL_WALLET_DATA));
sync_pb::EntitySpecifics experiment_entity;
sync_pb::ExperimentsSpecifics* experiment_specifics =
experiment_entity.mutable_experiments();
// First enable the experiment.
experiment_specifics->mutable_wallet_sync()->set_enabled(true);
GetFakeServer()->InjectEntity(
fake_server::UniqueClientEntity::CreateForInjection(
kWalletSyncExperimentTag, experiment_entity));
TriggerSyncCycle();
WalletEnabledChecker enabled_checker;
enabled_checker.Wait();
ASSERT_FALSE(enabled_checker.TimedOut());
ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
syncer::AUTOFILL_WALLET_DATA));
ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
syncer::AUTOFILL_WALLET_METADATA));
// Then disable the experiment.
experiment_specifics->mutable_wallet_sync()->set_enabled(false);
GetFakeServer()->InjectEntity(
fake_server::UniqueClientEntity::CreateForInjection(
kWalletSyncExperimentTag, experiment_entity));
TriggerSyncCycle();
WalletDisabledChecker disable_checker;
disable_checker.Wait();
ASSERT_FALSE(disable_checker.TimedOut());
ASSERT_FALSE(GetClient(0)->service()->GetActiveDataTypes().
Has(syncer::AUTOFILL_WALLET_DATA));
ASSERT_FALSE(GetClient(0)->service()->GetActiveDataTypes().Has(
syncer::AUTOFILL_WALLET_METADATA));
}
IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, Download) {
SetPreexistingPreferencesFileContents(kWalletSyncEnabledPreferencesContents);
AddDefaultCard(GetFakeServer());
ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
ASSERT_TRUE(pdm != nullptr);
std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
ASSERT_EQ(1uL, cards.size());
autofill::CreditCard* card = cards[0];
ASSERT_EQ(autofill::CreditCard::MASKED_SERVER_CARD, card->record_type());
ASSERT_EQ(kDefaultCardID, card->server_id());
ASSERT_EQ(base::UTF8ToUTF16(kDefaultCardLastFour), card->LastFourDigits());
ASSERT_EQ(autofill::kAmericanExpressCard, card->type());
ASSERT_EQ(kDefaultCardExpMonth, card->expiration_month());
ASSERT_EQ(kDefaultCardExpYear, card->expiration_year());
ASSERT_EQ(base::UTF8ToUTF16(kDefaultCardName),
card->GetRawInfo(autofill::ServerFieldType::CREDIT_CARD_NAME));
}
// Wallet data should get cleared from the database when sync is disabled.
IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnDisableSync) {
SetPreexistingPreferencesFileContents(kWalletSyncEnabledPreferencesContents);
AddDefaultCard(GetFakeServer());
ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
// Make sure the card is in the DB.
autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
ASSERT_TRUE(pdm != nullptr);
std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
ASSERT_EQ(1uL, cards.size());
// Turn off sync, the card should be gone.
ASSERT_TRUE(GetClient(0)->DisableSyncForAllDatatypes());
cards = pdm->GetCreditCards();
ASSERT_EQ(0uL, cards.size());
}
// Wallet data should get cleared from the database when the wallet sync type
// flag is disabled.
IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest, ClearOnDisableWalletSync) {
SetPreexistingPreferencesFileContents(kWalletSyncEnabledPreferencesContents);
AddDefaultCard(GetFakeServer());
ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
// Make sure the card is in the DB.
autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
ASSERT_TRUE(pdm != nullptr);
std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
ASSERT_EQ(1uL, cards.size());
// Turn off autofill sync, the card should be gone.
ASSERT_TRUE(GetClient(0)->DisableSyncForDatatype(syncer::AUTOFILL));
cards = pdm->GetCreditCards();
ASSERT_EQ(0uL, cards.size());
}
// Wallet data should get cleared from the database when the wallet autofill
// integration flag is disabled.
IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
ClearOnDisableWalletAutofill) {
SetPreexistingPreferencesFileContents(kWalletSyncEnabledPreferencesContents);
AddDefaultCard(GetFakeServer());
ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
// Make sure the card is in the DB.
autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
ASSERT_TRUE(pdm != nullptr);
std::vector<autofill::CreditCard*> cards = pdm->GetCreditCards();
ASSERT_EQ(1uL, cards.size());
// Turn off the wallet autofill pref, the card should be gone as a side
// effect of the wallet data type controller noticing.
GetProfile(0)->GetPrefs()->SetBoolean(
autofill::prefs::kAutofillWalletImportEnabled, false);
cards = pdm->GetCreditCards();
ASSERT_EQ(0uL, cards.size());
}