blob: 569ab8183612875f5536eb0b5c3134b74bffa829 [file] [log] [blame]
// Copyright 2022 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/browsing_topics/util.h"
#include "base/bits.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/test/bind.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace browsing_topics {
namespace {
std::string GenerateRandomUniformString(int min_length, int max_length) {
DCHECK_GT(min_length, 0);
DCHECK_LT(max_length, 30);
DCHECK_LE(min_length, max_length);
int min_bound = (1 << min_length);
int max_bound = (1 << (max_length + 1)) - 1;
int random_length =
base::bits::Log2Floor(base::RandInt(min_bound, max_bound));
return base::RandBytesAsString(random_length);
}
std::string GenerateRandomDomainOrHost() {
return GenerateRandomUniformString(/*min_length=*/3, /*max_length=*/20);
}
// Check for some properties of uniform random distribution:
// - The average of values is 0.5 * UINT64_MAX.
// - 5% of values mod 100 is less than 5.
// - Chances of each bit to be 0 and 1 are equally likely.
void CheckUniformRandom(base::RepeatingCallback<uint64_t()> uint64_generator) {
constexpr double kExpectedAverage =
static_cast<double>(std::numeric_limits<uint64_t>::max()) * 0.5;
constexpr int kRepeatTimes = 1000000;
constexpr double kExpectedBitSum = kRepeatTimes * 0.5;
constexpr double kExpectedCountModHundredBelowFive = kRepeatTimes * 0.05;
constexpr double kToleranceMultipler = 0.02;
int bit_sum[64] = {0};
int count_mod_hundred_below_five = 0;
double cumulative_average = 0.0;
for (int i = 0; i < kRepeatTimes; ++i) {
uint64_t random_value = uint64_generator.Run();
cumulative_average = (i * cumulative_average + random_value) / (i + 1);
count_mod_hundred_below_five += (random_value % 100 < 5);
for (int j = 0; j < 64; ++j) {
bit_sum[j] += (random_value >> j) & 1;
}
}
ASSERT_LT(kExpectedAverage * (1 - kToleranceMultipler), cumulative_average);
ASSERT_GT(kExpectedAverage * (1 + kToleranceMultipler), cumulative_average);
ASSERT_LT(kExpectedCountModHundredBelowFive * (1 - kToleranceMultipler),
count_mod_hundred_below_five);
ASSERT_GT(kExpectedCountModHundredBelowFive * (1 + kToleranceMultipler),
count_mod_hundred_below_five);
for (int i = 0; i < 64; ++i) {
ASSERT_LT(kExpectedBitSum * (1 - kToleranceMultipler), bit_sum[i]);
ASSERT_GT(kExpectedBitSum * (1 + kToleranceMultipler), bit_sum[i]);
}
}
} // namespace
class BrowsingTopicsUtilTest : public testing::Test {};
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForRandomOrTopTopicDecision_VariableHmacKey) {
std::string top_domain = GenerateRandomDomainOrHost();
base::Time epoch_calculation_time = base::Time::Now();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
HmacKey hmac_key = GenerateRandomHmacKey();
return HashTopDomainForRandomOrTopTopicDecision(
hmac_key, epoch_calculation_time, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForRandomOrTopTopicDecision_VariableEpochCalculationTime) {
HmacKey hmac_key = GenerateRandomHmacKey();
std::string top_domain = GenerateRandomDomainOrHost();
base::Time epoch_calculation_time = base::Time::Now();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
epoch_calculation_time += base::Days(7);
return HashTopDomainForRandomOrTopTopicDecision(
hmac_key, epoch_calculation_time, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForRandomOrTopTopicDecision_VariableTopDomain) {
HmacKey hmac_key = GenerateRandomHmacKey();
base::Time epoch_calculation_time = base::Time::Now();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
std::string top_domain = GenerateRandomDomainOrHost();
return HashTopDomainForRandomOrTopTopicDecision(
hmac_key, epoch_calculation_time, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForTopTopicIndexDecision_VariableHmacKey) {
std::string top_domain = GenerateRandomDomainOrHost();
base::Time epoch_calculation_time = base::Time::Now();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
HmacKey hmac_key = GenerateRandomHmacKey();
return HashTopDomainForTopTopicIndexDecision(
hmac_key, epoch_calculation_time, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForRandomTopicIndexDecision_VariableEpochCalculationTime) {
HmacKey hmac_key = GenerateRandomHmacKey();
std::string top_domain = GenerateRandomDomainOrHost();
base::Time epoch_calculation_time = base::Time::Now();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
epoch_calculation_time += base::Days(7);
return HashTopDomainForRandomTopicIndexDecision(
hmac_key, epoch_calculation_time, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForRandomTopicIndexDecision_VariableTopDomain) {
HmacKey hmac_key = GenerateRandomHmacKey();
base::Time epoch_calculation_time = base::Time::Now();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
std::string top_domain = GenerateRandomDomainOrHost();
return HashTopDomainForRandomTopicIndexDecision(
hmac_key, epoch_calculation_time, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForRandomTopicIndexDecision_VariableHmacKey) {
std::string top_domain = GenerateRandomDomainOrHost();
base::Time epoch_calculation_time = base::Time::Now();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
HmacKey hmac_key = GenerateRandomHmacKey();
return HashTopDomainForRandomTopicIndexDecision(
hmac_key, epoch_calculation_time, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForTopTopicIndexDecision_VariableEpochCalculationTime) {
HmacKey hmac_key = GenerateRandomHmacKey();
std::string top_domain = GenerateRandomDomainOrHost();
base::Time epoch_calculation_time = base::Time::Now();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
epoch_calculation_time += base::Days(7);
return HashTopDomainForTopTopicIndexDecision(
hmac_key, epoch_calculation_time, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForTopTopicIndexDecision_VariableTopDomain) {
HmacKey hmac_key = GenerateRandomHmacKey();
base::Time epoch_calculation_time = base::Time::Now();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
std::string top_domain = GenerateRandomDomainOrHost();
return HashTopDomainForTopTopicIndexDecision(
hmac_key, epoch_calculation_time, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForEpochSwitchTimeDecision_VariableHmacKey) {
std::string top_domain = GenerateRandomDomainOrHost();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
HmacKey hmac_key = GenerateRandomHmacKey();
return HashTopDomainForEpochSwitchTimeDecision(hmac_key, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashTopDomainForEpochSwitchTimeDecision_VariableContextDomain) {
HmacKey hmac_key = GenerateRandomHmacKey();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
std::string top_domain = GenerateRandomDomainOrHost();
return HashTopDomainForEpochSwitchTimeDecision(hmac_key, top_domain);
}));
}
TEST_F(BrowsingTopicsUtilTest, HashContextDomainForStorage_VariableHmacKey) {
std::string context_domain = GenerateRandomDomainOrHost();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
HmacKey hmac_key = GenerateRandomHmacKey();
return static_cast<uint64_t>(
HashContextDomainForStorage(hmac_key, context_domain).value());
}));
}
TEST_F(BrowsingTopicsUtilTest,
HashContextDomainForStorage_VariableContextDomain) {
HmacKey hmac_key = GenerateRandomHmacKey();
CheckUniformRandom(base::BindLambdaForTesting([&]() {
std::string context_domain = GenerateRandomDomainOrHost();
return static_cast<uint64_t>(
HashContextDomainForStorage(hmac_key, context_domain).value());
}));
}
TEST_F(BrowsingTopicsUtilTest, HashMainFrameHostForStorage) {
CheckUniformRandom(base::BindLambdaForTesting([&]() {
std::string main_frame_host = GenerateRandomDomainOrHost();
return static_cast<uint64_t>(
HashMainFrameHostForStorage(main_frame_host).value());
}));
}
} // namespace browsing_topics