user_demographics_unittest.cc 11 KB

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