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..8bff0d42f0a3d53320b4f29491eb1f46b02eaaae |
--- /dev/null |
+++ b/chrome/browser/signin/cross_device_promo_unittest.cc |
@@ -0,0 +1,618 @@ |
+// 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), |
+ times_set_active_(0), |
+ times_set_inactive_(0), |
+ promo_(promo) { |
+ promo->AddObserver(this); |
+ } |
+ |
+ ~CrossDevicePromoObserver() { promo_->RemoveObserver(this); } |
+ |
+ void OnPromoActivationChanged(bool active) override { |
+ active_ = active; |
+ if (active) |
+ times_set_active_++; |
+ else |
+ times_set_inactive_++; |
+ } |
+ |
+ bool is_active() { return active_; } |
+ int times_set_active() { return times_set_active_; } |
+ int times_set_inactive() { return times_set_inactive_; } |
+ |
+ private: |
+ bool active_; |
+ int times_set_active_; |
+ int times_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.times_set_inactive()); |
+ 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.is_active()); |
+ 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.is_active()); |
+ EXPECT_EQ(1, observer.times_set_active()); |
+ } |
+ |
+ // If there is one device found. It was not recently active. |
+ { |
+ CrossDevicePromoObserver observer(promo()); |
+ ASSERT_FALSE(observer.is_active()); |
+ 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.is_active()); |
+ } |
+ |
+ // If there are two devices found, one recently. |
+ { |
+ CrossDevicePromoObserver observer(promo()); |
+ ASSERT_FALSE(observer.is_active()); |
+ 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.is_active()); |
+ EXPECT_EQ(1, observer.times_set_active()); |
+ } |
+} |