1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/signin/cross_device_promo.h"
7 #include "base/metrics/field_trial.h"
8 #include "base/run_loop.h"
9 #include "base/test/histogram_tester.h"
10 #include "chrome/browser/prefs/browser_prefs.h"
11 #include "chrome/browser/prefs/pref_service_syncable.h"
12 #include "chrome/browser/signin/chrome_signin_client_factory.h"
13 #include "chrome/browser/signin/cross_device_promo_factory.h"
14 #include "chrome/browser/signin/fake_gaia_cookie_manager_service.h"
15 #include "chrome/browser/signin/fake_signin_manager_builder.h"
16 #include "chrome/browser/signin/gaia_cookie_manager_service_factory.h"
17 #include "chrome/browser/signin/signin_manager_factory.h"
18 #include "chrome/browser/signin/test_signin_client_builder.h"
19 #include "chrome/common/pref_names.h"
20 #include "chrome/test/base/testing_browser_process.h"
21 #include "chrome/test/base/testing_pref_service_syncable.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "chrome/test/base/testing_profile_manager.h"
24 #include "components/signin/core/browser/signin_manager.h"
25 #include "components/signin/core/browser/signin_metrics.h"
26 #include "components/signin/core/browser/test_signin_client.h"
27 #include "components/variations/entropy_provider.h"
28 #include "components/variations/variations_associated_data.h"
29 #include "content/public/test/test_browser_thread_bundle.h"
30 #include "google_apis/gaia/gaia_urls.h"
31 #include "net/url_request/test_url_fetcher_factory.h"
32 #include "testing/gtest/include/gtest/gtest.h"
36 typedef std::map
<std::string
, std::string
> VariationsMap
;
39 return (base::Time::Now() + base::TimeDelta::FromHours(2)).ToInternalValue();
44 class CrossDevicePromoObserver
: public CrossDevicePromo::Observer
{
46 explicit CrossDevicePromoObserver(CrossDevicePromo
* promo
)
48 times_set_eligible_(0),
49 times_set_ineligible_(0),
51 promo
->AddObserver(this);
54 ~CrossDevicePromoObserver() { promo_
->RemoveObserver(this); }
56 void OnPromoEligibilityChanged(bool eligible
) override
{
59 ++times_set_eligible_
;
61 ++times_set_ineligible_
;
64 bool is_eligible() const { return eligible_
; }
65 int times_set_eligible() const { return times_set_eligible_
; }
66 int times_set_inactive() const { return times_set_ineligible_
; }
70 int times_set_eligible_
;
71 int times_set_ineligible_
;
72 CrossDevicePromo
* promo_
;
74 DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoObserver
);
77 class CrossDevicePromoTest
: public ::testing::Test
{
79 CrossDevicePromoTest();
81 void SetUp() override
;
83 // Destroys any variations which might be defined, and starts fresh.
84 void ResetFieldTrialList();
86 // Defines a default set of variation parameters for promo initialization.
87 void InitPromoVariation();
89 CrossDevicePromo
* promo() { return cross_device_promo_
; }
90 TestingProfile
* profile() { return profile_
; }
91 FakeSigninManagerForTesting
* signin_manager() { return signin_manager_
; }
92 base::HistogramTester
* histogram_tester() { return &histogram_tester_
; }
93 TestingPrefServiceSyncable
* prefs() { return pref_service_
; }
94 FakeGaiaCookieManagerService
* cookie_manager_service() {
95 return cookie_manager_service_
;
97 net::FakeURLFetcherFactory
* fetcher_factory() {
98 return &fake_url_fetcher_factory_
;
102 content::TestBrowserThreadBundle bundle_
;
103 CrossDevicePromo
* cross_device_promo_
;
104 TestingProfile
* profile_
;
105 FakeSigninManagerForTesting
* signin_manager_
;
106 FakeGaiaCookieManagerService
* cookie_manager_service_
;
107 TestingPrefServiceSyncable
* pref_service_
;
108 scoped_ptr
<TestingProfileManager
> testing_profile_manager_
;
109 base::HistogramTester histogram_tester_
;
110 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
111 net::FakeURLFetcherFactory fake_url_fetcher_factory_
;
113 DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoTest
);
116 CrossDevicePromoTest::CrossDevicePromoTest() : fake_url_fetcher_factory_(NULL
) {
117 ResetFieldTrialList();
120 void CrossDevicePromoTest::SetUp() {
121 testing_profile_manager_
.reset(
122 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
123 ASSERT_TRUE(testing_profile_manager_
.get()->SetUp());
125 TestingProfile::TestingFactories factories
;
126 factories
.push_back(std::make_pair(ChromeSigninClientFactory::GetInstance(),
127 signin::BuildTestSigninClient
));
129 std::make_pair(GaiaCookieManagerServiceFactory::GetInstance(),
130 FakeGaiaCookieManagerService::Build
));
131 factories
.push_back(std::make_pair(SigninManagerFactory::GetInstance(),
132 BuildFakeSigninManagerBase
));
134 pref_service_
= new TestingPrefServiceSyncable();
135 chrome::RegisterUserProfilePrefs(pref_service_
->registry());
137 profile_
= testing_profile_manager_
.get()->CreateTestingProfile(
138 "name", make_scoped_ptr
<PrefServiceSyncable
>(pref_service_
),
139 base::UTF8ToUTF16("name"), 0, std::string(), factories
);
141 cookie_manager_service_
= static_cast<FakeGaiaCookieManagerService
*>(
142 GaiaCookieManagerServiceFactory::GetForProfile(profile()));
143 cookie_manager_service_
->Init(&fake_url_fetcher_factory_
);
145 signin_manager_
= static_cast<FakeSigninManagerForTesting
*>(
146 SigninManagerFactory::GetForProfile(profile()));
148 cross_device_promo_
= CrossDevicePromoFactory::GetForProfile(profile());
151 void CrossDevicePromoTest::ResetFieldTrialList() {
152 // Destroy the existing FieldTrialList before creating a new one to avoid
154 field_trial_list_
.reset();
155 field_trial_list_
.reset(
156 new base::FieldTrialList(new metrics::SHA1EntropyProvider("foo")));
157 variations::testing::ClearAllVariationParams();
160 void CrossDevicePromoTest::InitPromoVariation() {
161 VariationsMap variations_params
;
163 CrossDevicePromo::kParamHoursBetweenDeviceActivityChecks
] = "2";
165 CrossDevicePromo::kParamDaysToVerifySingleUserProfile
] = "0";
167 CrossDevicePromo::kParamMinutesBetweenBrowsingSessions
] = "0";
169 CrossDevicePromo::kParamMinutesMaxContextSwitchDuration
] = "10";
171 CrossDevicePromo::kParamRPCThrottle
] = "0";
172 EXPECT_TRUE(variations::AssociateVariationParams(
173 CrossDevicePromo::kCrossDevicePromoFieldTrial
, "A", variations_params
));
174 base::FieldTrialList::CreateFieldTrial(
175 CrossDevicePromo::kCrossDevicePromoFieldTrial
, "A");
178 // Tests for incrementally large portions flow that determines if the promo
181 TEST_F(CrossDevicePromoTest
, Uninitialized
) {
182 ASSERT_TRUE(promo());
183 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
184 signin_metrics::NO_VARIATIONS_CONFIG
,
187 promo()->CheckPromoEligibilityForTesting();
188 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
189 signin_metrics::NO_VARIATIONS_CONFIG
,
191 histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0);
192 EXPECT_FALSE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut
));
195 TEST_F(CrossDevicePromoTest
, UnitializedOptedOut
) {
196 CrossDevicePromoObserver
observer(promo());
199 // Opting out doesn't de-activate a never-active promo.
200 EXPECT_EQ(0, observer
.times_set_inactive());
201 EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut
));
203 // An opted-out promo will never be initialized.
204 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
205 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
206 signin_metrics::NO_VARIATIONS_CONFIG
,
208 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
209 signin_metrics::UNINITIALIZED_OPTED_OUT
,
211 histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0);
214 TEST_F(CrossDevicePromoTest
, PartiallyInitialized
) {
215 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
216 signin_metrics::NO_VARIATIONS_CONFIG
,
219 VariationsMap variations_params
;
221 CrossDevicePromo::kParamHoursBetweenDeviceActivityChecks
] = "1";
223 CrossDevicePromo::kParamDaysToVerifySingleUserProfile
] = "1";
224 EXPECT_TRUE(variations::AssociateVariationParams(
225 CrossDevicePromo::kCrossDevicePromoFieldTrial
, "A", variations_params
));
226 base::FieldTrialList::CreateFieldTrial(
227 CrossDevicePromo::kCrossDevicePromoFieldTrial
, "A");
229 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
230 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
231 signin_metrics::NO_VARIATIONS_CONFIG
,
233 histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0);
236 TEST_F(CrossDevicePromoTest
, FullyInitialized
) {
237 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
238 signin_metrics::NO_VARIATIONS_CONFIG
,
241 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
242 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
243 signin_metrics::NO_VARIATIONS_CONFIG
,
246 InitPromoVariation();
247 signin_manager()->SignIn("12345", "foo@bar.com", "password");
248 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
249 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
250 signin_metrics::INITIALIZED
, 1);
251 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
252 signin_metrics::NO_VARIATIONS_CONFIG
,
255 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
256 signin_metrics::SIGNED_IN
, 1);
259 TEST_F(CrossDevicePromoTest
, InitializedOptOut
) {
260 // In a normal browser, the variations get set before the CrossDevicePromo is
261 // created. Here, we need to force another Init() by calling
262 // CheckPromoEligibilityForTesting().
263 InitPromoVariation();
264 signin_manager()->SignIn("12345", "foo@bar.com", "password");
265 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
267 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
268 signin_metrics::INITIALIZED
, 1);
269 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
270 signin_metrics::SIGNED_IN
, 1);
272 // After opting out the initialized state remains; eligibility changes.
274 promo()->CheckPromoEligibilityForTesting();
275 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
276 signin_metrics::INITIALIZED
, 1);
277 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Eligibility",
278 signin_metrics::OPTED_OUT
, 1);
281 TEST_F(CrossDevicePromoTest
, SignedInAndOut
) {
282 InitPromoVariation();
285 base::HistogramTester test_signed_in
;
286 signin_manager()->SignIn("12345", "foo@bar.com", "password");
287 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
288 test_signed_in
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
289 signin_metrics::SIGNED_IN
, 1);
293 base::HistogramTester test_signed_out
;
294 signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST
);
295 promo()->CheckPromoEligibilityForTesting();
296 test_signed_out
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
297 signin_metrics::NOT_SINGLE_GAIA_ACCOUNT
,
302 TEST_F(CrossDevicePromoTest
, TrackAccountsInCookie
) {
303 InitPromoVariation();
304 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
306 ASSERT_FALSE(prefs()->HasPrefPath(
307 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
308 std::vector
<gaia::ListedAccount
> accounts
;
310 // Setting a single cookie sets the time.
311 base::Time before_setting_cookies
= base::Time::Now();
312 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
313 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
314 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
315 base::RunLoop().RunUntilIdle();
317 base::Time after_setting_cookies
= base::Time::Now();
318 EXPECT_TRUE(prefs()->HasPrefPath(
319 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
321 before_setting_cookies
.ToInternalValue(),
322 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
324 after_setting_cookies
.ToInternalValue(),
325 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
327 // A single cookie a second time doesn't change the time.
328 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
329 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
330 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
331 base::RunLoop().RunUntilIdle();
333 EXPECT_TRUE(prefs()->HasPrefPath(
334 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
336 after_setting_cookies
.ToInternalValue(),
337 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
339 // Setting accounts with an auth error doesn't change the time.
340 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
341 cookie_manager_service()->SetListAccountsResponseWebLoginRequired();
342 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
343 base::RunLoop().RunUntilIdle();
345 EXPECT_TRUE(prefs()->HasPrefPath(
346 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
348 before_setting_cookies
.ToInternalValue(),
349 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
351 after_setting_cookies
.ToInternalValue(),
352 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
354 // Seeing zero accounts clears the pref.
355 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
356 cookie_manager_service()->SetListAccountsResponseNoAccounts();
357 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
358 base::RunLoop().RunUntilIdle();
360 EXPECT_FALSE(prefs()->HasPrefPath(
361 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
364 TEST_F(CrossDevicePromoTest
, SingleAccountEligibility
) {
365 InitPromoVariation();
368 base::HistogramTester test_single_account
;
369 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
370 test_single_account
.ExpectUniqueSample(
371 "Signin.XDevicePromo.Eligibility",
372 signin_metrics::NOT_SINGLE_GAIA_ACCOUNT
, 1);
375 // Notice a single account.
377 base::HistogramTester test_single_account
;
378 std::vector
<gaia::ListedAccount
> accounts
;
379 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
380 cookie_manager_service()->SetListAccountsResponseOneAccount("a@b.com", "1");
381 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
382 base::RunLoop().RunUntilIdle();
384 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
385 test_single_account
.ExpectUniqueSample(
386 "Signin.XDevicePromo.Eligibility",
387 signin_metrics::UNKNOWN_COUNT_DEVICES
, 1);
390 // Set a single account that hasn't been around for "long enough".
392 base::HistogramTester test_single_account
;
393 prefs()->SetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
,
395 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
396 test_single_account
.ExpectBucketCount(
397 "Signin.XDevicePromo.Eligibility",
398 signin_metrics::NOT_SINGLE_GAIA_ACCOUNT
, 1);
402 TEST_F(CrossDevicePromoTest
, NumDevicesEligibility
) {
403 // Start with a variation, signed in, and one account in the cookie jar.
404 InitPromoVariation();
405 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
406 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
407 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
408 std::vector
<gaia::ListedAccount
> accounts
;
409 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
410 base::RunLoop().RunUntilIdle();
412 // Ensure we appropriate schedule a check for device activity.
414 base::HistogramTester test_missing_list_devices
;
415 int64 earliest_time_to_check_list_devices
=
416 base::Time::Now().ToInternalValue();
417 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
418 int64 latest_time_to_check_list_devices
= InTwoHours();
419 test_missing_list_devices
.ExpectUniqueSample(
420 "Signin.XDevicePromo.Eligibility",
421 signin_metrics::UNKNOWN_COUNT_DEVICES
, 1);
423 prefs()->HasPrefPath(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
424 int64 when_to_check_list_devices
=
425 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
);
426 EXPECT_LT(earliest_time_to_check_list_devices
, when_to_check_list_devices
);
427 EXPECT_GT(latest_time_to_check_list_devices
, when_to_check_list_devices
);
430 // Don't reschedule the device activity check if there's one pending.
432 base::HistogramTester test_unknown_devices
;
433 int64 list_devices_time
= InTwoHours();
434 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
436 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
437 test_unknown_devices
.ExpectUniqueSample(
438 "Signin.XDevicePromo.Eligibility",
439 signin_metrics::UNKNOWN_COUNT_DEVICES
, 1);
440 // The scheduled time to fetch device activity should not have changed.
443 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
446 // Execute the device activity fetch if it's time.
448 base::HistogramTester test_unknown_devices
;
449 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
450 base::Time::Now().ToInternalValue());
451 // The DeviceActivityFetcher will return an error to the promo service.
452 fetcher_factory()->SetFakeResponse(
453 GaiaUrls::GetInstance()->oauth2_iframe_url(), "not json", net::HTTP_OK
,
454 net::URLRequestStatus::SUCCESS
);
455 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
456 base::RunLoop().RunUntilIdle();
457 test_unknown_devices
.ExpectUniqueSample(
458 "Signin.XDevicePromo.Eligibility",
459 signin_metrics::ERROR_FETCHING_DEVICE_ACTIVITY
, 1);
463 TEST_F(CrossDevicePromoTest
, ThrottleDeviceActivityCall
) {
464 // Start with a variation (fully throttled), signed in, one account in cookie.
465 VariationsMap variations_params
;
467 CrossDevicePromo::kParamHoursBetweenDeviceActivityChecks
] = "1";
469 CrossDevicePromo::kParamDaysToVerifySingleUserProfile
] = "0";
471 CrossDevicePromo::kParamMinutesBetweenBrowsingSessions
] = "0";
473 CrossDevicePromo::kParamMinutesMaxContextSwitchDuration
] = "10";
475 CrossDevicePromo::kParamRPCThrottle
] = "100";
476 EXPECT_TRUE(variations::AssociateVariationParams(
477 CrossDevicePromo::kCrossDevicePromoFieldTrial
, "A", variations_params
));
478 base::FieldTrialList::CreateFieldTrial(
479 CrossDevicePromo::kCrossDevicePromoFieldTrial
, "A");
481 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
482 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
483 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
484 std::vector
<gaia::ListedAccount
> accounts
;
485 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
486 base::RunLoop().RunUntilIdle();
488 // Ensure device activity fetches get throttled.
490 base::HistogramTester test_throttle_rpc
;
491 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
492 base::Time::Now().ToInternalValue());
493 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
494 test_throttle_rpc
.ExpectUniqueSample(
495 "Signin.XDevicePromo.Eligibility",
496 signin_metrics::THROTTLED_FETCHING_DEVICE_ACTIVITY
, 1);
500 TEST_F(CrossDevicePromoTest
, NumDevicesKnown
) {
501 // Start with a variation, signed in, and one account, fetch device activity
503 InitPromoVariation();
504 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
505 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
506 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
507 std::vector
<gaia::ListedAccount
> accounts
;
508 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
509 base::RunLoop().RunUntilIdle();
510 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
513 // Verify that knowing there are no devices for this account logs the
514 // appropriate metric for ineligibility.
516 base::HistogramTester test_no_devices
;
517 prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices
, 0);
518 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
519 test_no_devices
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
520 signin_metrics::ZERO_DEVICES
, 1);
523 // Verify that knowing there is another device for this account results in the
524 // promo being eligible to be shown.
526 prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices
, 1);
527 EXPECT_TRUE(promo()->CheckPromoEligibilityForTesting());
531 TEST_F(CrossDevicePromoTest
, FetchDeviceResults
) {
532 // Start with a variation, signed in, and one account, fetch device activity
534 InitPromoVariation();
535 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
536 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
537 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
538 std::vector
<gaia::ListedAccount
> accounts
;
539 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
540 base::RunLoop().RunUntilIdle();
541 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
542 base::Time::Now().ToInternalValue());
543 prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices
, 1);
545 // Verify that if the device activity fetcher returns zero devices the
546 // eligibility metric will report a ZERO_DEVICES event, and will not report
547 // the promo as eligible to be shown.
549 base::HistogramTester test_no_devices
;
550 std::vector
<DeviceActivityFetcher::DeviceActivity
> devices
;
551 int64 in_two_hours
= InTwoHours();
552 promo()->OnFetchDeviceActivitySuccess(devices
);
555 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
556 EXPECT_EQ(0, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices
));
557 test_no_devices
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
558 signin_metrics::ZERO_DEVICES
, 1);
561 // Verify that if the device activity fetcher returns one device that was
562 // recently active, the promo is marked as eligible and the eligibility
563 // metric reports an ELIGIBLE event.
565 CrossDevicePromoObserver
observer(promo());
566 EXPECT_FALSE(observer
.is_eligible());
567 base::HistogramTester test_one_device
;
568 std::vector
<DeviceActivityFetcher::DeviceActivity
> devices
;
569 base::Time device_last_active
=
570 base::Time::Now() - base::TimeDelta::FromMinutes(4);
571 DeviceActivityFetcher::DeviceActivity device
;
572 device
.last_active
= device_last_active
;
573 device
.name
= "Aslan";
574 devices
.push_back(device
);
576 int64 in_two_hours
= InTwoHours();
577 promo()->OnFetchDeviceActivitySuccess(devices
);
580 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
581 EXPECT_EQ(1, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices
));
582 EXPECT_EQ(device_last_active
.ToInternalValue(),
583 prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime
));
584 EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoShouldBeShown
));
585 test_one_device
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
586 signin_metrics::ELIGIBLE
, 1);
587 EXPECT_TRUE(observer
.is_eligible());
588 EXPECT_EQ(1, observer
.times_set_eligible());
591 // Verify that if the device activity fetcher returns one device that was not
592 // recently active then the eligibility metric will report a NO_ACTIVE_DEVICES
593 // event, and will not report the promo as eligible to be shown.
595 CrossDevicePromoObserver
observer(promo());
596 EXPECT_FALSE(observer
.is_eligible());
597 base::HistogramTester test_one_device
;
598 std::vector
<DeviceActivityFetcher::DeviceActivity
> devices
;
599 base::Time device_last_active
=
600 base::Time::Now() - base::TimeDelta::FromMinutes(30);
601 DeviceActivityFetcher::DeviceActivity device
;
602 device
.last_active
= device_last_active
;
603 device
.name
= "Aslan";
604 devices
.push_back(device
);
606 int64 in_two_hours
= InTwoHours();
607 promo()->OnFetchDeviceActivitySuccess(devices
);
610 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
611 EXPECT_EQ(1, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices
));
612 EXPECT_EQ(device_last_active
.ToInternalValue(),
613 prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime
));
614 EXPECT_FALSE(prefs()->GetBoolean(prefs::kCrossDevicePromoShouldBeShown
));
615 test_one_device
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
616 signin_metrics::NO_ACTIVE_DEVICES
, 1);
617 EXPECT_FALSE(observer
.is_eligible());
620 // Verify that if the device activity fetcher returns two devices and one was
621 // recently active, that the promo is eligible to be shown and the last active
622 // time is stored properly.
624 CrossDevicePromoObserver
observer(promo());
625 EXPECT_FALSE(observer
.is_eligible());
626 base::HistogramTester test_two_devices
;
627 std::vector
<DeviceActivityFetcher::DeviceActivity
> devices
;
628 base::Time device1_last_active
=
629 base::Time::Now() - base::TimeDelta::FromMinutes(30);
630 base::Time device2_last_active
=
631 base::Time::Now() - base::TimeDelta::FromMinutes(3);
632 DeviceActivityFetcher::DeviceActivity device1
;
633 device1
.last_active
= device1_last_active
;
634 device1
.name
= "Aslan";
635 devices
.push_back(device1
);
636 DeviceActivityFetcher::DeviceActivity device2
;
637 device2
.last_active
= device2_last_active
;
638 device2
.name
= "Balrog";
639 devices
.push_back(device2
);
641 int64 in_two_hours
= InTwoHours();
642 promo()->OnFetchDeviceActivitySuccess(devices
);
645 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
646 EXPECT_EQ(2, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices
));
647 EXPECT_EQ(device2_last_active
.ToInternalValue(),
648 prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime
));
649 EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoShouldBeShown
));
650 test_two_devices
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
651 signin_metrics::ELIGIBLE
, 1);
652 EXPECT_TRUE(observer
.is_eligible());
653 EXPECT_EQ(1, observer
.times_set_eligible());