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.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"
37 return (base::Time::Now() + base::TimeDelta::FromHours(1)).ToInternalValue();
42 class CrossDevicePromoObserver
: public CrossDevicePromo::Observer
{
44 explicit CrossDevicePromoObserver(CrossDevicePromo
* promo
)
47 times_set_inactive_(0),
49 promo
->AddObserver(this);
52 ~CrossDevicePromoObserver() { promo_
->RemoveObserver(this); }
54 void OnPromoActivationChanged(bool active
) override
{
59 times_set_inactive_
++;
62 bool is_active() { return active_
; }
63 int times_set_active() { return times_set_active_
; }
64 int times_set_inactive() { return times_set_inactive_
; }
68 int times_set_active_
;
69 int times_set_inactive_
;
70 CrossDevicePromo
* promo_
;
72 DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoObserver
);
75 class CrossDevicePromoTest
: public ::testing::Test
{
77 CrossDevicePromoTest();
78 void SetUp() override
;
80 void ResetFieldTrialList();
82 CrossDevicePromo
* promo() { return cross_device_promo_
; }
83 TestingProfile
* profile() { return profile_
; }
84 FakeSigninManagerForTesting
* signin_manager() { return signin_manager_
; }
85 base::HistogramTester
* histogram_tester() { return &histogram_tester_
; }
86 TestingPrefServiceSyncable
* prefs() { return pref_service_
; }
87 FakeGaiaCookieManagerService
* cookie_manager_service() {
88 return cookie_manager_service_
;
90 net::FakeURLFetcherFactory
* fetcher_factory() {
91 return &fake_url_fetcher_factory_
;
94 void InitPromoVariation() {
95 std::map
<std::string
, std::string
> variations_params
;
96 variations_params
["HoursBetweenSyncDeviceChecks"] = "1";
97 variations_params
["DaysToVerifySingleUserProfile"] = "0";
98 variations_params
["MinutesBetweenBrowsingSessions"] = "0";
99 variations_params
["MinutesMaxContextSwitchDuration"] = "10";
100 variations_params
["RPCThrottle"] = "0";
101 EXPECT_TRUE(variations::AssociateVariationParams("CrossDevicePromo", "A",
103 base::FieldTrialList::CreateFieldTrial("CrossDevicePromo", "A");
107 content::TestBrowserThreadBundle bundle_
;
108 CrossDevicePromo
* cross_device_promo_
;
109 TestingProfile
* profile_
;
110 FakeSigninManagerForTesting
* signin_manager_
;
111 FakeGaiaCookieManagerService
* cookie_manager_service_
;
112 TestingPrefServiceSyncable
* pref_service_
;
113 scoped_ptr
<TestingProfileManager
> testing_profile_manager_
;
114 base::HistogramTester histogram_tester_
;
115 scoped_ptr
<base::FieldTrialList
> field_trial_list_
;
116 net::FakeURLFetcherFactory fake_url_fetcher_factory_
;
118 DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoTest
);
121 void CrossDevicePromoTest::SetUp() {
122 testing_profile_manager_
.reset(
123 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
124 ASSERT_TRUE(testing_profile_manager_
.get()->SetUp());
126 TestingProfile::TestingFactories factories
;
127 factories
.push_back(std::make_pair(ChromeSigninClientFactory::GetInstance(),
128 signin::BuildTestSigninClient
));
130 std::make_pair(GaiaCookieManagerServiceFactory::GetInstance(),
131 FakeGaiaCookieManagerService::Build
));
132 factories
.push_back(std::make_pair(SigninManagerFactory::GetInstance(),
133 FakeSigninManagerBase::Build
));
135 pref_service_
= new TestingPrefServiceSyncable();
136 chrome::RegisterUserProfilePrefs(pref_service_
->registry());
138 profile_
= testing_profile_manager_
.get()->CreateTestingProfile(
139 "name", make_scoped_ptr
<PrefServiceSyncable
>(pref_service_
),
140 base::UTF8ToUTF16("name"), 0, std::string(), factories
);
142 cookie_manager_service_
= static_cast<FakeGaiaCookieManagerService
*>(
143 GaiaCookieManagerServiceFactory::GetForProfile(profile()));
144 cookie_manager_service_
->Init(&fake_url_fetcher_factory_
);
146 signin_manager_
= static_cast<FakeSigninManagerForTesting
*>(
147 SigninManagerFactory::GetForProfile(profile()));
148 cross_device_promo_
= CrossDevicePromoFactory::GetForProfile(profile());
151 CrossDevicePromoTest::CrossDevicePromoTest() : fake_url_fetcher_factory_(NULL
) {
152 ResetFieldTrialList();
155 void CrossDevicePromoTest::ResetFieldTrialList() {
156 // Destroy the existing FieldTrialList before creating a new one to avoid
158 field_trial_list_
.reset();
159 field_trial_list_
.reset(
160 new base::FieldTrialList(new metrics::SHA1EntropyProvider("foo")));
161 variations::testing::ClearAllVariationParams();
164 TEST_F(CrossDevicePromoTest
, Uninitialized
) {
165 ASSERT_TRUE(promo());
166 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
167 signin_metrics::NO_VARIATIONS_CONFIG
,
170 promo()->CheckPromoEligibilityForTesting();
171 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
172 signin_metrics::NO_VARIATIONS_CONFIG
,
174 histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0);
175 ASSERT_FALSE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut
));
178 TEST_F(CrossDevicePromoTest
, UnitializedOptedOut
) {
179 CrossDevicePromoObserver
observer(promo());
182 // Opting out doesn't de-activate a never-active promo.
183 ASSERT_EQ(0, observer
.times_set_inactive());
184 ASSERT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut
));
186 // Never initialize a promo that is opted out.
187 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
188 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
189 signin_metrics::NO_VARIATIONS_CONFIG
,
191 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
192 signin_metrics::UNINITIALIZED_OPTED_OUT
,
194 histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0);
197 TEST_F(CrossDevicePromoTest
, PartiallyInitialized
) {
198 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
199 signin_metrics::NO_VARIATIONS_CONFIG
,
202 std::map
<std::string
, std::string
> variations_params
;
203 variations_params
["HoursBetweenSyncDeviceChecks"] = "1";
204 variations_params
["DaysToVerifySingleUserProfile"] = "1";
205 ASSERT_TRUE(variations::AssociateVariationParams("CrossDevicePromo", "A",
207 base::FieldTrialList::CreateFieldTrial("CrossDevicePromo", "A");
209 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
210 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
211 signin_metrics::NO_VARIATIONS_CONFIG
,
213 ASSERT_FALSE(histogram_tester()->GetHistogramSamplesSinceCreation(
214 "Signin.XDevicePromo.Eligibility"));
217 TEST_F(CrossDevicePromoTest
, FullyInitialized
) {
218 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
219 signin_metrics::NO_VARIATIONS_CONFIG
,
222 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
223 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Initialized",
224 signin_metrics::NO_VARIATIONS_CONFIG
,
227 InitPromoVariation();
228 signin_manager()->SignIn("12345", "foo@bar.com", "password");
229 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
230 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
231 signin_metrics::INITIALIZED
, 1);
232 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
233 signin_metrics::NO_VARIATIONS_CONFIG
,
236 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
237 signin_metrics::SIGNED_IN
, 1);
240 TEST_F(CrossDevicePromoTest
, InitializedOptOut
) {
241 // In a normal browser, the variations get set before the CrossDevicePromo is
242 // created. Here, we need to force another Init() by calling
243 // CheckPromoEligibilityForTesting().
244 InitPromoVariation();
245 signin_manager()->SignIn("12345", "foo@bar.com", "password");
246 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
248 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
249 signin_metrics::INITIALIZED
, 1);
250 histogram_tester()->ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
251 signin_metrics::SIGNED_IN
, 1);
253 // After opting out the initialized state remains; eligibility changes.
255 promo()->CheckPromoEligibilityForTesting();
256 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Initialized",
257 signin_metrics::INITIALIZED
, 1);
258 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Eligibility",
259 signin_metrics::OPTED_OUT
, 1);
262 TEST_F(CrossDevicePromoTest
, SignedInAndOut
) {
263 InitPromoVariation();
266 base::HistogramTester test_signed_in
;
267 signin_manager()->SignIn("12345", "foo@bar.com", "password");
268 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
269 test_signed_in
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
270 signin_metrics::SIGNED_IN
, 1);
274 base::HistogramTester test_signed_out
;
275 signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST
);
276 promo()->CheckPromoEligibilityForTesting();
277 test_signed_out
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
278 signin_metrics::NOT_SINGLE_GAIA_ACCOUNT
,
283 TEST_F(CrossDevicePromoTest
, TrackAccountsInCookie
) {
284 InitPromoVariation();
285 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
287 ASSERT_FALSE(prefs()->HasPrefPath(
288 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
289 std::vector
<gaia::ListedAccount
> accounts
;
291 // Setting a single cookie sets the time.
292 base::Time before_setting_cookies
= base::Time::Now();
293 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
294 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
295 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
296 base::RunLoop().RunUntilIdle();
298 base::Time after_setting_cookies
= base::Time::Now();
299 ASSERT_TRUE(prefs()->HasPrefPath(
300 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
302 before_setting_cookies
.ToInternalValue(),
303 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
305 after_setting_cookies
.ToInternalValue(),
306 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
308 // A single cookie a second time doesn't change the time.
309 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
310 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
311 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
312 base::RunLoop().RunUntilIdle();
314 ASSERT_TRUE(prefs()->HasPrefPath(
315 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
317 after_setting_cookies
.ToInternalValue(),
318 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
320 // Setting accounts with an auth error doesn't change the time.
321 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
322 cookie_manager_service()->SetListAccountsResponseWebLoginRequired();
323 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
324 base::RunLoop().RunUntilIdle();
326 ASSERT_TRUE(prefs()->HasPrefPath(
327 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
329 before_setting_cookies
.ToInternalValue(),
330 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
332 after_setting_cookies
.ToInternalValue(),
333 prefs()->GetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
));
335 // Seeing zero accounts clears the pref.
336 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
337 cookie_manager_service()->SetListAccountsResponseNoAccounts();
338 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
339 base::RunLoop().RunUntilIdle();
341 ASSERT_FALSE(prefs()->HasPrefPath(
342 prefs::kCrossDevicePromoObservedSingleAccountCookie
));
345 TEST_F(CrossDevicePromoTest
, SingleAccountEligibility
) {
346 InitPromoVariation();
349 base::HistogramTester test_single_account
;
350 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
351 test_single_account
.ExpectUniqueSample(
352 "Signin.XDevicePromo.Eligibility",
353 signin_metrics::NOT_SINGLE_GAIA_ACCOUNT
, 1);
356 // Notice a single account.
358 base::HistogramTester test_single_account
;
359 std::vector
<gaia::ListedAccount
> accounts
;
360 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
361 cookie_manager_service()->SetListAccountsResponseOneAccount("a@b.com", "1");
362 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
363 base::RunLoop().RunUntilIdle();
365 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
366 test_single_account
.ExpectUniqueSample(
367 "Signin.XDevicePromo.Eligibility",
368 signin_metrics::UNKNOWN_COUNT_DEVICES
, 1);
371 // Set a single account that hasn't been around for "long enough".
373 base::HistogramTester test_single_account
;
374 prefs()->SetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie
,
376 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
377 test_single_account
.ExpectBucketCount(
378 "Signin.XDevicePromo.Eligibility",
379 signin_metrics::NOT_SINGLE_GAIA_ACCOUNT
, 1);
383 TEST_F(CrossDevicePromoTest
, NumDevicesEligibility
) {
384 // Start with a variation, signed in, and one account in the cookie jar.
385 InitPromoVariation();
386 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
387 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
388 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
389 std::vector
<gaia::ListedAccount
> accounts
;
390 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
391 base::RunLoop().RunUntilIdle();
393 // Ensure we appropriate schedule a check for listing devices.
395 base::HistogramTester test_missing_list_devices
;
396 int64 earliest_time_to_check_list_devices
=
397 base::Time::Now().ToInternalValue();
398 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
399 int64 latest_time_to_check_list_devices
= InOneHour();
400 test_missing_list_devices
.ExpectUniqueSample(
401 "Signin.XDevicePromo.Eligibility",
402 signin_metrics::UNKNOWN_COUNT_DEVICES
, 1);
404 prefs()->HasPrefPath(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
405 int64 when_to_check_list_devices
=
406 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
);
407 EXPECT_LT(earliest_time_to_check_list_devices
, when_to_check_list_devices
);
408 EXPECT_GT(latest_time_to_check_list_devices
, when_to_check_list_devices
);
411 // Don't reschedule the list devices check if there's one pending.
413 base::HistogramTester test_unknown_devices
;
414 int64 list_devices_time
= InOneHour();
415 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
417 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
418 test_unknown_devices
.ExpectUniqueSample(
419 "Signin.XDevicePromo.Eligibility",
420 signin_metrics::UNKNOWN_COUNT_DEVICES
, 1);
421 // The scheduled time to call ListDevices should not have changed.
424 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
427 // Execute the list devices check if it's time.
429 base::HistogramTester test_unknown_devices
;
430 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
431 base::Time::Now().ToInternalValue());
432 // The DeviceActivityFetcher will return an error to the promo service.
433 fetcher_factory()->SetFakeResponse(
434 GaiaUrls::GetInstance()->oauth2_iframe_url(), "not json", net::HTTP_OK
,
435 net::URLRequestStatus::SUCCESS
);
436 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
437 base::RunLoop().RunUntilIdle();
438 test_unknown_devices
.ExpectUniqueSample(
439 "Signin.XDevicePromo.Eligibility",
440 signin_metrics::ERROR_FETCHING_DEVICE_ACTIVITY
, 1);
444 TEST_F(CrossDevicePromoTest
, ThrottleDeviceActivityCall
) {
445 // Start with a variation (fully throttled), signed in, one account in cookie.
446 std::map
<std::string
, std::string
> variations_params
;
447 variations_params
["HoursBetweenSyncDeviceChecks"] = "1";
448 variations_params
["DaysToVerifySingleUserProfile"] = "0";
449 variations_params
["MinutesBetweenBrowsingSessions"] = "0";
450 variations_params
["MinutesMaxContextSwitchDuration"] = "10";
451 variations_params
["RPCThrottle"] = "101";
452 EXPECT_TRUE(variations::AssociateVariationParams("CrossDevicePromo", "A",
454 base::FieldTrialList::CreateFieldTrial("CrossDevicePromo", "A");
456 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
457 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
458 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
459 std::vector
<gaia::ListedAccount
> accounts
;
460 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
461 base::RunLoop().RunUntilIdle();
463 // Ensure Device Activity Fetch gets throttled.
465 base::HistogramTester test_throttle_rpc
;
466 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
467 base::Time::Now().ToInternalValue());
468 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
469 test_throttle_rpc
.ExpectUniqueSample(
470 "Signin.XDevicePromo.Eligibility",
471 signin_metrics::THROTTLED_FETCHING_DEVICE_ACTIVITY
, 1);
475 TEST_F(CrossDevicePromoTest
, NumDevicesKnown
) {
476 // Start with a variation, signed in, and one account, sync devices in 1 hour.
477 InitPromoVariation();
478 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
479 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
480 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
481 std::vector
<gaia::ListedAccount
> accounts
;
482 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
483 base::RunLoop().RunUntilIdle();
484 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
487 // If there is no device present.
489 base::HistogramTester test_no_devices
;
490 prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices
, 0);
491 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
492 test_no_devices
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
493 signin_metrics::ZERO_DEVICES
, 1);
496 // If there is one device present.
498 prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices
, 1);
499 EXPECT_TRUE(promo()->CheckPromoEligibilityForTesting());
503 TEST_F(CrossDevicePromoTest
, FetchDeviceResults
) {
504 // Start with a variation, signed in, and one account, sync devices in 1 hour.
505 InitPromoVariation();
506 EXPECT_FALSE(promo()->CheckPromoEligibilityForTesting());
507 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
508 cookie_manager_service()->SetListAccountsResponseOneAccount("f@bar.com", "1");
509 std::vector
<gaia::ListedAccount
> accounts
;
510 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts
));
511 base::RunLoop().RunUntilIdle();
512 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
,
513 base::Time::Now().ToInternalValue());
514 prefs()->SetInteger(prefs::kCrossDevicePromoNumDevices
, 1);
516 // If there is no device found.
518 base::HistogramTester test_no_devices
;
519 std::vector
<DeviceActivityFetcher::DeviceActivity
> devices
;
520 int64 in_one_hour
= InOneHour();
521 promo()->OnFetchDeviceActivitySuccess(devices
);
524 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
525 EXPECT_EQ(0, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices
));
526 test_no_devices
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
527 signin_metrics::ZERO_DEVICES
, 1);
530 // If there is one device found. It was recently active.
532 CrossDevicePromoObserver
observer(promo());
533 ASSERT_FALSE(observer
.is_active());
534 base::HistogramTester test_one_device
;
535 std::vector
<DeviceActivityFetcher::DeviceActivity
> devices
;
536 base::Time device_last_active
=
537 base::Time::Now() - base::TimeDelta::FromMinutes(4);
538 DeviceActivityFetcher::DeviceActivity device
;
539 device
.last_active
= device_last_active
;
540 device
.name
= "Aslan";
541 devices
.push_back(device
);
543 int64 in_one_hour
= InOneHour();
544 promo()->OnFetchDeviceActivitySuccess(devices
);
547 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
548 EXPECT_EQ(1, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices
));
549 EXPECT_EQ(device_last_active
.ToInternalValue(),
550 prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime
));
551 EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoActive
));
552 test_one_device
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
553 signin_metrics::ELIGIBLE
, 1);
554 EXPECT_TRUE(observer
.is_active());
555 EXPECT_EQ(1, observer
.times_set_active());
558 // If there is one device found. It was not recently active.
560 CrossDevicePromoObserver
observer(promo());
561 ASSERT_FALSE(observer
.is_active());
562 base::HistogramTester test_one_device
;
563 std::vector
<DeviceActivityFetcher::DeviceActivity
> devices
;
564 base::Time device_last_active
=
565 base::Time::Now() - base::TimeDelta::FromMinutes(30);
566 DeviceActivityFetcher::DeviceActivity device
;
567 device
.last_active
= device_last_active
;
568 device
.name
= "Aslan";
569 devices
.push_back(device
);
571 int64 in_one_hour
= InOneHour();
572 promo()->OnFetchDeviceActivitySuccess(devices
);
575 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
576 EXPECT_EQ(1, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices
));
577 EXPECT_EQ(device_last_active
.ToInternalValue(),
578 prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime
));
579 EXPECT_FALSE(prefs()->GetBoolean(prefs::kCrossDevicePromoActive
));
580 test_one_device
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
581 signin_metrics::NO_ACTIVE_DEVICES
, 1);
582 EXPECT_FALSE(observer
.is_active());
585 // If there are two devices found, one recently.
587 CrossDevicePromoObserver
observer(promo());
588 ASSERT_FALSE(observer
.is_active());
589 base::HistogramTester test_two_devices
;
590 std::vector
<DeviceActivityFetcher::DeviceActivity
> devices
;
591 base::Time device1_last_active
=
592 base::Time::Now() - base::TimeDelta::FromMinutes(30);
593 base::Time device2_last_active
=
594 base::Time::Now() - base::TimeDelta::FromMinutes(3);
595 DeviceActivityFetcher::DeviceActivity device1
;
596 device1
.last_active
= device1_last_active
;
597 device1
.name
= "Aslan";
598 devices
.push_back(device1
);
599 DeviceActivityFetcher::DeviceActivity device2
;
600 device2
.last_active
= device2_last_active
;
601 device2
.name
= "Balrog";
602 devices
.push_back(device2
);
604 int64 in_one_hour
= InOneHour();
605 promo()->OnFetchDeviceActivitySuccess(devices
);
608 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime
));
609 EXPECT_EQ(2, prefs()->GetInteger(prefs::kCrossDevicePromoNumDevices
));
610 EXPECT_EQ(device2_last_active
.ToInternalValue(),
611 prefs()->GetInt64(prefs::kCrossDevicePromoLastDeviceActiveTime
));
612 EXPECT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoActive
));
613 test_two_devices
.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
614 signin_metrics::ELIGIBLE
, 1);
615 EXPECT_TRUE(observer
.is_active());
616 EXPECT_EQ(1, observer
.times_set_active());