[go: nahoru, domu]

blob: 382fd9dd4249d0e1050dbee148177562a812f2e0 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/metrics/demographics/user_demographics.h"
#include <utility>
#include "base/time/time.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/user_demographics.pb.h"
namespace metrics {
namespace {
// Gets the now time used for testing demographics.
base::Time GetNowTime() {
constexpr char kNowTimeInStringFormat[] = "22 Jul 2019 00:00:00 UDT";
base::Time now;
bool result = base::Time::FromString(kNowTimeInStringFormat, &now);
DCHECK(result);
return now;
}
} // namespace
TEST(UserDemographicsTest, UserDemographicsResult_ForValue) {
int user_birth_year = 1982;
UserDemographicsProto_Gender user_gender = UserDemographicsProto::GENDER_MALE;
UserDemographics user_demographics;
user_demographics.birth_year = user_birth_year;
user_demographics.gender = user_gender;
UserDemographicsResult user_demographics_result =
UserDemographicsResult::ForValue(std::move(user_demographics));
EXPECT_TRUE(user_demographics_result.IsSuccess());
EXPECT_EQ(UserDemographicsStatus::kSuccess,
user_demographics_result.status());
EXPECT_EQ(user_birth_year, user_demographics_result.value().birth_year);
EXPECT_EQ(user_gender, user_demographics_result.value().gender);
}
TEST(UserDemographicsTest, UserDemographicsResult_ForStatus) {
UserDemographicsStatus error_status =
UserDemographicsStatus::kIneligibleDemographicsData;
UserDemographicsResult user_demographics_result =
UserDemographicsResult::ForStatus(error_status);
EXPECT_FALSE(user_demographics_result.IsSuccess());
EXPECT_EQ(error_status, user_demographics_result.status());
}
class UserDemographicsPrefsTest : public testing::Test {
protected:
UserDemographicsPrefsTest() {
RegisterDemographicsProfilePrefs(pref_service_.registry());
}
void SetDemographics(int birth_year, UserDemographicsProto::Gender gender) {
base::DictionaryValue dict;
dict.SetIntPath(kSyncDemographicsBirthYearPath, birth_year);
dict.SetIntPath(kSyncDemographicsGenderPath, static_cast<int>(gender));
pref_service_.Set(kSyncDemographicsPrefName, dict);
}
sync_preferences::TestingPrefServiceSyncable pref_service_;
};
TEST_F(UserDemographicsPrefsTest, ReadDemographicsWithRandomOffset) {
int user_demographics_birth_year = 1983;
UserDemographicsProto_Gender user_demographics_gender =
UserDemographicsProto::GENDER_MALE;
// Set user demographic prefs.
SetDemographics(user_demographics_birth_year, user_demographics_gender);
int provided_birth_year;
{
UserDemographicsResult demographics_result =
GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
ASSERT_TRUE(demographics_result.IsSuccess());
EXPECT_EQ(user_demographics_gender, demographics_result.value().gender);
// Verify that the provided birth year is within the range.
provided_birth_year = demographics_result.value().birth_year;
int delta = provided_birth_year - user_demographics_birth_year;
EXPECT_LE(delta, kUserDemographicsBirthYearNoiseOffsetRange);
EXPECT_GE(delta, -kUserDemographicsBirthYearNoiseOffsetRange);
}
// Verify that the offset is cached and that the randomized birth year is the
// same when doing more that one read of the birth year.
{
ASSERT_TRUE(
pref_service_.HasPrefPath(kSyncDemographicsBirthYearOffsetPrefName));
UserDemographicsResult demographics_result =
GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
ASSERT_TRUE(demographics_result.IsSuccess());
EXPECT_EQ(provided_birth_year, demographics_result.value().birth_year);
}
}
TEST_F(UserDemographicsPrefsTest, ReadAndClearUserDemographicPreferences) {
// Verify demographic prefs are not available when there is nothing set.
ASSERT_FALSE(
GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_)
.IsSuccess());
// Set demographic prefs directly from the pref service interface because
// demographic prefs will only be set on the server-side. The SyncPrefs
// interface cannot set demographic prefs.
SetDemographics(1983, UserDemographicsProto::GENDER_FEMALE);
// Set birth year noise offset to not have it randomized.
pref_service_.SetInteger(kSyncDemographicsBirthYearOffsetPrefName, 2);
// Verify that demographics are provided.
{
UserDemographicsResult demographics_result =
GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
ASSERT_TRUE(demographics_result.IsSuccess());
}
ClearDemographicsPrefs(&pref_service_);
// Verify that demographics are not provided and kSyncDemographics is cleared.
// Note that we retain kSyncDemographicsBirthYearOffset. If the user resumes
// syncing, causing these prefs to be recreated, we don't want them to start
// reporting a different randomized birth year as this could narrow down or
// even reveal their true birth year.
EXPECT_FALSE(
GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_)
.IsSuccess());
EXPECT_FALSE(pref_service_.HasPrefPath(kSyncDemographicsPrefName));
EXPECT_TRUE(
pref_service_.HasPrefPath(kSyncDemographicsBirthYearOffsetPrefName));
}
struct DemographicsTestParam {
// Birth year of the user.
int birth_year = kUserDemographicsBirthYearDefaultValue;
// Non-random offset to apply to |birth_year| as noise.
int birth_year_offset = kUserDemographicsBirthYearNoiseOffsetDefaultValue;
// Gender of the user.
UserDemographicsProto_Gender gender = kUserDemographicGenderDefaultEnumValue;
// Status of the retrieval of demographics.
UserDemographicsStatus status = UserDemographicsStatus::kMaxValue;
};
// Extend UserDemographicsPrefsTest fixture for parameterized tests on
// demographics.
class UserDemographicsPrefsTestWithParam
: public UserDemographicsPrefsTest,
public testing::WithParamInterface<DemographicsTestParam> {};
TEST_P(UserDemographicsPrefsTestWithParam, ReadDemographics_OffsetIsNotRandom) {
DemographicsTestParam param = GetParam();
// Set user demographic prefs.
SetDemographics(param.birth_year, param.gender);
// Set birth year noise offset to not have it randomized.
pref_service_.SetInteger(kSyncDemographicsBirthYearOffsetPrefName,
param.birth_year_offset);
// Verify provided demographics for the different parameterized test cases.
UserDemographicsResult demographics_result =
GetUserNoisedBirthYearAndGenderFromPrefs(GetNowTime(), &pref_service_);
if (param.status == UserDemographicsStatus::kSuccess) {
ASSERT_TRUE(demographics_result.IsSuccess());
EXPECT_EQ(param.birth_year + param.birth_year_offset,
demographics_result.value().birth_year);
EXPECT_EQ(param.gender, demographics_result.value().gender);
} else {
ASSERT_FALSE(demographics_result.IsSuccess());
EXPECT_EQ(param.status, demographics_result.status());
}
}
// Test suite composed of different test cases of getting user demographics.
// The now time in each test case is "22 Jul 2019 00:00:00 UDT" which falls into
// the year bucket of 2018. Users need at most a |birth_year| +
// |birth_year_offset| of 1998 to be able to provide demographics.
INSTANTIATE_TEST_SUITE_P(
All,
UserDemographicsPrefsTestWithParam,
::testing::Values(
// Test where birth year should not be provided because |birth_year| + 2
// > 1998.
DemographicsTestParam{
/*birth_year=*/1997,
/*birth_year_offset=*/2,
/*gender=*/UserDemographicsProto::GENDER_FEMALE,
/*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
// Test where birth year should not be provided because |birth_year| - 2
// > 1998.
DemographicsTestParam{
/*birth_year=*/2001,
/*birth_year_offset=*/-2,
/*gender=*/UserDemographicsProto::GENDER_FEMALE,
/*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
// Test where birth year should not be provided because age of user is
// |kUserDemographicsMaxAge| + 1, which is over the max age.
DemographicsTestParam{
/*birth_year=*/1933,
/*birth_year_offset=*/0,
/*gender=*/UserDemographicsProto::GENDER_FEMALE,
/*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
// Test where gender should not be provided because it has a low
// population that can have their privacy compromised because of high
// entropy.
DemographicsTestParam{
/*birth_year=*/1986,
/*birth_year_offset=*/0,
/*gender=*/UserDemographicsProto::GENDER_CUSTOM_OR_OTHER,
/*status=*/UserDemographicsStatus::kIneligibleDemographicsData},
// Test where birth year can be provided because |birth_year| + 2 ==
// 1998.
DemographicsTestParam{/*birth_year=*/1996,
/*birth_year_offset=*/2,
/*gender=*/UserDemographicsProto::GENDER_FEMALE,
/*status=*/UserDemographicsStatus::kSuccess},
// Test where birth year can be provided because |birth_year| - 2 ==
// 1998.
DemographicsTestParam{/*birth_year=*/2000,
/*birth_year_offset=*/-2,
/*gender=*/UserDemographicsProto::GENDER_MALE,
/*status=*/UserDemographicsStatus::kSuccess},
// Test where birth year can be provided because |birth_year| + 2 <
// 1998.
DemographicsTestParam{/*birth_year=*/1995,
/*birth_year_offset=*/2,
/*gender=*/UserDemographicsProto::GENDER_FEMALE,
/*status=*/UserDemographicsStatus::kSuccess},
// Test where birth year can be provided because |birth_year| - 2 <
// 1998.
DemographicsTestParam{/*birth_year=*/1999,
/*birth_year_offset=*/-2,
/*gender=*/UserDemographicsProto::GENDER_MALE,
/*status=*/UserDemographicsStatus::kSuccess},
// Test where gender can be provided because it is part of a large
// population with a low entropy.
DemographicsTestParam{/*birth_year=*/1986,
/*birth_year_offset=*/0,
/*gender=*/UserDemographicsProto::GENDER_FEMALE,
/*status=*/UserDemographicsStatus::kSuccess},
// Test where gender can be provided because it is part of a large
// population with a low entropy.
DemographicsTestParam{/*birth_year=*/1986,
/*birth_year_offset=*/0,
/*gender=*/UserDemographicsProto::GENDER_MALE,
/*status=*/UserDemographicsStatus::kSuccess}));
} // namespace metrics