• 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/sync_prefs.h"
18 #include "components/sync/test/test_sync_service.h"
19 #include "components/sync_preferences/testing_pref_service_syncable.h"
20 #include "google_apis/gaia/google_service_auth_error.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   // Represents the user clearing sync data via dashboard. On all platforms
39   // except ChromeOS (Ash), this clears the primary account (which is basically
40   // SYNC_FEATURE_NOT_ENABLED). On ChromeOS Ash, Sync enters a special state.
41   SYNC_FEATURE_DISABLED_ON_CHROMEOS_ASH_VIA_DASHBOARD,
42 };
43 
44 // Profile client for testing that gets fake Profile information and services.
45 class TestProfileClient : public DemographicMetricsProvider::ProfileClient {
46  public:
47   TestProfileClient(const TestProfileClient&) = delete;
48   TestProfileClient& operator=(const TestProfileClient&) = delete;
49 
50   ~TestProfileClient() override = default;
51 
TestProfileClient(int number_of_profiles,TestSyncServiceState sync_service_state)52   TestProfileClient(int number_of_profiles,
53                     TestSyncServiceState sync_service_state)
54       : number_of_profiles_(number_of_profiles) {
55     RegisterDemographicsLocalStatePrefs(pref_service_.registry());
56     RegisterDemographicsProfilePrefs(pref_service_.registry());
57 
58     switch (sync_service_state) {
59       case NULL_SYNC_SERVICE:
60         break;
61 
62       case SYNC_FEATURE_NOT_ENABLED:
63         sync_service_ = std::make_unique<syncer::TestSyncService>();
64         // Set an arbitrary disable reason to mimic sync feature being unable to
65         // start.
66         sync_service_->SetDisableReasons(
67             syncer::SyncService::DISABLE_REASON_UNRECOVERABLE_ERROR);
68         break;
69 
70       case SYNC_FEATURE_ENABLED:
71         // TestSyncService by default behaves as everything enabled/active.
72         sync_service_ = std::make_unique<syncer::TestSyncService>();
73 
74         CHECK(sync_service_->GetDisableReasons().Empty());
75         CHECK_EQ(syncer::SyncService::TransportState::ACTIVE,
76                  sync_service_->GetTransportState());
77         break;
78 
79       case SYNC_FEATURE_ENABLED_BUT_PAUSED:
80         sync_service_ = std::make_unique<syncer::TestSyncService>();
81         // Mimic the user signing out from content are (sync paused).
82         sync_service_->SetPersistentAuthError();
83 
84         CHECK(sync_service_->GetDisableReasons().Empty());
85         CHECK_EQ(syncer::SyncService::TransportState::PAUSED,
86                  sync_service_->GetTransportState());
87         break;
88 
89       case SYNC_FEATURE_DISABLED_ON_CHROMEOS_ASH_VIA_DASHBOARD:
90         sync_service_ = std::make_unique<syncer::TestSyncService>();
91         sync_service_->SetDisableReasons(syncer::SyncService::DisableReasonSet(
92             syncer::SyncService::DISABLE_REASON_USER_CHOICE));
93 
94         // On ChromeOS Ash, IsFirstSetupComplete gets cleared temporarily but
95         // immediately afterwards, it gets set again with
96         // ENGINE_INITIALIZED_WITH_AUTO_START. And yet, IsSyncFeatureEnabled()
97         // stays false because the user needs to manually resume sync the
98         // feature.
99         CHECK(sync_service_->GetUserSettings()->IsFirstSetupComplete());
100         CHECK(!sync_service_->IsSyncFeatureEnabled());
101         break;
102     }
103   }
104 
GetNumberOfProfilesOnDisk()105   int GetNumberOfProfilesOnDisk() override { return number_of_profiles_; }
106 
GetSyncService()107   syncer::SyncService* GetSyncService() override { return sync_service_.get(); }
108 
GetLocalState()109   PrefService* GetLocalState() override { return &pref_service_; }
110 
GetProfilePrefs()111   PrefService* GetProfilePrefs() override { return &pref_service_; }
112 
GetNetworkTime() const113   base::Time GetNetworkTime() const override {
114     base::Time time;
115     auto result = base::Time::FromString("17 Jun 2019 00:00:00 UDT", &time);
116     DCHECK(result);
117     return time;
118   }
119 
SetDemographicsInPrefs(int birth_year,metrics::UserDemographicsProto_Gender gender)120   void SetDemographicsInPrefs(int birth_year,
121                               metrics::UserDemographicsProto_Gender gender) {
122     base::Value::Dict dict;
123     dict.Set(kSyncDemographicsBirthYearPath, birth_year);
124     dict.Set(kSyncDemographicsGenderPath, static_cast<int>(gender));
125     pref_service_.SetDict(kSyncDemographicsPrefName, std::move(dict));
126   }
127 
128  private:
129   sync_preferences::TestingPrefServiceSyncable pref_service_;
130   std::unique_ptr<syncer::TestSyncService> sync_service_;
131   const int number_of_profiles_;
132   base::SimpleTestClock clock_;
133 };
134 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_FeatureEnabled)135 TEST(DemographicMetricsProviderTest,
136      ProvideSyncedUserNoisedBirthYearAndGender_FeatureEnabled) {
137   base::HistogramTester histogram;
138 
139   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
140                                                     SYNC_FEATURE_ENABLED);
141   client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
142 
143   // Set birth year noise offset to not have it randomized.
144   const int kBirthYearOffset = 3;
145   client->GetLocalState()->SetInteger(kUserDemographicsBirthYearOffsetPrefName,
146                                       kBirthYearOffset);
147 
148   // Run demographics provider.
149   DemographicMetricsProvider provider(
150       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
151   ChromeUserMetricsExtension uma_proto;
152   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
153 
154   // Verify provided demographics.
155   EXPECT_EQ(kTestBirthYear + kBirthYearOffset,
156             uma_proto.user_demographics().birth_year());
157   EXPECT_EQ(kTestGender, uma_proto.user_demographics().gender());
158 
159   // Verify histograms.
160   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
161                                UserDemographicsStatus::kSuccess, 1);
162 }
163 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_NoSyncService)164 TEST(DemographicMetricsProviderTest,
165      ProvideSyncedUserNoisedBirthYearAndGender_NoSyncService) {
166   base::HistogramTester histogram;
167 
168   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
169                                                     NULL_SYNC_SERVICE);
170 
171   // Run demographics provider.
172   DemographicMetricsProvider provider(
173       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
174   ChromeUserMetricsExtension uma_proto;
175   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
176 
177   // Expect the proto fields to be not set and left to default.
178   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
179   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
180 
181   // Verify histograms.
182   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
183                                UserDemographicsStatus::kNoSyncService, 1);
184 }
185 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_SyncEnabledButPaused)186 TEST(DemographicMetricsProviderTest,
187      ProvideSyncedUserNoisedBirthYearAndGender_SyncEnabledButPaused) {
188   base::HistogramTester histogram;
189 
190   auto client = std::make_unique<TestProfileClient>(
191       /*number_of_profiles=*/1, SYNC_FEATURE_ENABLED_BUT_PAUSED);
192 
193   // Run demographics provider.
194   DemographicMetricsProvider provider(
195       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
196   ChromeUserMetricsExtension uma_proto;
197   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
198 
199   // Expect the proto fields to be not set and left to default.
200   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
201   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
202 
203   // Verify histograms.
204   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
205                                UserDemographicsStatus::kSyncNotEnabled, 1);
206 }
207 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_SyncFeatureDisabledOnChromeOsAshViaSyncDashboard)208 TEST(
209     DemographicMetricsProviderTest,
210     ProvideSyncedUserNoisedBirthYearAndGender_SyncFeatureDisabledOnChromeOsAshViaSyncDashboard) {
211   base::HistogramTester histogram;
212 
213   auto client = std::make_unique<TestProfileClient>(
214       /*number_of_profiles=*/1,
215       SYNC_FEATURE_DISABLED_ON_CHROMEOS_ASH_VIA_DASHBOARD);
216 
217   // Run demographics provider.
218   DemographicMetricsProvider provider(
219       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
220   ChromeUserMetricsExtension uma_proto;
221   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
222 
223   // Expect the proto fields to be not set and left to default.
224   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
225   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
226 
227   // Verify histograms.
228   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
229                                UserDemographicsStatus::kSyncNotEnabled, 1);
230 }
231 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_SyncNotEnabled)232 TEST(DemographicMetricsProviderTest,
233      ProvideSyncedUserNoisedBirthYearAndGender_SyncNotEnabled) {
234   base::HistogramTester histogram;
235 
236   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
237                                                     SYNC_FEATURE_NOT_ENABLED);
238 
239   // Run demographics provider.
240   DemographicMetricsProvider provider(
241       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
242   ChromeUserMetricsExtension uma_proto;
243   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
244 
245   // Expect the proto fields to be not set and left to default.
246   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
247   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
248 
249   // Verify histograms.
250   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
251                                UserDemographicsStatus::kSyncNotEnabled, 1);
252 }
253 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_FeatureDisabled)254 TEST(DemographicMetricsProviderTest,
255      ProvideSyncedUserNoisedBirthYearAndGender_FeatureDisabled) {
256   // Disable demographics reporting feature.
257   base::test::ScopedFeatureList local_feature;
258   local_feature.InitAndDisableFeature(kDemographicMetricsReporting);
259 
260   base::HistogramTester histogram;
261 
262   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
263                                                     SYNC_FEATURE_ENABLED);
264   client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
265 
266   // Run demographics provider.
267   DemographicMetricsProvider provider(
268       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
269   ChromeUserMetricsExtension uma_proto;
270   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
271 
272   // Expect that the UMA proto is untouched.
273   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
274   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
275 
276   // Verify that there are no histograms for user demographics.
277   histogram.ExpectTotalCount("UMA.UserDemographics.Status", 0);
278 }
279 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_NotExactlyOneProfile)280 TEST(DemographicMetricsProviderTest,
281      ProvideSyncedUserNoisedBirthYearAndGender_NotExactlyOneProfile) {
282   base::HistogramTester histogram;
283 
284   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/2,
285                                                     SYNC_FEATURE_ENABLED);
286   client->SetDemographicsInPrefs(kTestBirthYear, kTestGender);
287 
288   // Run demographics provider with not exactly one Profile on disk.
289   DemographicMetricsProvider provider(
290       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
291   ChromeUserMetricsExtension uma_proto;
292   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
293 
294 #if !BUILDFLAG(IS_CHROMEOS_ASH)
295   // Expect that the UMA proto is untouched.
296   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
297   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
298 
299   // Verify histograms.
300   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
301                                UserDemographicsStatus::kMoreThanOneProfile, 1);
302 #else
303   // On ChromeOS, we have a profile selection strategy, so expect UMA reporting
304   // to work.
305   EXPECT_TRUE(uma_proto.user_demographics().has_birth_year());
306   EXPECT_TRUE(uma_proto.user_demographics().has_gender());
307 
308   // Verify histograms.
309   histogram.ExpectUniqueSample("UMA.UserDemographics.Status",
310                                UserDemographicsStatus::kSuccess, 1);
311 #endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
312 }
313 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGender_NoUserDemographics)314 TEST(DemographicMetricsProviderTest,
315      ProvideSyncedUserNoisedBirthYearAndGender_NoUserDemographics) {
316   base::HistogramTester histogram;
317 
318   auto client = std::make_unique<TestProfileClient>(/*number_of_profiles=*/1,
319                                                     SYNC_FEATURE_ENABLED);
320   // Set some ineligible values to prefs.
321   client->SetDemographicsInPrefs(/*birth_year=*/-17,
322                                  UserDemographicsProto::GENDER_UNKNOWN);
323 
324   // Run demographics provider with a ProfileClient that does not provide
325   // demographics because of some error.
326   DemographicMetricsProvider provider(
327       std::move(client), MetricsLogUploader::MetricServiceType::UMA);
328   ChromeUserMetricsExtension uma_proto;
329   provider.ProvideSyncedUserNoisedBirthYearAndGender(&uma_proto);
330 
331   // Expect that the UMA proto is untouched.
332   EXPECT_FALSE(uma_proto.user_demographics().has_birth_year());
333   EXPECT_FALSE(uma_proto.user_demographics().has_gender());
334 
335   // Verify that there are no histograms for user demographics.
336   histogram.ExpectUniqueSample(
337       "UMA.UserDemographics.Status",
338       UserDemographicsStatus::kIneligibleDemographicsData, 1);
339 }
340 
TEST(DemographicMetricsProviderTest,ProvideSyncedUserNoisedBirthYearAndGenderToUkmReport)341 TEST(DemographicMetricsProviderTest,
342      ProvideSyncedUserNoisedBirthYearAndGenderToUkmReport) {
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   // Set birth year noise offset to not have it randomized.
350   const int kBirthYearOffset = 3;
351   client->GetLocalState()->SetInteger(kUserDemographicsBirthYearOffsetPrefName,
352                                       kBirthYearOffset);
353 
354   // Run demographics provider.
355   DemographicMetricsProvider provider(
356       std::move(client), MetricsLogUploader::MetricServiceType::UKM);
357   ukm::Report report;
358   provider.ProvideSyncedUserNoisedBirthYearAndGenderToReport(&report);
359 
360   // Verify provided demographics.
361   EXPECT_EQ(kTestBirthYear + kBirthYearOffset,
362             report.user_demographics().birth_year());
363   EXPECT_EQ(kTestGender, report.user_demographics().gender());
364 
365   // Verify histograms.
366   histogram.ExpectUniqueSample("UKM.UserDemographics.Status",
367                                UserDemographicsStatus::kSuccess, 1);
368 }
369 
370 }  // namespace
371 }  // namespace metrics
372