• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors
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 "components/metrics/demographics/demographic_metrics_provider.h"
6 
7 #include <memory>
8 
9 #include "base/test/metrics/histogram_tester.h"
10 #include "base/test/scoped_feature_list.h"
11 #include "base/test/simple_test_clock.h"
12 #include "base/time/time.h"
13 #include "base/values.h"
14 #include "build/chromeos_buildflags.h"
15 #include "components/metrics/demographics/user_demographics.h"
16 #include "components/metrics/metrics_log_uploader.h"
17 #include "components/sync/base/features.h"
18 #include "components/sync/service/sync_prefs.h"
19 #include "components/sync/test/test_sync_service.h"
20 #include "components/sync_preferences/testing_pref_service_syncable.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h"
24 #include "third_party/metrics_proto/ukm/report.pb.h"
25 
26 namespace metrics {
27 namespace {
28 
29 constexpr int kTestBirthYear = 1983;
30 constexpr UserDemographicsProto::Gender kTestGender =
31     UserDemographicsProto::GENDER_FEMALE;
32 
33 enum TestSyncServiceState {
34   NULL_SYNC_SERVICE,
35   SYNC_FEATURE_NOT_ENABLED,
36   SYNC_FEATURE_ENABLED,
37   SYNC_FEATURE_ENABLED_BUT_PAUSED,
38   SYNC_FEATURE_DISABLED_BUT_PREFERENCES_ENABLED,
39 #if BUILDFLAG(IS_CHROMEOS_ASH)
40   // Represents the user clearing sync data via dashboard. On all platforms
41   // except ChromeOS (Ash), this clears the primary account (which is basically
42   // SYNC_FEATURE_NOT_ENABLED). On ChromeOS Ash, Sync enters a special state.
43   SYNC_FEATURE_DISABLED_ON_CHROMEOS_ASH_VIA_DASHBOARD,
44 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
45 };
46 
47 // Profile client for testing that gets fake Profile information and services.
48 class TestProfileClient : public DemographicMetricsProvider::ProfileClient {
49  public:
50   TestProfileClient(const TestProfileClient&) = delete;
51   TestProfileClient& operator=(const TestProfileClient&) = delete;
52 
53   ~TestProfileClient() override = default;
54 
TestProfileClient(int number_of_profiles,TestSyncServiceState sync_service_state)55   TestProfileClient(int number_of_profiles,
56                     TestSyncServiceState sync_service_state)
57       : number_of_profiles_(number_of_profiles) {
58     RegisterDemographicsLocalStatePrefs(pref_service_.registry());
59     RegisterDemographicsProfilePrefs(pref_service_.registry());
60 
61     switch (sync_service_state) {
62       case NULL_SYNC_SERVICE:
63         break;
64 
65       case SYNC_FEATURE_NOT_ENABLED:
66         sync_service_ = std::make_unique<syncer::TestSyncService>();
67         // Set an arbitrary disable reason to mimic sync feature being unable to
68         // start.
69         sync_service_->SetHasUnrecoverableError(true);
70         break;
71 
72       case SYNC_FEATURE_ENABLED:
73         // TestSyncService by default behaves as everything enabled/active.
74         sync_service_ = std::make_unique<syncer::TestSyncService>();
75 
76         CHECK(sync_service_->GetDisableReasons().empty());
77         CHECK_EQ(syncer::SyncService::TransportState::ACTIVE,
78                  sync_service_->GetTransportState());
79         break;
80 
81       case SYNC_FEATURE_ENABLED_BUT_PAUSED:
82         sync_service_ = std::make_unique<syncer::TestSyncService>();
83         // Mimic the user signing out from content are (sync paused).
84         sync_service_->SetPersistentAuthError();
85 
86         CHECK(sync_service_->GetDisableReasons().empty());
87         CHECK_EQ(syncer::SyncService::TransportState::PAUSED,
88                  sync_service_->GetTransportState());
89         break;
90 
91       case SYNC_FEATURE_DISABLED_BUT_PREFERENCES_ENABLED:
92         sync_service_ = std::make_unique<syncer::TestSyncService>();
93         sync_service_->SetSignedIn(signin::ConsentLevel::kSignin);
94         CHECK(sync_service_->GetUserSettings()->GetSelectedTypes().Has(
95             syncer::UserSelectableType::kPreferences));
96         CHECK(!sync_service_->IsSyncFeatureEnabled());
97         CHECK(sync_service_->GetDisableReasons().empty());
98         CHECK_EQ(syncer::SyncService::TransportState::ACTIVE,
99                  sync_service_->GetTransportState());
100         break;
101 
102 #if BUILDFLAG(IS_CHROMEOS_ASH)
103       case SYNC_FEATURE_DISABLED_ON_CHROMEOS_ASH_VIA_DASHBOARD:
104         sync_service_ = std::make_unique<syncer::TestSyncService>();
105         sync_service_->GetUserSettings()->SetSyncFeatureDisabledViaDashboard(
106             true);
107 
108         // On ChromeOS Ash, IsInitialSyncFeatureSetupComplete always returns
109         // true but IsSyncFeatureEnabled() stays false because the user needs to
110         // manually resume sync the feature.
111         CHECK(sync_service_->GetUserSettings()
112                   ->IsInitialSyncFeatureSetupComplete());
113         CHECK(!sync_service_->IsSyncFeatureEnabled());
114         break;
115 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
116     }
117   }
118 
GetNumberOfProfilesOnDisk()119   int GetNumberOfProfilesOnDisk() override { return number_of_profiles_; }
120 
GetSyncService()121   syncer::SyncService* GetSyncService() override { return sync_service_.get(); }
122 
GetLocalState()123   PrefService* GetLocalState() override { return &pref_service_; }
124 
GetProfilePrefs()125   PrefService* GetProfilePrefs() override { return &pref_service_; }
126 
GetNetworkTime() const127   base::Time GetNetworkTime() const override {
128     base::Time time;
129     auto result = base::Time::FromString("17 Jun 2019 00:00:00 UDT", &time);
130     DCHECK(result);
131     return time;
132   }
133 
SetDemographicsInPrefs(int birth_year,metrics::UserDemographicsProto_Gender gender)134   void SetDemographicsInPrefs(int birth_year,
135                               metrics::UserDemographicsProto_Gender gender) {
136     base::Value::Dict dict;
137     dict.Set(kSyncDemographicsBirthYearPath, birth_year);
138     dict.Set(kSyncDemographicsGenderPath, static_cast<int>(gender));
139     pref_service_.SetDict(kSyncDemographicsPrefName, std::move(dict));
140   }
141 
142  private:
143   sync_preferences::TestingPrefServiceSyncable pref_service_;
144   std::unique_ptr<syncer::TestSyncService> sync_service_;
145   const int number_of_profiles_;
146   base::SimpleTestClock clock_;
147 };
148 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_FeatureEnabled)149 TEST(DemographicMetricsProviderTest,
150      ProvideSyncedUserNoisedBirthYearAndGender_FeatureEnabled) {
151   base::HistogramTester histogram;
152 
153   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
154                                                     SYNC_FEATURE_ENABLED);
155   client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
156 
157   // Set birth year noise offset to not have it randomized.
158   const int kBirthYearOffset = 3;
159   client->GetLocalState()->SetInteger(kUserDemographicsBirthYearOffsetPrefName,
160                                       kBirthYearOffset);
161 
162   // Run demographics provider.
163   DemographicMetricsProvider provider(
164       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
165   ChromeUserMetricsExtension uma_proto;
166   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
167 
168   // Verify provided demographics.
169   EXPECT_EQ(kTestBirthYear + kBirthYearOffset,
170             uma_proto.user_demographics().birth_year());
171   EXPECT_EQ(kTestGender, uma_proto.user_demographics().gender());
172 
173   // Verify histograms.
174   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
175                                UserDemographicsStatus::kSuccess, 1);
176 }
177 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_NoSyncService)178 TEST(DemographicMetricsProviderTest,
179      ProvideSyncedUserNoisedBirthYearAndGender_NoSyncService) {
180   base::HistogramTester histogram;
181 
182   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
183                                                     NULL_SYNC_SERVICE);
184 
185   // Run demographics provider.
186   DemographicMetricsProvider provider(
187       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
188   ChromeUserMetricsExtension uma_proto;
189   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
190 
191   // Expect the proto fields to be not set and left to default.
192   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
193   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
194 
195   // Verify histograms.
196   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
197                                UserDemographicsStatus::kNoSyncService, 1);
198 }
199 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_SyncEnabledButPaused)200 TEST(DemographicMetricsProviderTest,
201      ProvideSyncedUserNoisedBirthYearAndGender_SyncEnabledButPaused) {
202   base::HistogramTester histogram;
203 
204   auto client = std::make_unique<TestProfileClient>(
205       /*number_of_profiles=*/1, SYNC_FEATURE_ENABLED_BUT_PAUSED);
206 
207   // Run demographics provider.
208   DemographicMetricsProvider provider(
209       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
210   ChromeUserMetricsExtension uma_proto;
211   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
212 
213   // Expect the proto fields to be not set and left to default.
214   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
215   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
216 
217   // Verify histograms.
218   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
219                                UserDemographicsStatus::kSyncNotEnabled, 1);
220 }
221 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_SyncFeatureDisabledButPreferencesEnabled_WithSyncToSignin)222 TEST(
223     DemographicMetricsProviderTest,
224     ProvideSyncedUserNoisedBirthYearAndGender_SyncFeatureDisabledButPreferencesEnabled_WithSyncToSignin) {
225   base::test::ScopedFeatureList sync_to_signin_enabled;
226   sync_to_signin_enabled.InitAndEnableFeature(
227       syncer::kReplaceSyncPromosWithSignInPromos);
228 
229   base::HistogramTester histogram;
230 
231   auto client = std::make_unique<TestProfileClient>(
232       /*number_of_profiles=*/1, SYNC_FEATURE_DISABLED_BUT_PREFERENCES_ENABLED);
233   client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
234 
235   // Set birth year noise offset to not have it randomized.
236   const int kBirthYearOffset = 3;
237   client->GetLocalState()->SetInteger(kUserDemographicsBirthYearOffsetPrefName,
238                                       kBirthYearOffset);
239 
240   // Run demographics provider.
241   DemographicMetricsProvider provider(
242       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
243   ChromeUserMetricsExtension uma_proto;
244   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
245 
246   // Verify provided demographics.
247   EXPECT_EQ(kTestBirthYear + kBirthYearOffset,
248             uma_proto.user_demographics().birth_year());
249   EXPECT_EQ(kTestGender, uma_proto.user_demographics().gender());
250 
251   // Verify histograms: Demographics should be provided.
252   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
253                                UserDemographicsStatus::kSuccess, 1);
254 }
255 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_SyncFeatureDisabledButPreferencesEnabled_WithoutSyncToSignin)256 TEST(
257     DemographicMetricsProviderTest,
258     ProvideSyncedUserNoisedBirthYearAndGender_SyncFeatureDisabledButPreferencesEnabled_WithoutSyncToSignin) {
259   base::test::ScopedFeatureList sync_to_signin_disabled;
260   sync_to_signin_disabled.InitAndDisableFeature(
261       syncer::kReplaceSyncPromosWithSignInPromos);
262 
263   base::HistogramTester histogram;
264 
265   auto client = std::make_unique<TestProfileClient>(
266       /*number_of_profiles=*/1, SYNC_FEATURE_DISABLED_BUT_PREFERENCES_ENABLED);
267   client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
268 
269   // Set birth year noise offset to not have it randomized.
270   const int kBirthYearOffset = 3;
271   client->GetLocalState()->SetInteger(kUserDemographicsBirthYearOffsetPrefName,
272                                       kBirthYearOffset);
273 
274   // Run demographics provider.
275   DemographicMetricsProvider provider(
276       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
277   ChromeUserMetricsExtension uma_proto;
278   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
279 
280   // Expect the proto fields to be not set and left to default.
281   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
282   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
283 
284   // Verify histograms: Demographics should NOT be provided.
285   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
286                                UserDemographicsStatus::kSyncNotEnabled, 1);
287 }
288 
289 #if BUILDFLAG(IS_CHROMEOS_ASH)
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_SyncFeatureDisabledOnChromeOsAshViaSyncDashboard)290 TEST(
291     DemographicMetricsProviderTest,
292     ProvideSyncedUserNoisedBirthYearAndGender_SyncFeatureDisabledOnChromeOsAshViaSyncDashboard) {
293   base::HistogramTester histogram;
294 
295   auto client = std::make_unique<TestProfileClient>(
296       /*number_of_profiles=*/1,
297       SYNC_FEATURE_DISABLED_ON_CHROMEOS_ASH_VIA_DASHBOARD);
298 
299   // Run demographics provider.
300   DemographicMetricsProvider provider(
301       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
302   ChromeUserMetricsExtension uma_proto;
303   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
304 
305   // Expect the proto fields to be not set and left to default.
306   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
307   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
308 
309   // Verify histograms.
310   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
311                                UserDemographicsStatus::kSyncNotEnabled, 1);
312 }
313 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
314 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_SyncNotEnabled)315 TEST(DemographicMetricsProviderTest,
316      ProvideSyncedUserNoisedBirthYearAndGender_SyncNotEnabled) {
317   base::HistogramTester histogram;
318 
319   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
320                                                     SYNC_FEATURE_NOT_ENABLED);
321 
322   // Run demographics provider.
323   DemographicMetricsProvider provider(
324       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
325   ChromeUserMetricsExtension uma_proto;
326   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
327 
328   // Expect the proto fields to be not set and left to default.
329   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
330   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
331 
332   // Verify histograms.
333   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
334                                UserDemographicsStatus::kSyncNotEnabled, 1);
335 }
336 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_FeatureDisabled)337 TEST(DemographicMetricsProviderTest,
338      ProvideSyncedUserNoisedBirthYearAndGender_FeatureDisabled) {
339   // Disable demographics reporting feature.
340   base::test::ScopedFeatureList local_feature;
341   local_feature.InitAndDisableFeature(kDemographicMetricsReporting);
342 
343   base::HistogramTester histogram;
344 
345   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
346                                                     SYNC_FEATURE_ENABLED);
347   client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
348 
349   // Run demographics provider.
350   DemographicMetricsProvider provider(
351       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
352   ChromeUserMetricsExtension uma_proto;
353   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
354 
355   // Expect that the UMA proto is untouched.
356   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
357   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
358 
359   // Verify that there are no histograms for user demographics.
360   histogram.ExpectTotalCount("UMA.UserDemographics.Status", 0);
361 }
362 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_NotExactlyOneProfile)363 TEST(DemographicMetricsProviderTest,
364      ProvideSyncedUserNoisedBirthYearAndGender_NotExactlyOneProfile) {
365   base::HistogramTester histogram;
366 
367   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/2,
368                                                     SYNC_FEATURE_ENABLED);
369   client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
370 
371   // Run demographics provider with not exactly one Profile on disk.
372   DemographicMetricsProvider provider(
373       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
374   ChromeUserMetricsExtension uma_proto;
375   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
376 
377 #if !BUILDFLAG(IS_CHROMEOS_ASH)
378   // Expect that the UMA proto is untouched.
379   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
380   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
381 
382   // Verify histograms.
383   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
384                                UserDemographicsStatus::kMoreThanOneProfile, 1);
385 #else
386   // On ChromeOS, we have a profile selection strategy, so expect UMA reporting
387   // to work.
388   EXPECT_TRUE(uma_proto.user_demographics().has_birth_year());
389   EXPECT_TRUE(uma_proto.user_demographics().has_gender());
390 
391   // Verify histograms.
392   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
393                                UserDemographicsStatus::kSuccess, 1);
394 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
395 }
396 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_NoUserDemographics)397 TEST(DemographicMetricsProviderTest,
398      ProvideSyncedUserNoisedBirthYearAndGender_NoUserDemographics) {
399   base::HistogramTester histogram;
400 
401   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
402                                                     SYNC_FEATURE_ENABLED);
403   // Set some ineligible values to prefs.
404   client->SetDemographicsInPrefs(/*birth_year=*/-17,
405                                  UserDemographicsProto::GENDER_UNKNOWN);
406 
407   // Run demographics provider with a ProfileClient that does not provide
408   // demographics because of some error.
409   DemographicMetricsProvider provider(
410       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
411   ChromeUserMetricsExtension uma_proto;
412   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
413 
414   // Expect that the UMA proto is untouched.
415   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
416   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
417 
418   // Verify that there are no histograms for user demographics.
419   histogram.ExpectUniqueSample(
420       "UMA.UserDemographics.Status",
421       UserDemographicsStatus::kIneligibleDemographicsData, 1);
422 }
423 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGenderToUkmReport)424 TEST(DemographicMetricsProviderTest,
425      ProvideSyncedUserNoisedBirthYearAndGenderToUkmReport) {
426   base::HistogramTester histogram;
427 
428   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
429                                                     SYNC_FEATURE_ENABLED);
430   client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
431 
432   // Set birth year noise offset to not have it randomized.
433   const int kBirthYearOffset = 3;
434   client->GetLocalState()->SetInteger(kUserDemographicsBirthYearOffsetPrefName,
435                                       kBirthYearOffset);
436 
437   // Run demographics provider.
438   DemographicMetricsProvider provider(
439       std::move(client), MetricsLogUploader::MetricServiceType::UKM);
440   ukm::Report report;
441   provider.ProvideSyncedUserNoisedBirthYearAndGenderToReport(&report);
442 
443   // Verify provided demographics.
444   EXPECT_EQ(kTestBirthYear + kBirthYearOffset,
445             report.user_demographics().birth_year());
446   EXPECT_EQ(kTestGender, report.user_demographics().gender());
447 }
448 
449 }  // namespace
450 }  // namespace metrics
451