1 // Copyright (c) 2012 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/profiles/gaia_info_update_service.h"
6
7 #include <stddef.h>
8
9 #include <string>
10
11 #include "base/bind.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/test/metrics/histogram_tester.h"
14 #include "build/build_config.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/profiles/profile_attributes_entry.h"
17 #include "chrome/browser/profiles/profile_attributes_storage.h"
18 #include "chrome/browser/profiles/profile_downloader.h"
19 #include "chrome/browser/profiles/profile_info_cache.h"
20 #include "chrome/browser/profiles/profile_info_cache_unittest.h"
21 #include "chrome/browser/profiles/profiles_state.h"
22 #include "chrome/browser/signin/chrome_signin_client_factory.h"
23 #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
24 #include "chrome/browser/signin/test_signin_client_builder.h"
25 #include "chrome/common/pref_names.h"
26 #include "chrome/test/base/testing_browser_process.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "chrome/test/base/testing_profile_manager.h"
29 #include "components/prefs/pref_service.h"
30 #include "components/profile_metrics/state.h"
31 #include "components/signin/public/base/signin_pref_names.h"
32 #include "components/signin/public/identity_manager/account_info.h"
33 #include "components/sync_preferences/pref_service_syncable.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "ui/gfx/image/image.h"
36 #include "ui/gfx/image/image_unittest_util.h"
37
38 using ::testing::Return;
39
40 namespace {
41
42 #if !defined(OS_CHROMEOS)
GetValidAccountInfo(std::string email,CoreAccountId account_id,std::string given_name,std::string full_name,std::string hosted_domain)43 AccountInfo GetValidAccountInfo(std::string email,
44 CoreAccountId account_id,
45 std::string given_name,
46 std::string full_name,
47 std::string hosted_domain) {
48 AccountInfo account_info;
49 account_info.email = email;
50 account_info.gaia = account_id.ToString();
51 account_info.account_id = account_id;
52 account_info.given_name = given_name;
53 account_info.full_name = full_name;
54 account_info.hosted_domain = hosted_domain;
55 account_info.locale = email;
56 account_info.picture_url = "example.com";
57 return account_info;
58 }
59
60 #if !defined(ANDROID)
61 const char kChromiumOrgDomain[] = "chromium.org";
62 #endif // !defined(ANDROID)
63
64 #endif // !defined(OS_CHROMEOS)
65
66 class GAIAInfoUpdateServiceTest : public testing::Test {
67 protected:
GAIAInfoUpdateServiceTest()68 GAIAInfoUpdateServiceTest()
69 : testing_profile_manager_(TestingBrowserProcess::GetGlobal()) {}
70 ~GAIAInfoUpdateServiceTest() override = default;
71
SetUp()72 void SetUp() override {
73 testing::Test::SetUp();
74 ASSERT_TRUE(testing_profile_manager_.SetUp());
75 RecreateGAIAInfoUpdateService();
76 }
77
RecreateGAIAInfoUpdateService()78 void RecreateGAIAInfoUpdateService() {
79 if (service_)
80 service_->Shutdown();
81
82 service_.reset(new GAIAInfoUpdateService(
83 identity_test_env_.identity_manager(),
84 testing_profile_manager_.profile_attributes_storage(),
85 profile()->GetPath(), profile()->GetPrefs()));
86 }
87
TearDown()88 void TearDown() override {
89 if (service_) {
90 service_->Shutdown();
91 service_.reset();
92 }
93 }
94
profile()95 TestingProfile* profile() {
96 if (!profile_)
97 CreateProfile("Person 1");
98 return profile_;
99 }
100
identity_test_env()101 signin::IdentityTestEnvironment* identity_test_env() {
102 return &identity_test_env_;
103 }
104
storage()105 ProfileAttributesStorage* storage() {
106 return testing_profile_manager_.profile_attributes_storage();
107 }
108
service()109 GAIAInfoUpdateService* service() { return service_.get(); }
110
CreateProfile(const std::string & name)111 void CreateProfile(const std::string& name) {
112 profile_ = testing_profile_manager_.CreateTestingProfile(
113 name, std::unique_ptr<sync_preferences::PrefServiceSyncable>(),
114 base::UTF8ToUTF16(name), 0, std::string(),
115 TestingProfile::TestingFactories());
116 }
117
118 content::BrowserTaskEnvironment task_environment_;
119 TestingProfileManager testing_profile_manager_;
120 TestingProfile* profile_ = nullptr;
121 signin::IdentityTestEnvironment identity_test_env_;
122 std::unique_ptr<GAIAInfoUpdateService> service_;
123
124 private:
125 DISALLOW_COPY_AND_ASSIGN(GAIAInfoUpdateServiceTest);
126 };
127 } // namespace
128
TEST_F(GAIAInfoUpdateServiceTest,ShouldUseGAIAProfileInfo)129 TEST_F(GAIAInfoUpdateServiceTest, ShouldUseGAIAProfileInfo) {
130 #if defined(OS_CHROMEOS)
131 // This feature should never be enabled on ChromeOS.
132 EXPECT_FALSE(GAIAInfoUpdateService::ShouldUseGAIAProfileInfo(profile()));
133 #endif
134 }
135
136 #if !defined(OS_CHROMEOS)
137
TEST_F(GAIAInfoUpdateServiceTest,SyncOnSyncOff)138 TEST_F(GAIAInfoUpdateServiceTest, SyncOnSyncOff) {
139 AccountInfo info =
140 identity_test_env()->MakeAccountAvailable("pat@example.com");
141 base::RunLoop().RunUntilIdle();
142 identity_test_env()->SetPrimaryAccount(info.email);
143 info = GetValidAccountInfo(info.email, info.account_id, "Pat", "Pat Foo",
144 kNoHostedDomainFound);
145 signin::UpdateAccountInfoForAccount(identity_test_env()->identity_manager(),
146 info);
147 base::RunLoop().RunUntilIdle();
148
149 ASSERT_EQ(1u, storage()->GetNumberOfProfiles());
150 ProfileAttributesEntry* entry = storage()->GetAllProfilesAttributes().front();
151 EXPECT_EQ(entry->GetGAIAGivenName(), base::UTF8ToUTF16("Pat"));
152 EXPECT_EQ(entry->GetGAIAName(), base::UTF8ToUTF16("Pat Foo"));
153 EXPECT_EQ(entry->GetHostedDomain(), kNoHostedDomainFound);
154 EXPECT_EQ(
155 profile()->GetPrefs()->GetString(prefs::kGoogleServicesHostedDomain),
156 kNoHostedDomainFound);
157
158 gfx::Image gaia_picture = gfx::test::CreateImage(256, 256);
159 signin::SimulateAccountImageFetch(identity_test_env()->identity_manager(),
160 info.account_id, "GAIA_IMAGE_URL_WITH_SIZE",
161 gaia_picture);
162 // Set a fake picture URL.
163 EXPECT_TRUE(gfx::test::AreImagesEqual(gaia_picture, entry->GetAvatarIcon()));
164 // Log out.
165 identity_test_env()->ClearPrimaryAccount();
166 // Verify that the GAIA name and picture, and picture URL are unset.
167 EXPECT_TRUE(entry->GetGAIAGivenName().empty());
168 EXPECT_TRUE(entry->GetGAIAName().empty());
169 EXPECT_EQ(nullptr, entry->GetGAIAPicture());
170 EXPECT_TRUE(entry->GetHostedDomain().empty());
171 EXPECT_TRUE(profile()
172 ->GetPrefs()
173 ->GetString(prefs::kGoogleServicesHostedDomain)
174 .empty());
175 }
176
177 #if !defined(ANDROID)
TEST_F(GAIAInfoUpdateServiceTest,SyncOnSyncOffKeepAllAccounts)178 TEST_F(GAIAInfoUpdateServiceTest, SyncOnSyncOffKeepAllAccounts) {
179 AccountInfo info =
180 identity_test_env()->MakeAccountAvailable("pat@example.com");
181 base::RunLoop().RunUntilIdle();
182 identity_test_env()->SetPrimaryAccount(info.email);
183 info = GetValidAccountInfo(info.email, info.account_id, "Pat", "Pat Foo",
184 kNoHostedDomainFound);
185 signin::UpdateAccountInfoForAccount(identity_test_env()->identity_manager(),
186 info);
187 base::RunLoop().RunUntilIdle();
188
189 ASSERT_EQ(1u, storage()->GetNumberOfProfiles());
190 ProfileAttributesEntry* entry = storage()->GetAllProfilesAttributes().front();
191 gfx::Image gaia_picture = gfx::test::CreateImage(256, 256);
192 signin::SimulateAccountImageFetch(identity_test_env()->identity_manager(),
193 info.account_id, "GAIA_IMAGE_URL_WITH_SIZE",
194 gaia_picture);
195 // Turn off sync but stay logged in.
196 identity_test_env()->ClearPrimaryAccount(
197 signin::ClearPrimaryAccountPolicy::KEEP_ALL_ACCOUNTS);
198 ASSERT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount(
199 signin::ConsentLevel::kNotRequired));
200 // Verify that the GAIA name and picture, and picture URL are not cleared
201 // as unconsented primary account still exists.
202 EXPECT_EQ(entry->GetGAIAGivenName(), base::UTF8ToUTF16("Pat"));
203 EXPECT_EQ(entry->GetGAIAName(), base::UTF8ToUTF16("Pat Foo"));
204 EXPECT_EQ(entry->GetHostedDomain(), kNoHostedDomainFound);
205 EXPECT_EQ(
206 profile()->GetPrefs()->GetString(prefs::kGoogleServicesHostedDomain),
207 kNoHostedDomainFound);
208 EXPECT_TRUE(gfx::test::AreImagesEqual(gaia_picture, entry->GetAvatarIcon()));
209 }
210
TEST_F(GAIAInfoUpdateServiceTest,LogInLogOut)211 TEST_F(GAIAInfoUpdateServiceTest, LogInLogOut) {
212 std::string email = "pat@example.com";
213 AccountInfo info =
214 identity_test_env()->MakeUnconsentedPrimaryAccountAvailable(email);
215 EXPECT_TRUE(identity_test_env()->identity_manager()->HasPrimaryAccount(
216 signin::ConsentLevel::kNotRequired));
217 EXPECT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount());
218 info = GetValidAccountInfo(info.email, info.account_id, "Pat", "Pat Foo",
219 kNoHostedDomainFound);
220 signin::UpdateAccountInfoForAccount(identity_test_env()->identity_manager(),
221 info);
222 base::RunLoop().RunUntilIdle();
223
224 ASSERT_EQ(1u, storage()->GetNumberOfProfiles());
225 ProfileAttributesEntry* entry = storage()->GetAllProfilesAttributes().front();
226 EXPECT_EQ(entry->GetGAIAGivenName(), base::UTF8ToUTF16("Pat"));
227 EXPECT_EQ(entry->GetGAIAName(), base::UTF8ToUTF16("Pat Foo"));
228 EXPECT_EQ(entry->GetHostedDomain(), kNoHostedDomainFound);
229 EXPECT_EQ(
230 profile()->GetPrefs()->GetString(prefs::kGoogleServicesHostedDomain),
231 kNoHostedDomainFound);
232
233 gfx::Image gaia_picture = gfx::test::CreateImage(256, 256);
234 signin::SimulateAccountImageFetch(identity_test_env()->identity_manager(),
235 info.account_id, "GAIA_IMAGE_URL_WITH_SIZE",
236 gaia_picture);
237 // Set a fake picture URL.
238 EXPECT_TRUE(gfx::test::AreImagesEqual(gaia_picture, entry->GetAvatarIcon()));
239 // Log out.
240 identity_test_env()->ClearPrimaryAccount();
241 base::RunLoop().RunUntilIdle();
242
243 // Verify that the GAIA name and picture, and picture URL are unset.
244 EXPECT_TRUE(entry->GetGAIAGivenName().empty());
245 EXPECT_TRUE(entry->GetGAIAName().empty());
246 EXPECT_EQ(nullptr, entry->GetGAIAPicture());
247 EXPECT_TRUE(entry->GetHostedDomain().empty());
248 EXPECT_TRUE(profile()
249 ->GetPrefs()
250 ->GetString(prefs::kGoogleServicesHostedDomain)
251 .empty());
252 }
253
TEST_F(GAIAInfoUpdateServiceTest,LogInLogOutLogIn)254 TEST_F(GAIAInfoUpdateServiceTest, LogInLogOutLogIn) {
255 std::string email1 = "pat1@example.com";
256 AccountInfo info1 = identity_test_env()->MakeAccountAvailableWithCookies(
257 email1, signin::GetTestGaiaIdForEmail(email1));
258 base::RunLoop().RunUntilIdle();
259 info1 = GetValidAccountInfo(info1.email, info1.account_id, "Pat 1",
260 "Pat Foo The First", kNoHostedDomainFound);
261 signin::UpdateAccountInfoForAccount(identity_test_env()->identity_manager(),
262 info1);
263 base::RunLoop().RunUntilIdle();
264 ASSERT_EQ(1u, storage()->GetNumberOfProfiles());
265 ProfileAttributesEntry* entry = storage()->GetAllProfilesAttributes().front();
266
267 // Test correct histogram recording for all accounts info that has no getters.
268 base::HistogramTester tester;
269 entry->RecordAccountMetrics();
270 tester.ExpectBucketCount(
271 "Profile.AllAccounts.Names",
272 /*sample=*/profile_metrics::AllAccountsNames::kLikelySingleName,
273 /*expected_count=*/1);
274 tester.ExpectBucketCount(
275 "Profile.AllAccounts.Categories",
276 /*sample=*/profile_metrics::AllAccountsCategories::kSingleCategory,
277 /*expected_count=*/1);
278
279 // Log out and record the metric again, sign-out wipes previous info in the
280 // entry so again the default values get reported.
281 identity_test_env()->SetCookieAccounts({});
282 entry->RecordAccountMetrics();
283 tester.ExpectBucketCount(
284 "Profile.AllAccounts.Names",
285 /*sample=*/profile_metrics::AllAccountsNames::kLikelySingleName,
286 /*expected_count=*/2);
287 tester.ExpectBucketCount(
288 "Profile.AllAccounts.Categories",
289 /*sample=*/profile_metrics::AllAccountsCategories::kSingleCategory,
290 /*expected_count=*/2);
291
292 std::string email2 = "pat2@example.com";
293 AccountInfo info2 = identity_test_env()->MakeAccountAvailableWithCookies(
294 email2, signin::GetTestGaiaIdForEmail(email2));
295 base::RunLoop().RunUntilIdle();
296 info2 = GetValidAccountInfo(info2.email, info2.account_id, "Pat 2",
297 "Pat Foo The Second", kChromiumOrgDomain);
298 signin::UpdateAccountInfoForAccount(identity_test_env()->identity_manager(),
299 info2);
300 base::RunLoop().RunUntilIdle();
301 ASSERT_EQ(1u, storage()->GetNumberOfProfiles());
302
303 // Because due to the complete sign-out, the info about the previous account
304 // got wiped. Thus the same default metrics get recorded again, despite the
305 // second account has a different gaia name and a different account category
306 // than the first one.
307 entry->RecordAccountMetrics();
308 tester.ExpectBucketCount(
309 "Profile.AllAccounts.Names",
310 /*sample=*/profile_metrics::AllAccountsNames::kLikelySingleName,
311 /*expected_count=*/3);
312 tester.ExpectBucketCount(
313 "Profile.AllAccounts.Categories",
314 /*sample=*/profile_metrics::AllAccountsCategories::kSingleCategory,
315 /*expected_count=*/3);
316 tester.ExpectTotalCount("Profile.AllAccounts.Names", /*expected_count=*/3);
317 tester.ExpectTotalCount("Profile.AllAccounts.Categories",
318 /*expected_count=*/3);
319 }
320
TEST_F(GAIAInfoUpdateServiceTest,MultiLoginAndLogOut)321 TEST_F(GAIAInfoUpdateServiceTest, MultiLoginAndLogOut) {
322 // Make two accounts available with both refresh token and cookies.
323 AccountInfo info1 =
324 identity_test_env()->MakeAccountAvailable("pat@example.com");
325 AccountInfo info2 =
326 identity_test_env()->MakeAccountAvailable("pat2@example.com");
327 identity_test_env()->SetCookieAccounts(
328 {{info1.email, info1.gaia}, {info2.email, info2.gaia}});
329 base::RunLoop().RunUntilIdle();
330 info1 = GetValidAccountInfo(info1.email, info1.account_id, "Pat 1",
331 "Pat Foo The First", kNoHostedDomainFound);
332 // Make the second account an enterprise account by setting a hosted domain.
333 info2 = GetValidAccountInfo(info2.email, info2.account_id, "Pat 2",
334 "Pat Foo The Second", kChromiumOrgDomain);
335 signin::UpdateAccountInfoForAccount(identity_test_env()->identity_manager(),
336 info1);
337 signin::UpdateAccountInfoForAccount(identity_test_env()->identity_manager(),
338 info2);
339 base::RunLoop().RunUntilIdle();
340 ASSERT_EQ(1u, storage()->GetNumberOfProfiles());
341 ProfileAttributesEntry* entry = storage()->GetAllProfilesAttributes().front();
342
343 // Test correct histogram recording for all accounts info that has no getters.
344 // The two accounts have both different gaia names and account categories.
345 base::HistogramTester tester;
346 entry->RecordAccountMetrics();
347 tester.ExpectBucketCount(
348 "Profile.AllAccounts.Names",
349 /*sample=*/profile_metrics::AllAccountsNames::kMultipleNamesWithoutSync,
350 /*expected_count=*/1);
351 tester.ExpectBucketCount(
352 "Profile.AllAccounts.Categories",
353 /*sample=*/
354 profile_metrics::AllAccountsCategories::kBothConsumerAndEnterpriseNoSync,
355 /*expected_count=*/1);
356
357 // Log out and record the metric again, sign-out wipes previous info in the
358 // entry so the default values get reported.
359 identity_test_env()->SetCookieAccounts({});
360 entry->RecordAccountMetrics();
361 tester.ExpectBucketCount(
362 "Profile.AllAccounts.Names",
363 /*sample=*/profile_metrics::AllAccountsNames::kLikelySingleName,
364 /*expected_count=*/1);
365 tester.ExpectBucketCount(
366 "Profile.AllAccounts.Categories",
367 /*sample=*/profile_metrics::AllAccountsCategories::kSingleCategory,
368 /*expected_count=*/1);
369 tester.ExpectTotalCount("Profile.AllAccounts.Names", /*expected_count=*/2);
370 tester.ExpectTotalCount("Profile.AllAccounts.Categories",
371 /*expected_count=*/2);
372 }
373 #endif // !defined(ANDROID)
374
TEST_F(GAIAInfoUpdateServiceTest,ClearGaiaInfoOnStartup)375 TEST_F(GAIAInfoUpdateServiceTest, ClearGaiaInfoOnStartup) {
376 // Simulate a state where the profile entry has GAIA related information
377 // when there is not primary account set.
378 ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount(
379 signin::ConsentLevel::kNotRequired));
380 ASSERT_EQ(1u, storage()->GetNumberOfProfiles());
381 ProfileAttributesEntry* entry = storage()->GetAllProfilesAttributes().front();
382 entry->SetGAIAName(base::UTF8ToUTF16("foo"));
383 entry->SetGAIAGivenName(base::UTF8ToUTF16("Pat Foo"));
384 gfx::Image gaia_picture = gfx::test::CreateImage(256, 256);
385 entry->SetGAIAPicture("GAIA_IMAGE_URL_WITH_SIZE", gaia_picture);
386 entry->SetHostedDomain(kNoHostedDomainFound);
387
388 // Verify that creating the GAIAInfoUpdateService resets the GAIA related
389 // profile attributes if the profile no longer has a primary account and that
390 // the profile info cache observer wass notified about profile name and
391 // avatar changes.
392 RecreateGAIAInfoUpdateService();
393
394 EXPECT_TRUE(entry->GetGAIAName().empty());
395 EXPECT_TRUE(entry->GetGAIAGivenName().empty());
396 EXPECT_FALSE(entry->GetGAIAPicture());
397 EXPECT_TRUE(entry->GetHostedDomain().empty());
398 }
399
400 #endif // !defined(OS_CHROMEOS)
401