blob: cc28714f1f1cac8b3e0d8d5a849e575dcaab93bc [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/metrics/dwa/dwa_recorder.h"
#include <unordered_map>
#include <vector>
#include "base/metrics/field_trial.h"
#include "base/metrics/metrics_hashes.h"
#include "base/test/scoped_feature_list.h"
#include "components/metrics/dwa/dwa_entry_builder.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace metrics::dwa {
namespace {
// Converts `repeated_ptr_field_metrics` into an unordered_map of metrics. Each
// metric in metrics consists of a name_hash (key) and value (value).
std::unordered_map<uint64_t, int64_t> RepeatedPtrFieldMetricToUnorderedMap(
const google::protobuf::RepeatedPtrField<
::dwa::DeidentifiedWebAnalyticsEvent::Metric>&
repeated_ptr_field_metrics) {
std::unordered_map<uint64_t, int64_t> metrics;
metrics.reserve(repeated_ptr_field_metrics.size());
for (const auto& metric : repeated_ptr_field_metrics) {
metrics[metric.name_hash()] = metric.value();
}
return metrics;
}
// Converts `repeated_ptr_field_field_trials` into vector of field trial groups.
// Each field trial group consist of a pair of field trial name hash (first) and
// group name hash (second).
std::vector<std::pair<uint32_t, uint32_t>> RepeatedPtrFieldFieldTrialsToVector(
const google::protobuf::RepeatedPtrField<
::metrics::SystemProfileProto::FieldTrial>&
repeated_ptr_field_field_trials) {
std::vector<std::pair<uint32_t, uint32_t>> field_trial_groups;
field_trial_groups.reserve(repeated_ptr_field_field_trials.size());
for (const auto& field_trial : repeated_ptr_field_field_trials) {
field_trial_groups.emplace_back(field_trial.name_id(),
field_trial.group_id());
}
return field_trial_groups;
}
} // namespace
class DwaRecorderTestBase : public testing::Test {
public:
explicit DwaRecorderTestBase(bool enable_feature) {
if (enable_feature) {
scoped_feature_list_.InitAndEnableFeature(kDwaFeature);
} else {
scoped_feature_list_.InitAndDisableFeature(kDwaFeature);
}
recorder_ = DwaRecorder::Get();
recorder_->Purge();
recorder_->EnableRecording();
}
~DwaRecorderTestBase() override = default;
DwaRecorder* GetRecorder() { return recorder_; }
private:
raw_ptr<DwaRecorder> recorder_;
base::test::ScopedFeatureList scoped_feature_list_;
};
class DwaRecorderEnabledTest : public DwaRecorderTestBase {
public:
DwaRecorderEnabledTest() : DwaRecorderTestBase(/*enable_feature=*/true) {}
};
class DwaRecorderDisabledTest : public DwaRecorderTestBase {
public:
DwaRecorderDisabledTest() : DwaRecorderTestBase(/*enable_feature=*/false) {}
};
TEST_F(DwaRecorderEnabledTest, ValidateHasEntriesWhenEntryIsAdded) {
::dwa::DwaEntryBuilder builder("Kangaroo.Jumped");
builder.SetContent("https://adtech.com");
builder.SetMetric("Length", 5);
builder.Record(GetRecorder());
EXPECT_TRUE(GetRecorder()->HasEntries());
}
TEST_F(DwaRecorderEnabledTest, ValidateEntriesWhenRecordingIsDisabled) {
GetRecorder()->DisableRecording();
::dwa::DwaEntryBuilder builder("Kangaroo.Jumped");
builder.SetContent("https://adtech.com");
builder.SetMetric("Length", 5);
builder.Record(GetRecorder());
EXPECT_FALSE(GetRecorder()->HasEntries());
}
TEST_F(DwaRecorderEnabledTest, ValidateRecorderRecords) {
base::FieldTrialList::CreateFieldTrial("test_trial_1", "test_group_2")
->Activate();
base::FieldTrialList::CreateFieldTrial("test_trial_2", "test_group_1")
->Activate();
base::FieldTrialList::CreateFieldTrial("test_trial_3", "test_group_8")
->Activate();
::dwa::DwaEntryBuilder builder_1("Kangaroo.Jumped");
builder_1.SetContent("https://adtech.com");
builder_1.AddToStudiesOfInterest("test_trial_1");
builder_1.AddToStudiesOfInterest("test_trial_2");
builder_1.SetMetric("Length", 5);
builder_1.SetMetric("Width", 10);
builder_1.Record(GetRecorder());
::dwa::DwaEntryBuilder builder_2("Frog.Leaped");
builder_2.SetContent("https://adtech.com");
builder_2.AddToStudiesOfInterest("test_trial_1");
builder_2.AddToStudiesOfInterest("test_trial_2");
builder_2.SetMetric("Distance", 20);
builder_2.Record(GetRecorder());
::dwa::DwaEntryBuilder builder_3("Kangaroo.Jumped");
builder_3.SetContent("https://adtech2.com");
builder_3.AddToStudiesOfInterest("test_trial_3");
builder_3.SetMetric("Length", 3);
builder_3.SetMetric("Width", 12);
builder_3.Record(GetRecorder());
EXPECT_TRUE(GetRecorder()->HasEntries());
auto dwa_events = GetRecorder()->TakeDwaEvents();
EXPECT_FALSE(dwa_events.empty());
ASSERT_EQ(dwa_events.size(), 3u);
// Validate event hash is populated accordingly to the recorded dwa events.
EXPECT_EQ(dwa_events[0].event_hash(),
base::HashMetricName("Kangaroo.Jumped"));
EXPECT_EQ(dwa_events[1].event_hash(), base::HashMetricName("Frog.Leaped"));
EXPECT_EQ(dwa_events[2].event_hash(),
base::HashMetricName("Kangaroo.Jumped"));
// Validate content hash is populated accordingly to the recorded dwa events.
EXPECT_EQ(dwa_events[0].content_hash(), base::HashMetricName("adtech.com"));
EXPECT_EQ(dwa_events[1].content_hash(), base::HashMetricName("adtech.com"));
EXPECT_EQ(dwa_events[2].content_hash(), base::HashMetricName("adtech2.com"));
// Validate metrics are populated accordingly to the recorded dwa events.
ASSERT_EQ(dwa_events[0].metric().size(), 2);
EXPECT_THAT(RepeatedPtrFieldMetricToUnorderedMap(dwa_events[0].metric()),
testing::UnorderedElementsAre(
testing::Pair(base::HashMetricName("Length"), 5),
testing::Pair(base::HashMetricName("Width"), 10)));
ASSERT_EQ(dwa_events[1].metric().size(), 1);
EXPECT_THAT(RepeatedPtrFieldMetricToUnorderedMap(dwa_events[1].metric()),
testing::UnorderedElementsAre(
testing::Pair(base::HashMetricName("Distance"), 20)));
ASSERT_EQ(dwa_events[2].metric().size(), 2);
EXPECT_THAT(RepeatedPtrFieldMetricToUnorderedMap(dwa_events[2].metric()),
testing::UnorderedElementsAre(
testing::Pair(base::HashMetricName("Length"), 3),
testing::Pair(base::HashMetricName("Width"), 12)));
// Validate studies of interests are populated accordingly to the recorded dwa
// events.
EXPECT_THAT(RepeatedPtrFieldFieldTrialsToVector(dwa_events[0].field_trials()),
testing::UnorderedElementsAre(
testing::Pair(base::HashFieldTrialName("test_trial_1"),
base::HashFieldTrialName("test_group_2")),
testing::Pair(base::HashFieldTrialName("test_trial_2"),
base::HashFieldTrialName("test_group_1"))));
EXPECT_THAT(RepeatedPtrFieldFieldTrialsToVector(dwa_events[1].field_trials()),
testing::UnorderedElementsAre(
testing::Pair(base::HashFieldTrialName("test_trial_1"),
base::HashFieldTrialName("test_group_2")),
testing::Pair(base::HashFieldTrialName("test_trial_2"),
base::HashFieldTrialName("test_group_1"))));
EXPECT_THAT(RepeatedPtrFieldFieldTrialsToVector(dwa_events[2].field_trials()),
testing::UnorderedElementsAre(
testing::Pair(base::HashFieldTrialName("test_trial_3"),
base::HashFieldTrialName("test_group_8"))));
}
TEST_F(DwaRecorderDisabledTest, FeatureDisabled) {
::dwa::DwaEntryBuilder builder("Kangaroo.Jumped");
builder.SetContent("https://adtech.com");
builder.SetMetric("Length", 5);
builder.Record(GetRecorder());
EXPECT_FALSE(GetRecorder()->HasEntries());
}
} // namespace metrics::dwa