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