Chromium Code Reviews| Index: chrome/browser/signin/cross_device_promo_unittest.cc |
| diff --git a/chrome/browser/signin/cross_device_promo_unittest.cc b/chrome/browser/signin/cross_device_promo_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..e9d5cd4e938cfec3fc84698dfccc514421f3b90c |
| --- /dev/null |
| +++ b/chrome/browser/signin/cross_device_promo_unittest.cc |
| @@ -0,0 +1,612 @@ |
| +// 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 "chrome/browser/signin/cross_device_promo.h" |
| + |
| +#include "base/metrics/field_trial.h" |
| +#include "base/run_loop.h" |
| +#include "base/test/histogram_tester.h" |
| +#include "chrome/browser/prefs/browser_prefs.h" |
| +#include "chrome/browser/prefs/pref_service_syncable.h" |
| +#include "chrome/browser/signin/chrome_signin_client_factory.h" |
| +#include "chrome/browser/signin/cross_device_promo_factory.h" |
| +#include "chrome/browser/signin/fake_gaia_cookie_manager_service.h" |
| +#include "chrome/browser/signin/fake_signin_manager.h" |
| +#include "chrome/browser/signin/gaia_cookie_manager_service_factory.h" |
| +#include "chrome/browser/signin/signin_manager_factory.h" |
| +#include "chrome/browser/signin/test_signin_client_builder.h" |
| +#include "chrome/common/pref_names.h" |
| +#include "chrome/test/base/testing_browser_process.h" |
| +#include "chrome/test/base/testing_pref_service_syncable.h" |
| +#include "chrome/test/base/testing_profile.h" |
| +#include "chrome/test/base/testing_profile_manager.h" |
| +#include "components/signin/core/browser/signin_manager.h" |
| +#include "components/signin/core/browser/signin_metrics.h" |
| +#include "components/signin/core/browser/test_signin_client.h" |
| +#include "components/variations/entropy_provider.h" |
| +#include "components/variations/variations_associated_data.h" |
| +#include "content/public/test/test_browser_thread_bundle.h" |
| +#include "google_apis/gaia/gaia_urls.h" |
| +#include "net/url_request/test_url_fetcher_factory.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace { |
| + |
| +int64 InOneHour() { |
| + return (base::Time::Now() + base::TimeDelta::FromHours(1)).ToInternalValue(); |
| +} |
| + |
| +} // namespace |
| + |
| +class CrossDevicePromoObserver : public CrossDevicePromo::Observer { |
| + public: |
| + explicit CrossDevicePromoObserver(CrossDevicePromo* promo) |
| + : active_(false), set_active_(0), set_inactive_(0), promo_(promo) { |
| + promo->AddObserver(this); |
| + } |
| + |
| + ~CrossDevicePromoObserver() { promo_->RemoveObserver(this); } |
| + |
| + void OnPromoActivationChanged(bool active) override { |
| + active_ = active; |
| + active ? set_active_++ : set_inactive_++; |
|
Alexei Svitkine (slow)
2015/05/19 17:10:37
Just use an if.
Mike Lerman
2015/05/19 18:17:34
Really? so much longer! but ok.
|
| + } |
| + |
| + bool IsActive() { return active_; } |
|
Alexei Svitkine (slow)
2015/05/19 17:10:37
Nit: Just use a hacker_style accessor - is_active(
Mike Lerman
2015/05/19 18:17:34
Done. The others are now times_set_active and time
|
| + int TimesBecameActive() { return set_active_; } |
| + int TimesBecameInactive() { return set_inactive_; } |
| + |
| + private: |
| + bool active_; |
| + int set_active_; |
| + int set_inactive_; |
| + CrossDevicePromo* promo_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoObserver); |
| +}; |
| + |
| +class CrossDevicePromoTest : public ::testing::Test { |
| + public: |
| + CrossDevicePromoTest(); |
| + void SetUp() override; |
| + |
| + void ResetFieldTrialList(); |
| + |
| + CrossDevicePromo* promo() { return cross_device_promo_; } |
| + TestingProfile* profile() { return profile_; } |
| + FakeSigninManagerForTesting* signin_manager() { return signin_manager_; } |
| + base::HistogramTester* histogram_tester() { return &histogram_tester_; } |
| + TestingPrefServiceSyncable* prefs() { return pref_service_; } |
| + FakeGaiaCookieManagerService* cookie_manager_service() { |
| + return cookie_manager_service_; |
| + } |
| + net::FakeURLFetcherFactory* fetcher_factory() { |
| + return &fake_url_fetcher_factory_; |
| + } |
| + |
| + void InitPromoVariation() { |
| + std::map<std::string, std::string> variations_params; |
| + variations_params["HoursBetweenSyncDeviceChecks"] = "1"; |
| + variations_params["DaysToVerifySingleUserProfile"] = "0"; |
| + variations_params["MinutesBetweenBrowsingSessions"] = "0"; |
| + variations_params["MinutesMaxContextSwitchDuration"] = "10"; |
| + variations_params["RPCThrottle"] = "0"; |
| + EXPECT_TRUE(variations::AssociateVariationParams("CrossDevicePromo", "A", |
| + variations_params)); |
| + base::FieldTrialList::CreateFieldTrial("CrossDevicePromo", "A"); |
| + } |
| + |
| + private: |
| + content::TestBrowserThreadBundle bundle_; |
| + CrossDevicePromo* cross_device_promo_; |
| + TestingProfile* profile_; |
| + FakeSigninManagerForTesting* signin_manager_; |
| + FakeGaiaCookieManagerService* cookie_manager_service_; |
| + TestingPrefServiceSyncable* pref_service_; |
| + scoped_ptr<TestingProfileManager> testing_profile_manager_; |
| + base::HistogramTester histogram_tester_; |
| + scoped_ptr<base::FieldTrialList> field_trial_list_; |
| + net::FakeURLFetcherFactory fake_url_fetcher_factory_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoTest); |
| +}; |
| + |
| +void CrossDevicePromoTest::SetUp() { |
| + testing_profile_manager_.reset( |
| + new TestingProfileManager(TestingBrowserProcess::GetGlobal())); |
| + ASSERT_TRUE(testing_profile_manager_.get()->SetUp()); |
| + |
| + TestingProfile::TestingFactories factories; |
| + factories.push_back(std::make_pair(ChromeSigninClientFactory::GetInstance(), |
| + signin::BuildTestSigninClient)); |
| + factories.push_back( |
| + std::make_pair(GaiaCookieManagerServiceFactory::GetInstance(), |
| + FakeGaiaCookieManagerService::Build)); |
| + factories.push_back(std::make_pair(SigninManagerFactory::GetInstance(), |
| + FakeSigninManagerBase::Build)); |
| + |
| + pref_service_ = new TestingPrefServiceSyncable(); |
| + chrome::RegisterUserProfilePrefs(pref_service_->registry()); |
| + |
| + profile_ = testing_profile_manager_.get()->CreateTestingProfile( |
| + "name", make_scoped_ptr<PrefServiceSyncable>(pref_service_), |
| + base::UTF8ToUTF16("name"), 0, std::string(), factories); |
| + |
| + cookie_manager_service_ = static_cast<FakeGaiaCookieManagerService*>( |
| + GaiaCookieManagerServiceFactory::GetForProfile(profile())); |
| + cookie_manager_service_->Init(&fake_url_fetcher_factory_); |
| + |
| + signin_manager_ = static_cast<FakeSigninManagerForTesting*>( |
| + SigninManagerFactory::GetForProfile(profile())); |
| + cross_device_promo_ = CrossDevicePromoFactory::GetForProfile(profile()); |
| +} |
| + |
| +CrossDevicePromoTest::CrossDevicePromoTest() : fake_url_fetcher_factory_(NULL) { |
| + ResetFieldTrialList(); |
| +} |
| + |
| +void CrossDevicePromoTest::ResetFieldTrialList() { |
| + // Destroy the existing FieldTrialList before creating a new one to avoid |
| + // a DCHECK. |
| + field_trial_list_.reset(); |
| + field_trial_list_.reset( |
| + new base::FieldTrialList(new metrics::SHA1EntropyProvider("foo"))); |
| + variations::testing::ClearAllVariationParams(); |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, Uninitialized) { |
| + ASSERT_TRUE(promo()); |
| + histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", |
| + signin_metrics::NO_VARIATIONS_CONFIG, |
| + 1); |
| + |
| + promo()->CheckPromoEligibilityForTesting(); |
| + histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", |
| + signin_metrics::NO_VARIATIONS_CONFIG, |
| + 2); |
| + histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0); |
| + ASSERT_FALSE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut)); |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, UnitializedOptedOut) { |
| + CrossDevicePromoObserver observer(promo()); |
| + |
| + promo()->OptOut(); |
| + // Opting out doesn't de-activate a never-active promo. |
| + ASSERT_EQ(0, observer.TimesBecameInactive()); |
| + ASSERT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut)); |
| + |
| + // Never initialize a promo that is opted out. |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", |
| + signin_metrics::NO_VARIATIONS_CONFIG, |
| + 1); |
| + histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", |
| + signin_metrics::UNINITIALIZED_OPTED_OUT, |
| + 1); |
| + histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0); |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, PartiallyInitialized) { |
| + histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", |
| + signin_metrics::NO_VARIATIONS_CONFIG, |
| + 1); |
| + |
| + std::map<std::string, std::string> variations_params; |
| + variations_params["HoursBetweenSyncDeviceChecks"] = "1"; |
| + variations_params["DaysToVerifySingleUserProfile"] = "1"; |
| + ASSERT_TRUE(variations::AssociateVariationParams("CrossDevicePromo", "A", |
| + variations_params)); |
| + base::FieldTrialList::CreateFieldTrial("CrossDevicePromo", "A"); |
| + |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", |
| + signin_metrics::NO_VARIATIONS_CONFIG, |
| + 2); |
| + ASSERT_FALSE(histogram_tester()->GetHistogramSamplesSinceCreation( |
| + "Signin.XDevicePromo.Eligibility")); |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, FullyInitialized) { |
| + histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", |
| + signin_metrics::NO_VARIATIONS_CONFIG, |
| + 1); |
| + |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized", |
| + signin_metrics::NO_VARIATIONS_CONFIG, |
| + 2); |
| + |
| + InitPromoVariation(); |
| + signin_manager()->SignIn("12345", "foo@bar.com", "password"); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", |
| + signin_metrics::INITIALIZED, 1); |
| + histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", |
| + signin_metrics::NO_VARIATIONS_CONFIG, |
| + 2); |
| + |
| + histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::SIGNED_IN, 1); |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, InitializedOptOut) { |
| + // In a normal browser, the variations get set before the CrossDevicePromo is |
| + // created. Here, we need to force another Init() by calling |
| + // CheckPromoEligibilityForTesting(). |
| + InitPromoVariation(); |
| + signin_manager()->SignIn("12345", "foo@bar.com", "password"); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + |
| + histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", |
| + signin_metrics::INITIALIZED, 1); |
| + histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::SIGNED_IN, 1); |
| + |
| + // After opting out the initialized state remains; eligibility changes. |
| + promo()->OptOut(); |
| + promo()->CheckPromoEligibilityForTesting(); |
| + histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized", |
| + signin_metrics::INITIALIZED, 1); |
| + histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::OPTED_OUT, 1); |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, SignedInAndOut) { |
| + InitPromoVariation(); |
| + |
| + { |
| + base::HistogramTester test_signed_in; |
| + signin_manager()->SignIn("12345", "foo@bar.com", "password"); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + test_signed_in.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::SIGNED_IN, 1); |
| + } |
| + |
| + { |
| + base::HistogramTester test_signed_out; |
| + signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST); |
| + promo()->CheckPromoEligibilityForTesting(); |
| + test_signed_out.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, |
| + 1); |
| + } |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, TrackAccountsInCookie) { |
| + InitPromoVariation(); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + |
| + ASSERT_FALSE(prefs()->HasPrefPath( |
| + prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| + std::vector<std::pair<std::string, bool>> accounts; |
| + |
| + // Setting a single cookie sets the time. |
| + base::Time before_setting_cookies = base::Time::Now(); |
| + cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false); |
| + cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com"); |
| + EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts)); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + base::Time after_setting_cookies = base::Time::Now(); |
| + ASSERT_TRUE(prefs()->HasPrefPath( |
| + prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| + ASSERT_LE( |
| + before_setting_cookies.ToInternalValue(), |
| + prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| + ASSERT_GE( |
| + after_setting_cookies.ToInternalValue(), |
| + prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| + |
| + // A single cookie a second time doesn't change the time. |
| + cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false); |
| + cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com"); |
| + EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts)); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + ASSERT_TRUE(prefs()->HasPrefPath( |
| + prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| + ASSERT_GE( |
| + after_setting_cookies.ToInternalValue(), |
| + prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| + |
| + // Setting accounts with an auth error doesn't change the time. |
| + cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false); |
| + cookie_manager_service()->SetListAccountsResponseWebLoginRequired(); |
| + EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts)); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + ASSERT_TRUE(prefs()->HasPrefPath( |
| + prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| + ASSERT_LE( |
| + before_setting_cookies.ToInternalValue(), |
| + prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| + ASSERT_GE( |
| + after_setting_cookies.ToInternalValue(), |
| + prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| + |
| + // Seeing zero accounts clears the pref. |
| + cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false); |
| + cookie_manager_service()->SetListAccountsResponseNoAccounts(); |
| + EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts)); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + ASSERT_FALSE(prefs()->HasPrefPath( |
| + prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, SingleAccountEligibility) { |
| + InitPromoVariation(); |
| + |
| + { |
| + base::HistogramTester test_single_account; |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + test_single_account.ExpectUniqueSample( |
| + "Signin.XDevicePromo.Eligibility", |
| + signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, 1); |
| + } |
| + |
| + // Notice a single account. |
| + { |
| + base::HistogramTester test_single_account; |
| + std::vector<std::pair<std::string, bool>> accounts; |
| + cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false); |
| + cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com"); |
| + EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts)); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + test_single_account.ExpectUniqueSample( |
| + "Signin.XDevicePromo.Eligibility", |
| + signin_metrics::UNKNOWN_COUNT_DEVICES, 1); |
| + } |
| + |
| + // Set a single account that hasn't been around for "long enough". |
| + { |
| + base::HistogramTester test_single_account; |
| + prefs()->SetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie, |
| + InOneHour()); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + test_single_account.ExpectBucketCount( |
| + "Signin.XDevicePromo.Eligibility", |
| + signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, 1); |
| + } |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, NumDevicesEligibility) { |
| + // Start with a variation, signed in, and one account in the cookie jar. |
| + InitPromoVariation(); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false); |
| + cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com"); |
| + std::vector<std::pair<std::string, bool>> accounts; |
| + EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts)); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // Ensure we appropriate schedule a check for listing devices. |
| + { |
| + base::HistogramTester test_missing_list_devices; |
| + int64 earliest_time_to_check_list_devices = |
| + base::Time::Now().ToInternalValue(); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + int64 latest_time_to_check_list_devices = InOneHour(); |
| + test_missing_list_devices.ExpectUniqueSample( |
| + "Signin.XDevicePromo.Eligibility", |
| + signin_metrics::UNKNOWN_COUNT_DEVICES, 1); |
| + EXPECT_TRUE( |
| + prefs()->HasPrefPath(prefs::kCrossDevicePromoNextFetchListDevicesTime)); |
| + int64 when_to_check_list_devices = |
| + prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime); |
| + EXPECT_LT(earliest_time_to_check_list_devices, when_to_check_list_devices); |
| + EXPECT_GT(latest_time_to_check_list_devices, when_to_check_list_devices); |
| + } |
| + |
| + // Don't reschedule the list devices check if there's one pending. |
| + { |
| + base::HistogramTester test_unknown_devices; |
| + int64 list_devices_time = InOneHour(); |
| + prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, |
| + list_devices_time); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + test_unknown_devices.ExpectUniqueSample( |
| + "Signin.XDevicePromo.Eligibility", |
| + signin_metrics::UNKNOWN_COUNT_DEVICES, 1); |
| + // The scheduled time to call ListDevices should not have changed. |
| + ASSERT_EQ( |
| + list_devices_time, |
| + prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); |
| + } |
| + |
| + // Execute the list devices check if it's time. |
| + { |
| + base::HistogramTester test_unknown_devices; |
| + prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, |
| + base::Time::Now().ToInternalValue()); |
| + // The DeviceActivityFetcher will return an error to the promo service. |
| + fetcher_factory()->SetFakeResponse( |
| + GaiaUrls::GetInstance()->oauth2_iframe_url(), "not json", net::HTTP_OK, |
| + net::URLRequestStatus::SUCCESS); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + base::RunLoop().RunUntilIdle(); |
| + test_unknown_devices.ExpectUniqueSample( |
| + "Signin.XDevicePromo.Eligibility", |
| + signin_metrics::ERROR_FETCHING_DEVICE_ACTIVITY, 1); |
| + } |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, ThrottleDeviceActivityCall) { |
| + // Start with a variation (fully throttled), signed in, one account in cookie. |
| + std::map<std::string, std::string> variations_params; |
| + variations_params["HoursBetweenSyncDeviceChecks"] = "1"; |
| + variations_params["DaysToVerifySingleUserProfile"] = "0"; |
| + variations_params["MinutesBetweenBrowsingSessions"] = "0"; |
| + variations_params["MinutesMaxContextSwitchDuration"] = "10"; |
| + variations_params["RPCThrottle"] = "101"; |
| + EXPECT_TRUE(variations::AssociateVariationParams("CrossDevicePromo", "A", |
| + variations_params)); |
| + base::FieldTrialList::CreateFieldTrial("CrossDevicePromo", "A"); |
| + |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false); |
| + cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com"); |
| + std::vector<std::pair<std::string, bool>> accounts; |
| + EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts)); |
| + base::RunLoop().RunUntilIdle(); |
| + |
| + // Ensure Device Activity Fetch gets throttled. |
| + { |
| + base::HistogramTester test_throttle_rpc; |
| + prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, |
| + base::Time::Now().ToInternalValue()); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + test_throttle_rpc.ExpectUniqueSample( |
| + "Signin.XDevicePromo.Eligibility", |
| + signin_metrics::THROTTLED_FETCHING_DEVICE_ACTIVITY, 1); |
| + } |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, NumDevicesKnown) { |
| + // Start with a variation, signed in, and one account, sync devices in 1 hour. |
| + InitPromoVariation(); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false); |
| + cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com"); |
| + std::vector<std::pair<std::string, bool>> accounts; |
| + EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts)); |
| + base::RunLoop().RunUntilIdle(); |
| + prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, |
| + InOneHour()); |
| + |
| + // If there is no device present. |
| + { |
| + base::HistogramTester test_no_devices; |
| + prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices, 0); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + test_no_devices.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::ZERO_DEVICES, 1); |
| + } |
| + |
| + // If there is one device present. |
| + { |
| + prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices, 1); |
| + EXPECT_TRUE(promo()->CheckPromoEligibilityForTesting()); |
| + } |
| +} |
| + |
| +TEST_F(CrossDevicePromoTest, FetchDeviceResults) { |
| + // Start with a variation, signed in, and one account, sync devices in 1 hour. |
| + InitPromoVariation(); |
| + EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting()); |
| + cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false); |
| + cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com"); |
| + std::vector<std::pair<std::string, bool>> accounts; |
| + EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts)); |
| + base::RunLoop().RunUntilIdle(); |
| + prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime, |
| + base::Time::Now().ToInternalValue()); |
| + prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices, 1); |
| + |
| + // If there is no device found. |
| + { |
| + base::HistogramTester test_no_devices; |
| + std::vector<DeviceActivityFetcher::DeviceActivity> devices; |
| + int64 in_one_hour = InOneHour(); |
| + promo()->OnFetchDeviceActivitySuccess(devices); |
| + EXPECT_LE( |
| + in_one_hour, |
| + prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); |
| + EXPECT_EQ(0, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices)); |
| + test_no_devices.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::ZERO_DEVICES, 1); |
| + } |
| + |
| + // If there is one device found. It was recently active. |
| + { |
| + CrossDevicePromoObserver observer(promo()); |
| + ASSERT_FALSE(observer.IsActive()); |
| + base::HistogramTester test_one_device; |
| + std::vector<DeviceActivityFetcher::DeviceActivity> devices; |
| + base::Time device_last_active = |
| + base::Time::Now() - base::TimeDelta::FromMinutes(4); |
| + DeviceActivityFetcher::DeviceActivity device; |
| + device.last_active = device_last_active; |
| + device.name = "Aslan"; |
| + devices.push_back(device); |
| + |
| + int64 in_one_hour = InOneHour(); |
| + promo()->OnFetchDeviceActivitySuccess(devices); |
| + EXPECT_LE( |
| + in_one_hour, |
| + prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); |
| + EXPECT_EQ(1, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices)); |
| + EXPECT_EQ(device_last_active.ToInternalValue(), |
| + prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime)); |
| + EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoActive)); |
| + test_one_device.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::ELIGIBLE, 1); |
| + EXPECT_TRUE(observer.IsActive()); |
| + EXPECT_EQ(1, observer.TimesBecameActive()); |
| + } |
| + |
| + // If there is one device found. It was not recently active. |
| + { |
| + CrossDevicePromoObserver observer(promo()); |
| + ASSERT_FALSE(observer.IsActive()); |
| + base::HistogramTester test_one_device; |
| + std::vector<DeviceActivityFetcher::DeviceActivity> devices; |
| + base::Time device_last_active = |
| + base::Time::Now() - base::TimeDelta::FromMinutes(30); |
| + DeviceActivityFetcher::DeviceActivity device; |
| + device.last_active = device_last_active; |
| + device.name = "Aslan"; |
| + devices.push_back(device); |
| + |
| + int64 in_one_hour = InOneHour(); |
| + promo()->OnFetchDeviceActivitySuccess(devices); |
| + EXPECT_LE( |
| + in_one_hour, |
| + prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); |
| + EXPECT_EQ(1, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices)); |
| + EXPECT_EQ(device_last_active.ToInternalValue(), |
| + prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime)); |
| + EXPECT_FALSE(prefs()->GetBoolean(prefs::kCrossDevicePromoActive)); |
| + test_one_device.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::NO_ACTIVE_DEVICES, 1); |
| + EXPECT_FALSE(observer.IsActive()); |
| + } |
| + |
| + // If there are two devices found, one recently. |
| + { |
| + CrossDevicePromoObserver observer(promo()); |
| + ASSERT_FALSE(observer.IsActive()); |
| + base::HistogramTester test_two_devices; |
| + std::vector<DeviceActivityFetcher::DeviceActivity> devices; |
| + base::Time device1_last_active = |
| + base::Time::Now() - base::TimeDelta::FromMinutes(30); |
| + base::Time device2_last_active = |
| + base::Time::Now() - base::TimeDelta::FromMinutes(3); |
| + DeviceActivityFetcher::DeviceActivity device1; |
| + device1.last_active = device1_last_active; |
| + device1.name = "Aslan"; |
| + devices.push_back(device1); |
| + DeviceActivityFetcher::DeviceActivity device2; |
| + device2.last_active = device2_last_active; |
| + device2.name = "Balrog"; |
| + devices.push_back(device2); |
| + |
| + int64 in_one_hour = InOneHour(); |
| + promo()->OnFetchDeviceActivitySuccess(devices); |
| + EXPECT_LE( |
| + in_one_hour, |
| + prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime)); |
| + EXPECT_EQ(2, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices)); |
| + EXPECT_EQ(device2_last_active.ToInternalValue(), |
| + prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime)); |
| + EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoActive)); |
| + test_two_devices.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
| + signin_metrics::ELIGIBLE, 1); |
| + EXPECT_TRUE(observer.IsActive()); |
| + EXPECT_EQ(1, observer.TimesBecameActive()); |
| + } |
| +} |