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..e21fe797ff9e85655ed74e1d8738ec7b97cd3fe9 |
--- /dev/null |
+++ b/chrome/browser/signin/cross_device_promo_unittest.cc |
@@ -0,0 +1,587 @@ |
+// 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(); |
+} |
+ |
+} |
+ |
+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_++; |
+ } |
+ |
+ bool IsActive() { return active_; } |
+ int TimesBecameActive() { return set_active_; } |
+ int TimesBecameInactive() { return set_inactive_; } |
+ |
+ private: |
+ bool active_; |
+ int set_active_; |
+ int set_inactive_; |
+ CrossDevicePromo* promo_; |
+}; |
+ |
+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", 0, 1); |
+ |
+ promo()->CheckPromoEligibility(); |
+ histogram_tester()->ExpectUniqueSample( |
+ "Signin.XDevicePromo.Initialized", 0, 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()->CheckPromoEligibility()); |
+ histogram_tester()->ExpectUniqueSample( |
+ "Signin.XDevicePromo.Initialized", 0, 2); |
+ histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0); |
+} |
+ |
+TEST_F(CrossDevicePromoTest, PartiallyInitialized) { |
+ histogram_tester()->ExpectUniqueSample( |
+ "Signin.XDevicePromo.Initialized", 0, 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()->CheckPromoEligibility()); |
+ histogram_tester()->ExpectUniqueSample( |
+ "Signin.XDevicePromo.Initialized", 0, 2); |
+ ASSERT_FALSE(histogram_tester()->GetHistogramSamplesSinceCreation( |
+ "Signin.XDevicePromo.Eligibility")); |
+} |
+ |
+TEST_F(CrossDevicePromoTest, FullyInitialized) { |
+ histogram_tester()->ExpectUniqueSample( |
+ "Signin.XDevicePromo.Initialized", 0, 1); |
+ |
+ EXPECT_FALSE(promo()->CheckPromoEligibility()); |
+ histogram_tester()->ExpectUniqueSample( |
+ "Signin.XDevicePromo.Initialized", 0, 2); |
+ |
+ InitPromoVariation(); |
+ signin_manager()->SignIn("12345", "foo@bar.com", "password"); |
+ EXPECT_FALSE(promo()->CheckPromoEligibility()); |
+ histogram_tester()->ExpectBucketCount( |
+ "Signin.XDevicePromo.Initialized", 1, 1); |
+ histogram_tester()->ExpectBucketCount( |
+ "Signin.XDevicePromo.Initialized", 0, 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 |
+ // CheckPromoEligibility(). |
+ InitPromoVariation(); |
+ signin_manager()->SignIn("12345", "foo@bar.com", "password"); |
+ EXPECT_FALSE(promo()->CheckPromoEligibility()); |
+ |
+ histogram_tester()->ExpectBucketCount( |
+ "Signin.XDevicePromo.Initialized", 1, 1); |
+ histogram_tester()->ExpectUniqueSample( |
+ "Signin.XDevicePromo.Eligibility", signin_metrics::SIGNED_IN, 1); |
+ |
+ // After opting out the initialized state remains; eligibility changes. |
+ promo()->OptOut(); |
+ promo()->CheckPromoEligibility(); |
+ histogram_tester()->ExpectBucketCount( |
+ "Signin.XDevicePromo.Initialized", 1, 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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility(); |
+ test_signed_out.ExpectUniqueSample("Signin.XDevicePromo.Eligibility", |
+ signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, 1); |
+ } |
+} |
+ |
+TEST_F(CrossDevicePromoTest, TrackAccountsInCookie) { |
+ InitPromoVariation(); |
+ EXPECT_FALSE(promo()->CheckPromoEligibility()); |
+ |
+ 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_LT(before_setting_cookies.ToInternalValue(), prefs()->GetInt64( |
+ prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
+ ASSERT_GT(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_GT(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_LT(before_setting_cookies.ToInternalValue(), prefs()->GetInt64( |
+ prefs::kCrossDevicePromoObservedSingleAccountCookie)); |
+ ASSERT_GT(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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ 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"] = "100"; |
+ EXPECT_TRUE(variations::AssociateVariationParams( |
+ "CrossDevicePromo", "A", variations_params)); |
+ base::FieldTrialList::CreateFieldTrial("CrossDevicePromo", "A"); |
+ |
+ EXPECT_FALSE(promo()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ 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()->CheckPromoEligibility()); |
+ } |
+} |
+ |
+TEST_F(CrossDevicePromoTest, FetchDeviceResults) { |
+ // Start with a variation, signed in, and one account, sync devices in 1 hour. |
+ InitPromoVariation(); |
+ EXPECT_FALSE(promo()->CheckPromoEligibility()); |
+ 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()); |
+ } |
+} |