1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
|
// Copyright 2017 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/field_trials_provider.h"
#include <array>
#include <string_view>
#include "base/containers/span.h"
#include "base/metrics/field_trial.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/platform_thread.h"
#include "components/variations/active_field_trials.h"
#include "components/variations/synthetic_trial_registry.h"
#include "components/variations/synthetic_trials.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/metrics_proto/system_profile.pb.h"
using ActiveGroup = base::FieldTrial::ActiveGroup;
namespace variations {
namespace {
constexpr const char* kSuffix = "UKM";
const auto kFieldTrials = std::to_array<ActiveGroup>({
{"Trial1", "Group1"},
{"Trial2", "Group2"},
{"Trial3", "Group3"},
});
const auto kSyntheticFieldTrials = std::to_array<ActiveGroup>({
{"Synthetic1", "SyntheticGroup1"},
{"Synthetic2", "SyntheticGroup2"},
});
ActiveGroupId ToActiveGroupId(ActiveGroup active_group,
std::string suffix = "");
const auto kFieldTrialIds = std::to_array<ActiveGroupId>({
ToActiveGroupId(kFieldTrials[0]),
ToActiveGroupId(kFieldTrials[1]),
ToActiveGroupId(kFieldTrials[2]),
});
const auto kAllTrialIds = std::to_array<ActiveGroupId>({
ToActiveGroupId(kFieldTrials[0]),
ToActiveGroupId(kFieldTrials[1]),
ToActiveGroupId(kFieldTrials[2]),
ToActiveGroupId(kSyntheticFieldTrials[0]),
ToActiveGroupId(kSyntheticFieldTrials[1]),
});
const auto kAllTrialIdsWithSuffixes = std::to_array<ActiveGroupId>({
ToActiveGroupId(kFieldTrials[0], kSuffix),
ToActiveGroupId(kFieldTrials[1], kSuffix),
ToActiveGroupId(kFieldTrials[2], kSuffix),
ToActiveGroupId(kSyntheticFieldTrials[0], kSuffix),
ToActiveGroupId(kSyntheticFieldTrials[1], kSuffix),
});
// Check that the field trials in |system_profile| correspond to |expected|.
void CheckFieldTrialsInSystemProfile(
const metrics::SystemProfileProto& system_profile,
base::span<const ActiveGroupId> expected) {
for (int i = 0; i < system_profile.field_trial_size(); ++i) {
const metrics::SystemProfileProto::FieldTrial& field_trial =
system_profile.field_trial(i);
EXPECT_EQ(expected[i].name, field_trial.name_id());
EXPECT_EQ(expected[i].group, field_trial.group_id());
}
}
ActiveGroupId ToActiveGroupId(ActiveGroup active_group, std::string suffix) {
return MakeActiveGroupId(active_group.trial_name + suffix,
active_group.group_name + suffix);
}
} // namespace
class FieldTrialsProviderTest : public ::testing::Test {
public:
FieldTrialsProviderTest() { scope_.InitWithEmptyFeatureAndFieldTrialLists(); }
~FieldTrialsProviderTest() override = default;
protected:
void SetUp() override {
// Register the field trials.
for (const ActiveGroup& trial : kFieldTrials) {
base::FieldTrial* field_trial = base::FieldTrialList::CreateFieldTrial(
trial.trial_name, trial.group_name);
// Call Activate() to finalize and mark the field trial as active.
field_trial->Activate();
}
}
// Register trials which should get recorded.
void RegisterExpectedSyntheticTrials() {
for (const ActiveGroup& trial : kSyntheticFieldTrials) {
registry_.RegisterSyntheticFieldTrial(SyntheticTrialGroup(
trial.trial_name, trial.group_name,
/*annotation_mode=*/
variations::SyntheticTrialAnnotationMode::kNextLog));
}
}
// Register trial which shouldn't get recorded.
void RegisterExtraSyntheticTrial() {
registry_.RegisterSyntheticFieldTrial(SyntheticTrialGroup(
"ExtraSynthetic", "ExtraGroup",
/*annotation_mode=*/
variations::SyntheticTrialAnnotationMode::kNextLog));
}
// Waits until base::TimeTicks::Now() no longer equals |value|. This should
// take between 1-15ms per the documented resolution of base::TimeTicks.
void WaitUntilTimeChanges(const base::TimeTicks& value) {
while (base::TimeTicks::Now() == value) {
base::PlatformThread::Sleep(base::Milliseconds(1));
}
}
SyntheticTrialRegistry registry_;
base::test::ScopedFeatureList scope_;
};
TEST_F(FieldTrialsProviderTest, ProvideSyntheticTrials) {
FieldTrialsProvider provider(®istry_, std::string_view());
RegisterExpectedSyntheticTrials();
// Make sure these trials are older than the log.
WaitUntilTimeChanges(base::TimeTicks::Now());
// Get the current time and wait for it to change.
base::TimeTicks log_creation_time = base::TimeTicks::Now();
// Make sure that the log is older than the trials that should be excluded.
WaitUntilTimeChanges(log_creation_time);
RegisterExtraSyntheticTrial();
metrics::SystemProfileProto proto;
provider.ProvideSystemProfileMetricsWithLogCreationTime(log_creation_time,
&proto);
EXPECT_EQ(std::size(kAllTrialIds),
static_cast<size_t>(proto.field_trial_size()));
CheckFieldTrialsInSystemProfile(proto, kAllTrialIds);
}
TEST_F(FieldTrialsProviderTest, NoSyntheticTrials) {
FieldTrialsProvider provider(nullptr, std::string_view());
metrics::SystemProfileProto proto;
provider.ProvideSystemProfileMetricsWithLogCreationTime(base::TimeTicks(),
&proto);
EXPECT_EQ(std::size(kFieldTrialIds),
static_cast<size_t>(proto.field_trial_size()));
CheckFieldTrialsInSystemProfile(proto, kFieldTrialIds);
}
TEST_F(FieldTrialsProviderTest, ProvideCurrentSessionData) {
metrics::ChromeUserMetricsExtension uma_log;
uma_log.system_profile();
// {1, 1} should not be in the resulting proto as ProvideCurrentSessionData()
// clears existing trials and sets the trials to be those determined by
// GetSyntheticFieldTrialsOlderThan() and GetFieldTrialIds().
metrics::SystemProfileProto::FieldTrial* trial =
uma_log.mutable_system_profile()->add_field_trial();
trial->set_name_id(1);
trial->set_group_id(1);
FieldTrialsProvider provider(®istry_, std::string_view());
RegisterExpectedSyntheticTrials();
WaitUntilTimeChanges(base::TimeTicks::Now());
provider.SetLogCreationTimeForTesting(base::TimeTicks::Now());
provider.ProvideCurrentSessionData(&uma_log);
EXPECT_EQ(std::size(kAllTrialIds),
static_cast<size_t>(uma_log.system_profile().field_trial_size()));
CheckFieldTrialsInSystemProfile(uma_log.system_profile(), kAllTrialIds);
}
TEST_F(FieldTrialsProviderTest, GetAndWriteFieldTrialsWithSuffixes) {
metrics::ChromeUserMetricsExtension uma_log;
uma_log.system_profile();
FieldTrialsProvider provider(®istry_, kSuffix);
RegisterExpectedSyntheticTrials();
WaitUntilTimeChanges(base::TimeTicks::Now());
provider.SetLogCreationTimeForTesting(base::TimeTicks::Now());
provider.ProvideCurrentSessionData(&uma_log);
EXPECT_EQ(std::size(kAllTrialIdsWithSuffixes),
static_cast<size_t>(uma_log.system_profile().field_trial_size()));
CheckFieldTrialsInSystemProfile(uma_log.system_profile(),
kAllTrialIdsWithSuffixes);
}
} // namespace variations
|