Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(958)

Side by Side Diff: chrome/browser/signin/cross_device_promo_unittest.cc

Issue 1087933002: Cross Device Promo - Main Eligibility Flow (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add a flow for when the first listDevices request is scheduled in the future. Tests around the sche… Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "chrome/browser/signin/cross_device_promo.h"
6
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 "net/url_request/test_url_fetcher_factory.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32
33 namespace {
34
35 int64 InOneHour() {
36 return (base::Time::Now() + base::TimeDelta::FromHours(1)).ToInternalValue();
37 }
38
39 }
40
41 class CrossDevicePromoObserver : public CrossDevicePromo::Observer {
42 public:
43 explicit CrossDevicePromoObserver(CrossDevicePromo* promo) :
44 active_(false), set_active_(0), set_inactive_(0), promo_(promo) {
45 promo->AddObserver(this);
46 }
47
48 ~CrossDevicePromoObserver() {
49 promo_->RemoveObserver(this);
50 }
51
52 void OnPromoActivationChanged(bool active) override {
53 active_ = active;
54 active ? set_active_++ : set_inactive_++;
55 }
56
57 bool IsActive() { return active_; }
58 int TimesBecameActive() { return set_active_; }
59 int TimesBecameInactive() { return set_inactive_; }
60
61 private:
62 bool active_;
63 int set_active_;
64 int set_inactive_;
65 CrossDevicePromo* promo_;
66 };
67
68 class CrossDevicePromoTest : public ::testing::Test {
69 public:
70 CrossDevicePromoTest();
71 void SetUp() override;
72
73 void ResetFieldTrialList();
74
75 CrossDevicePromo* promo() { return cross_device_promo_; }
76 TestingProfile* profile() { return profile_; }
77 FakeSigninManagerForTesting* signin_manager() { return signin_manager_; }
78 base::HistogramTester* histogram_tester() { return &histogram_tester_; }
79 TestingPrefServiceSyncable* prefs() { return pref_service_; }
80 FakeGaiaCookieManagerService* cookie_manager_service() {
81 return cookie_manager_service_;
82 }
83 net::FakeURLFetcherFactory* fetcher_factory() {
84 return &url_fetcher_factory_;
85 }
86
87 void InitPromoVariation() {
88 std::map<std::string, std::string> variations_params;
89 variations_params["HoursBetweenSyncDeviceChecks"] = "1";
90 variations_params["DaysToVerifySingleUserProfile"] = "0";
91 variations_params["MinutesBetweenBrowsingSessions"] = "0";
92 variations_params["MinutesMaxContextSwitchDuration"] = "0";
93 EXPECT_TRUE(variations::AssociateVariationParams(
94 "CrossDevicePromo", "A", variations_params));
95 base::FieldTrialList::CreateFieldTrial("CrossDevicePromo", "A");
96 }
97
98 private:
99 content::TestBrowserThreadBundle bundle_;
100 CrossDevicePromo* cross_device_promo_;
101 TestingProfile* profile_;
102 FakeSigninManagerForTesting* signin_manager_;
103 FakeGaiaCookieManagerService* cookie_manager_service_;
104 TestingPrefServiceSyncable* pref_service_;
105 scoped_ptr<TestingProfileManager> testing_profile_manager_;
106 base::HistogramTester histogram_tester_;
107 scoped_ptr<base::FieldTrialList> field_trial_list_;
108 net::FakeURLFetcherFactory url_fetcher_factory_;
109
110 DISALLOW_COPY_AND_ASSIGN(CrossDevicePromoTest);
111 };
112
113 void CrossDevicePromoTest::SetUp() {
114 testing_profile_manager_.reset(
115 new TestingProfileManager(TestingBrowserProcess::GetGlobal()));
116 ASSERT_TRUE(testing_profile_manager_.get()->SetUp());
117
118 TestingProfile::TestingFactories factories;
119 factories.push_back(std::make_pair(ChromeSigninClientFactory::GetInstance(),
120 signin::BuildTestSigninClient));
121 factories.push_back(std::make_pair(
122 GaiaCookieManagerServiceFactory::GetInstance(),
123 FakeGaiaCookieManagerService::Build));
124 factories.push_back(std::make_pair(SigninManagerFactory::GetInstance(),
125 FakeSigninManagerBase::Build));
126
127 pref_service_ = new TestingPrefServiceSyncable();
128 chrome::RegisterUserProfilePrefs(pref_service_->registry());
129
130 profile_ = testing_profile_manager_.get()->CreateTestingProfile(
131 "name", make_scoped_ptr<PrefServiceSyncable>(pref_service_),
132 base::UTF8ToUTF16("name"), 0, std::string(), factories);
133
134 cookie_manager_service_ =
135 static_cast<FakeGaiaCookieManagerService*>(
136 GaiaCookieManagerServiceFactory::GetForProfile(profile()));
137 cookie_manager_service_->Init(&url_fetcher_factory_);
138
139 signin_manager_ =
140 static_cast<FakeSigninManagerForTesting*>(
141 SigninManagerFactory::GetForProfile(profile()));
142 cross_device_promo_ = CrossDevicePromoFactory::GetForProfile(profile());
143 }
144
145 CrossDevicePromoTest::CrossDevicePromoTest() : url_fetcher_factory_(NULL) {
146 ResetFieldTrialList();
147 }
148
149 void CrossDevicePromoTest::ResetFieldTrialList() {
150 // Destroy the existing FieldTrialList before creating a new one to avoid
151 // a DCHECK.
152 field_trial_list_.reset();
153 field_trial_list_.reset(new base::FieldTrialList(
154 new metrics::SHA1EntropyProvider("foo")));
155 variations::testing::ClearAllVariationParams();
156 }
157
158 TEST_F(CrossDevicePromoTest, Uninitialized) {
159 ASSERT_TRUE(promo());
160 histogram_tester()->ExpectUniqueSample(
161 "Signin.XDevicePromo.Initialized", 0, 1);
162
163 promo()->CheckPromoEligibility();
164 histogram_tester()->ExpectUniqueSample(
165 "Signin.XDevicePromo.Initialized", 0, 2);
166 histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0);
167 ASSERT_FALSE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut));
168 }
169
170 TEST_F(CrossDevicePromoTest, UnitializedOptedOut) {
171 CrossDevicePromoObserver observer(promo());
172
173 promo()->OptOut();
174 // Opting out doesn't de-activate a never-active promo.
175 ASSERT_EQ(0, observer.TimesBecameInactive());
176 ASSERT_TRUE(prefs()->GetBoolean(prefs::kCrossDevicePromoOptedOut));
177
178 // Never initialize a promo that is opted out.
179 EXPECT_FALSE(promo()->CheckPromoEligibility());
180 histogram_tester()->ExpectUniqueSample(
181 "Signin.XDevicePromo.Initialized", 0, 2);
182 histogram_tester()->ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0);
183 }
184
185 TEST_F(CrossDevicePromoTest, PartiallyInitialized) {
186 histogram_tester()->ExpectUniqueSample(
187 "Signin.XDevicePromo.Initialized", 0, 1);
188
189 std::map<std::string, std::string> variations_params;
190 variations_params["HoursBetweenSyncDeviceChecks"] = "1";
191 variations_params["DaysToVerifySingleUserProfile"] = "1";
192 ASSERT_TRUE(variations::AssociateVariationParams(
193 "CrossDevicePromo", "A", variations_params));
194 base::FieldTrialList::CreateFieldTrial("CrossDevicePromo", "A");
195
196 EXPECT_FALSE(promo()->CheckPromoEligibility());
197 histogram_tester()->ExpectUniqueSample(
198 "Signin.XDevicePromo.Initialized", 0, 2);
199 ASSERT_FALSE(histogram_tester()->GetHistogramSamplesSinceCreation(
200 "Signin.XDevicePromo.Eligibility"));
201 }
202
203 TEST_F(CrossDevicePromoTest, FullyInitialized) {
204 histogram_tester()->ExpectUniqueSample(
205 "Signin.XDevicePromo.Initialized", 0, 1);
206
207 EXPECT_FALSE(promo()->CheckPromoEligibility());
208 histogram_tester()->ExpectUniqueSample(
209 "Signin.XDevicePromo.Initialized", 0, 2);
210
211 InitPromoVariation();
212 EXPECT_FALSE(promo()->CheckPromoEligibility());
213 histogram_tester()->ExpectBucketCount(
214 "Signin.XDevicePromo.Initialized", 1, 1);
215 histogram_tester()->ExpectBucketCount(
216 "Signin.XDevicePromo.Initialized", 0, 2);
217
218 histogram_tester()->ExpectUniqueSample(
219 "Signin.XDevicePromo.Eligibility", signin_metrics::NOT_SIGNED_IN, 1);
220 }
221
222 TEST_F(CrossDevicePromoTest, InitializedOptOut) {
223 // In a normal browser, the variations get set before the CrossDevicePromo is
224 // created. Here, we need to force another Init() by calling
225 // CheckPromoEligibility().
226 InitPromoVariation();
227 EXPECT_FALSE(promo()->CheckPromoEligibility());
228
229 histogram_tester()->ExpectBucketCount(
230 "Signin.XDevicePromo.Initialized", 1, 1);
231 histogram_tester()->ExpectUniqueSample(
232 "Signin.XDevicePromo.Eligibility", signin_metrics::NOT_SIGNED_IN, 1);
233
234 // After opting out the initialized state remains; eligibility changes.
235 promo()->OptOut();
236 promo()->CheckPromoEligibility();
237 histogram_tester()->ExpectBucketCount(
238 "Signin.XDevicePromo.Initialized", 1, 1);
239 histogram_tester()->ExpectBucketCount(
240 "Signin.XDevicePromo.Eligibility", signin_metrics::OPTED_OUT, 1);
241 }
242
243 TEST_F(CrossDevicePromoTest, SignedIn) {
244 InitPromoVariation();
245 EXPECT_FALSE(promo()->CheckPromoEligibility());
246 histogram_tester()->ExpectBucketCount(
247 "Signin.XDevicePromo.Initialized", 1, 1);
248 histogram_tester()->ExpectUniqueSample(
249 "Signin.XDevicePromo.Eligibility", signin_metrics::NOT_SIGNED_IN, 1);
250
251 signin_manager()->SignIn("12345", "foo@bar.com", "password");
252 promo()->CheckPromoEligibility();
253 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Eligibility",
254 signin_metrics::OPTED_OUT, 0);
255 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Eligibility",
256 signin_metrics::NOT_SIGNED_IN, 1);
257 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Eligibility",
258 signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, 1);
259 histogram_tester()->ExpectBucketCount("Signin.XDevicePromo.Eligibility",
260 signin_metrics::UNKNOWN_COUNT_SYNC_DEVICES, 0);
261 }
262
263 TEST_F(CrossDevicePromoTest, TrackAccountsInCookie) {
264 InitPromoVariation();
265 EXPECT_FALSE(promo()->CheckPromoEligibility());
266
267 ASSERT_FALSE(prefs()->HasPrefPath(
268 prefs::kCrossDevicePromoObservedSingleAccountCookie));
269 std::vector<std::pair<std::string, bool>> accounts;
270
271 // Setting a single cookie sets the time.
272 base::Time before_setting_cookies = base::Time::Now();
273 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
274 cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
275 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
276 base::RunLoop().RunUntilIdle();
277
278 base::Time after_setting_cookies = base::Time::Now();
279 ASSERT_TRUE(prefs()->HasPrefPath(
280 prefs::kCrossDevicePromoObservedSingleAccountCookie));
281 ASSERT_LT(before_setting_cookies.ToInternalValue(), prefs()->GetInt64(
282 prefs::kCrossDevicePromoObservedSingleAccountCookie));
283 ASSERT_GT(after_setting_cookies.ToInternalValue(), prefs()->GetInt64(
284 prefs::kCrossDevicePromoObservedSingleAccountCookie));
285
286 // A single cookie a second time doesn't change the time.
287 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
288 cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
289 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
290 base::RunLoop().RunUntilIdle();
291
292 ASSERT_TRUE(prefs()->HasPrefPath(
293 prefs::kCrossDevicePromoObservedSingleAccountCookie));
294 ASSERT_GT(after_setting_cookies.ToInternalValue(), prefs()->GetInt64(
295 prefs::kCrossDevicePromoObservedSingleAccountCookie));
296
297 // Setting accounts with an auth error doesn't change the time.
298 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
299 cookie_manager_service()->SetListAccountsResponseWebLoginRequired();
300 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
301 base::RunLoop().RunUntilIdle();
302
303 ASSERT_TRUE(prefs()->HasPrefPath(
304 prefs::kCrossDevicePromoObservedSingleAccountCookie));
305 ASSERT_LT(before_setting_cookies.ToInternalValue(), prefs()->GetInt64(
306 prefs::kCrossDevicePromoObservedSingleAccountCookie));
307 ASSERT_GT(after_setting_cookies.ToInternalValue(), prefs()->GetInt64(
308 prefs::kCrossDevicePromoObservedSingleAccountCookie));
309
310 // Seeing zero accounts clears the pref.
311 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
312 cookie_manager_service()->SetListAccountsResponseNoAccounts();
313 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
314 base::RunLoop().RunUntilIdle();
315
316 ASSERT_FALSE(prefs()->HasPrefPath(
317 prefs::kCrossDevicePromoObservedSingleAccountCookie));
318 }
319
320 TEST_F(CrossDevicePromoTest, SingleAccountEligibility) {
321 InitPromoVariation();
322 signin_manager()->SignIn("12345", "foo@bar.com", "password");
323 {
324 base::HistogramTester test_single_account;
325 EXPECT_FALSE(promo()->CheckPromoEligibility());
326 test_single_account.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
327 signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, 1);
328 }
329
330 // Notice a single account.
331 {
332 base::HistogramTester test_single_account;
333 std::vector<std::pair<std::string, bool>> accounts;
334 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
335 cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
336 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
337 base::RunLoop().RunUntilIdle();
338
339 EXPECT_FALSE(promo()->CheckPromoEligibility());
340 test_single_account.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
341 signin_metrics::UNKNOWN_COUNT_SYNC_DEVICES, 1);
342 }
343
344 // Set a single account that hasn't been around for "long enough".
345 {
346 base::HistogramTester test_single_account;
347 prefs()->SetInt64(prefs::kCrossDevicePromoObservedSingleAccountCookie,
348 InOneHour());
349 EXPECT_FALSE(promo()->CheckPromoEligibility());
350 test_single_account.ExpectBucketCount("Signin.XDevicePromo.Eligibility",
351 signin_metrics::NOT_SINGLE_GAIA_ACCOUNT, 1);
352 }
353 }
354
355 TEST_F(CrossDevicePromoTest, NumDevicesEligibility) {
356 // Start with a variation, signed in, and one account in the cookie jar.
357 InitPromoVariation();
358 signin_manager()->SignIn("12345", "foo@bar.com", "password");
359 cookie_manager_service()->set_list_accounts_fetched_once_for_testing(false);
360 cookie_manager_service()->SetListAccountsResponseOneAccount("foo@bar.com");
361 std::vector<std::pair<std::string, bool>> accounts;
362 EXPECT_FALSE(cookie_manager_service()->ListAccounts(&accounts));
363 base::RunLoop().RunUntilIdle();
364
365 // Ensure we appropriate schedule a check for listing devices.
366 {
367 base::HistogramTester test_missing_list_devices;
368 base::Time earliest_time_to_check_list_devices = base::Time::Now();
369 EXPECT_FALSE(promo()->CheckPromoEligibility());
370 base::Time latest_time_to_check_list_devices = InOneHour();
371 test_missing_list_devices.ExpectUniqueSample(
372 "Signin.XDevicePromo.Eligibility",
373 signin_metrics::UNKNOWN_COUNT_SYNC_DEVICES, 1);
374 EXPECT_TRUE(prefs()->HasPrefPath(
375 prefs::kCrossDevicePromoNextFetchListDevicesTime));
376 base::Time when_to_check_list_devices = base::Time::FromInternalValue(
377 prefs()->GetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime));
378 EXPECT_LT(earliest_time_to_check_list_devices, when_to_check_list_devices);
379 EXPECT_GT(latest_time_to_check_list_devices, when_to_check_list_devices);
380 }
381
382 // Don't reschedule the list devices check if there's one pending.
383 {
384 base::HistogramTester test_unknown_devices;
385 int64 list_devices_time = InOneHour();
386 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime,
387 list_devices_time);
388 EXPECT_FALSE(promo()->CheckPromoEligibility());
389 test_unknown_devices.ExpectUniqueSample("Signin.XDevicePromo.Eligibility",
390 signin_metrics::UNKNOWN_COUNT_SYNC_DEVICES, 1);
391 // The scheduled time to call ListDevices should not have changed.
392 ASSERT_EQ(list_devices_time, prefs()->GetInt64(
393 prefs::kCrossDevicePromoNextFetchListDevicesTime));
394 }
395
396 // Execute the list devices check if it's time.
397 {
398 base::HistogramTester test_unknown_devices;
399 prefs()->SetInt64(prefs::kCrossDevicePromoNextFetchListDevicesTime,
400 base::Time::Now().ToInternalValue());
401 EXPECT_FALSE(fetcher_factory()->GetFetcherByID(0));
402 EXPECT_FALSE(promo()->CheckPromoEligibility());
403 // No stat of eligibility until the request comes back.
404 test_unknown_devices.ExpectTotalCount("Signin.XDevicePromo.Eligibility", 0);
405 net::TestURLFetcher* fetcher = fetcher_factory()->GetFetcherByID(0);
406 ASSERT_TRUE(fetcher);
407 ASSERT_EQ(GaiaUrls::oauth2_iframe_url(), fetcher->GetURL());
408 }
409
410 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698