1 // Copyright 2019 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 "components/metrics/demographics/user_demographics.h"
6
7 #include <utility>
8
9 #include "components/sync_preferences/testing_pref_service_syncable.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 #include "third_party/metrics_proto/user_demographics.pb.h"
12
13 namespace metrics {
14
15 namespace {
16
17 // Gets the now time used for testing demographics.
GetNowTime()18 base::Time GetNowTime() {
19 constexpr char kNowTimeInStringFormat[] = "22 Jul 2019 00:00:00 UDT";
20
21 base::Time now;
22 bool result = base::Time::FromString(kNowTimeInStringFormat, &now);
23 DCHECK(result);
24 return now;
25 }
26
27 } // namespace
28
TEST(UserDemographicsTest,UserDemographicsResult_ForValue)29 TEST(UserDemographicsTest, UserDemographicsResult_ForValue) {
30 int user_birth_year = 1982;
31 UserDemographicsProto_Gender user_gender = UserDemographicsProto::GENDER_MALE;
32
33 UserDemographics user_demographics;
34 user_demographics.birth_year = user_birth_year;
35 user_demographics.gender = user_gender;
36 UserDemographicsResult user_demographics_result =
37 UserDemographicsResult::ForValue(std::move(user_demographics));
38
39 EXPECT_TRUE(user_demographics_result.IsSuccess());
40 EXPECT_EQ(UserDemographicsStatus::kSuccess,
41 user_demographics_result.status());
42 EXPECT_EQ(user_birth_year, user_demographics_result.value().birth_year);
43 EXPECT_EQ(user_gender, user_demographics_result.value().gender);
44 }
45
TEST(UserDemographicsTest,UserDemographicsResult_ForStatus)46 TEST(UserDemographicsTest, UserDemographicsResult_ForStatus) {
47 UserDemographicsStatus error_status =
48 UserDemographicsStatus::kIneligibleDemographicsData;
49 UserDemographicsResult user_demographics_result =
50 UserDemographicsResult::ForStatus(error_status);
51
52 EXPECT_FALSE(user_demographics_result.IsSuccess());
53 EXPECT_EQ(error_status, user_demographics_result.status());
54 }
55
56 class UserDemographicsPrefsTest : public testing::Test {
57 protected:
UserDemographicsPrefsTest()58 UserDemographicsPrefsTest() {
59 RegisterDemographicsProfilePrefs(pref_service_.registry());
60 }
61
SetDemographics(int birth_year,UserDemographicsProto::Gender gender)62 void SetDemographics(int birth_year, UserDemographicsProto::Gender gender) {
63 base::DictionaryValue dict;
64 dict.SetIntPath(kSyncDemographicsBirthYearPath, birth_year);
65 dict.SetIntPath(kSyncDemographicsGenderPath, static_cast<int>(gender));
66 pref_service_.Set(kSyncDemographicsPrefName, dict);
67 }
68
69 sync_preferences::TestingPrefServiceSyncable pref_service_;
70 };
71
TEST_F(UserDemographicsPrefsTest,ReadDemographicsWithRandomOffset)72 TEST_F(UserDemographicsPrefsTest, ReadDemographicsWithRandomOffset) {
73 int user_demographics_birth_year = 1983;
74 UserDemographicsProto_Gender user_demographics_gender =
75 UserDemographicsProto::GENDER_MALE;
76
77 // Set user demographic prefs.
78 SetDemographics(user_demographics_birth_year, user_demographics_gender);
79
80 int provided_birth_year;
81 {
82 UserDemographicsResult demographics_result =
83 GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
84 ASSERT_TRUE(demographics_result.IsSuccess());
85 EXPECT_EQ(user_demographics_gender, demographics_result.value().gender);
86 // Verify that the provided birth year is within the range.
87 provided_birth_year = demographics_result.value().birth_year;
88 int delta = provided_birth_year - user_demographics_birth_year;
89 EXPECT_LE(delta, kUserDemographicsBirthYearNoiseOffsetRange);
90 EXPECT_GE(delta, -kUserDemographicsBirthYearNoiseOffsetRange);
91 }
92
93 // Verify that the offset is cached and that the randomized birth year is the
94 // same when doing more that one read of the birth year.
95 {
96 ASSERT_TRUE(
97 pref_service_.HasPrefPath(kSyncDemographicsBirthYearOffsetPrefName));
98 UserDemographicsResult demographics_result =
99 GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
100 ASSERT_TRUE(demographics_result.IsSuccess());
101 EXPECT_EQ(provided_birth_year, demographics_result.value().birth_year);
102 }
103 }
104
TEST_F(UserDemographicsPrefsTest,ReadAndClearUserDemographicPreferences)105 TEST_F(UserDemographicsPrefsTest, ReadAndClearUserDemographicPreferences) {
106 // Verify demographic prefs are not available when there is nothing set.
107 ASSERT_FALSE(
108 GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_)
109 .IsSuccess());
110
111 // Set demographic prefs directly from the pref service interface because
112 // demographic prefs will only be set on the server-side. The SyncPrefs
113 // interface cannot set demographic prefs.
114 SetDemographics(1983, UserDemographicsProto::GENDER_FEMALE);
115
116 // Set birth year noise offset to not have it randomized.
117 pref_service_.SetInteger(kSyncDemographicsBirthYearOffsetPrefName, 2);
118
119 // Verify that demographics are provided.
120 {
121 UserDemographicsResult demographics_result =
122 GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
123 ASSERT_TRUE(demographics_result.IsSuccess());
124 }
125
126 ClearDemographicsPrefs(&pref_service_);
127
128 // Verify that demographics are not provided and kSyncDemographics is cleared.
129 // Note that we retain kSyncDemographicsBirthYearOffset. If the user resumes
130 // syncing, causing these prefs to be recreated, we don't want them to start
131 // reporting a different randomized birth year as this could narrow down or
132 // even reveal their true birth year.
133 EXPECT_FALSE(
134 GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_)
135 .IsSuccess());
136 EXPECT_FALSE(pref_service_.HasPrefPath(kSyncDemographicsPrefName));
137 EXPECT_TRUE(
138 pref_service_.HasPrefPath(kSyncDemographicsBirthYearOffsetPrefName));
139 }
140
141 struct DemographicsTestParam {
142 // Birth year of the user.
143 int birth_year = kUserDemographicsBirthYearDefaultValue;
144
145 // Non-random offset to apply to |birth_year| as noise.
146 int birth_year_offset = kUserDemographicsBirthYearNoiseOffsetDefaultValue;
147
148 // Gender of the user.
149 UserDemographicsProto_Gender gender = kUserDemographicGenderDefaultEnumValue;
150
151 // Status of the retrieval of demographics.
152 UserDemographicsStatus status = UserDemographicsStatus::kMaxValue;
153 };
154
155 // Extend UserDemographicsPrefsTest fixture for parameterized tests on
156 // demographics.
157 class UserDemographicsPrefsTestWithParam
158 : public UserDemographicsPrefsTest,
159 public testing::WithParamInterface<DemographicsTestParam> {};
160
TEST_P(UserDemographicsPrefsTestWithParam,ReadDemographics_OffsetIsNotRandom)161 TEST_P(UserDemographicsPrefsTestWithParam, ReadDemographics_OffsetIsNotRandom) {
162 DemographicsTestParam param = GetParam();
163
164 // Set user demographic prefs.
165 SetDemographics(param.birth_year, param.gender);
166
167 // Set birth year noise offset to not have it randomized.
168 pref_service_.SetInteger(kSyncDemographicsBirthYearOffsetPrefName,
169 param.birth_year_offset);
170
171 // Verify provided demographics for the different parameterized test cases.
172 UserDemographicsResult demographics_result =
173 GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
174 if (param.status == UserDemographicsStatus::kSuccess) {
175 ASSERT_TRUE(demographics_result.IsSuccess());
176 EXPECT_EQ(param.birth_year + param.birth_year_offset,
177 demographics_result.value().birth_year);
178 EXPECT_EQ(param.gender, demographics_result.value().gender);
179 } else {
180 ASSERT_FALSE(demographics_result.IsSuccess());
181 EXPECT_EQ(param.status, demographics_result.status());
182 }
183 }
184
185 // Test suite composed of different test cases of getting user demographics.
186 // The now time in each test case is "22 Jul 2019 00:00:00 UDT" which falls into
187 // the year bucket of 2018. Users need at most a |birth_year| +
188 // |birth_year_offset| of 1998 to be able to provide demographics.
189 INSTANTIATE_TEST_SUITE_P(
190 All,
191 UserDemographicsPrefsTestWithParam,
192 ::testing::Values(
193 // Test where birth year should not be provided because |birth_year| + 2
194 // > 1998.
195 DemographicsTestParam{
196 /*birth_year=*/1997,
197 /*birth_year_offset=*/2,
198 /*gender=*/UserDemographicsProto::GENDER_FEMALE,
199 /*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
200 // Test where birth year should not be provided because |birth_year| - 2
201 // > 1998.
202 DemographicsTestParam{
203 /*birth_year=*/2001,
204 /*birth_year_offset=*/-2,
205 /*gender=*/UserDemographicsProto::GENDER_FEMALE,
206 /*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
207 // Test where birth year should not be provided because age of user is
208 // |kUserDemographicsMaxAge| + 1, which is over the max age.
209 DemographicsTestParam{
210 /*birth_year=*/1933,
211 /*birth_year_offset=*/0,
212 /*gender=*/UserDemographicsProto::GENDER_FEMALE,
213 /*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
214 // Test where gender should not be provided because it has a low
215 // population that can have their privacy compromised because of high
216 // entropy.
217 DemographicsTestParam{
218 /*birth_year=*/1986,
219 /*birth_year_offset=*/0,
220 /*gender=*/UserDemographicsProto::GENDER_CUSTOM_OR_OTHER,
221 /*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
222 // Test where birth year can be provided because |birth_year| + 2 ==
223 // 1998.
224 DemographicsTestParam{/*birth_year=*/1996,
225 /*birth_year_offset=*/2,
226 /*gender=*/UserDemographicsProto::GENDER_FEMALE,
227 /*status=*/UserDemographicsStatus::kSuccess},
228 // Test where birth year can be provided because |birth_year| - 2 ==
229 // 1998.
230 DemographicsTestParam{/*birth_year=*/2000,
231 /*birth_year_offset=*/-2,
232 /*gender=*/UserDemographicsProto::GENDER_MALE,
233 /*status=*/UserDemographicsStatus::kSuccess},
234 // Test where birth year can be provided because |birth_year| + 2 <
235 // 1998.
236 DemographicsTestParam{/*birth_year=*/1995,
237 /*birth_year_offset=*/2,
238 /*gender=*/UserDemographicsProto::GENDER_FEMALE,
239 /*status=*/UserDemographicsStatus::kSuccess},
240 // Test where birth year can be provided because |birth_year| - 2 <
241 // 1998.
242 DemographicsTestParam{/*birth_year=*/1999,
243 /*birth_year_offset=*/-2,
244 /*gender=*/UserDemographicsProto::GENDER_MALE,
245 /*status=*/UserDemographicsStatus::kSuccess},
246 // Test where gender can be provided because it is part of a large
247 // population with a low entropy.
248 DemographicsTestParam{/*birth_year=*/1986,
249 /*birth_year_offset=*/0,
250 /*gender=*/UserDemographicsProto::GENDER_FEMALE,
251 /*status=*/UserDemographicsStatus::kSuccess},
252 // Test where gender can be provided because it is part of a large
253 // population with a low entropy.
254 DemographicsTestParam{/*birth_year=*/1986,
255 /*birth_year_offset=*/0,
256 /*gender=*/UserDemographicsProto::GENDER_MALE,
257 /*status=*/UserDemographicsStatus::kSuccess}));
258
259 } // namespace metrics
260