#include "components/feature_engagement/internal/chrome_variations_configuration.h"
#include <map>
#include <string>
#include <vector>
#include "base/feature_list.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_param_associator.h"
#include "base/metrics/field_trial_params.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "components/feature_engagement/public/configuration.h"
#include "components/feature_engagement/public/configuration_provider.h"
#include "components/feature_engagement/public/group_constants.h"
#include "components/feature_engagement/public/stats.h"
#include "components/feature_engagement/public/tracker.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace feature_engagement {
namespace {
BASE_FEATURE(…);
BASE_FEATURE(…);
BASE_FEATURE(…);
BASE_FEATURE(…);
BASE_FEATURE(…);
BASE_FEATURE(…);
const char kFooTrialName[] = …;
const char kBarTrialName[] = …;
const char kQuxTrialName[] = …;
const char kGroupOneTrialName[] = …;
const char kGroupTwoTrialName[] = …;
const char kGroupThreeTrialName[] = …;
const char kTrialGroupName[] = …;
const char kConfigParseEventName[] = …;
SessionRateImpact CreateSessionRateImpactExplicit(
std::vector<std::string> affected_features) { … }
BlockedBy CreateBlockedByExplicit(std::vector<std::string> affected_features) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
class TestConfigurationProvider : public ConfigurationProvider {
public:
TestConfigurationProvider() = default;
~TestConfigurationProvider() override = default;
bool MaybeProvideFeatureConfiguration(
const base::Feature& feature,
feature_engagement::FeatureConfig& config,
const feature_engagement::FeatureVector& known_features,
const feature_engagement::GroupVector& known_groups) const override {
config = config_;
return true;
}
const char* GetConfigurationSourceDescription() const override {
return "Test Configuration Provider";
}
std::set<std::string> MaybeProvideAllowedEventPrefixes(
const base::Feature& feature) const override {
return {"TestEventPrefix"};
}
void SetConfig(const FeatureConfig& config) { config_ = config; }
private:
FeatureConfig config_;
};
#endif
class ChromeVariationsConfigurationTest : public ::testing::Test { … };
}
TEST_F(ChromeVariationsConfigurationTest,
DisabledFeatureShouldHaveInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseSingleFeature) { … }
TEST_F(ChromeVariationsConfigurationTest, ParsePrefixedParamNames) { … }
TEST_F(ChromeVariationsConfigurationTest,
MultipleFeaturesWithPrefixedAndUnprefixedParams) { … }
TEST_F(ChromeVariationsConfigurationTest, MissingUsedIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest, MissingTriggerIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest, OnlyTriggerAndUsedIsValid) { … }
void RunBlockedByTest(ChromeVariationsConfigurationTest* test,
ChromeVariationsConfiguration* configuration,
std::vector<const base::Feature*> features,
std::string blocked_by_param_value,
BlockedBy expected_blocked_by,
bool is_valid) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockingNone) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockingAll) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseInvalidBlockingParams) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockedByAll) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockedByNone) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockedByExplicitSelf) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockedByExplicitOther) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockedByExplicitMultiple) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockedByExplicitEmpty) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockedByExplicitOnlySeparator) { … }
TEST_F(ChromeVariationsConfigurationTest,
ParseBlockedByExplicitUnknownFeature) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseBlockedByExplicitAll) { … }
void RunSessionRateImpactTest(ChromeVariationsConfigurationTest* test,
ChromeVariationsConfiguration* configuration,
std::vector<const base::Feature*> features,
std::string session_rate_impact_param_value,
SessionRateImpact expected_impact,
bool is_valid) { … }
TEST_F(ChromeVariationsConfigurationTest, SessionRateImpactAll) { … }
TEST_F(ChromeVariationsConfigurationTest, SessionRateImpactNone) { … }
TEST_F(ChromeVariationsConfigurationTest, SessionRateImpactExplicitSelf) { … }
TEST_F(ChromeVariationsConfigurationTest, SessionRateImpactExplicitOther) { … }
TEST_F(ChromeVariationsConfigurationTest, SessionRateImpactExplicitMultiple) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitAtLeastOneValidFeature) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitAtLeastOneValidFeaturePlusEmpty) { … }
void TestInvalidSessionRateImpactParamValue(
ChromeVariationsConfigurationTest* test,
ChromeVariationsConfiguration* configuration,
std::string session_rate_impact_param_value,
uint32_t parse_errors,
uint32_t unknown_features) { … }
TEST_F(ChromeVariationsConfigurationTest, SessionRateImpactExplicitEmpty) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitEmptyWhitespace) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitOnlySeparator) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitOnlySeparatorWhitespace) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitOnlyUnknownFeature) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitOnlyMultipleUnknownFeatures) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitOnlyUnknownFeaturePlusEmpty) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitInvalidFeatureNameAllFirst) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitInvalidFeatureNameAllLast) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitInvalidFeatureNameAllLastInvalidFirst) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitInvalidFeatureNameNoneFirst) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitInvalidFeatureNameNoneLast) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitInvalidFeatureNameNoneLastInvalidFirst) { … }
TEST_F(ChromeVariationsConfigurationTest,
SessionRateImpactExplicitInvalidFeatureNameFromCodeReview) { … }
void RunGroupsTest(ChromeVariationsConfigurationTest* test,
ChromeVariationsConfiguration* configuration,
FeatureVector features,
GroupVector groups,
std::string groups_param_value,
std::vector<std::string> expected_groups,
bool is_valid) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseGroupsItem) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseGroupsMultiple) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseGroupsEmpty) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseGroupsOnlySeparator) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseGroupsUnknownGroup) { … }
TEST_F(ChromeVariationsConfigurationTest,
ParseGroupsCombinationKnownAndUnknownGroups) { … }
TEST_F(ChromeVariationsConfigurationTest, WhitespaceIsValid) { … }
TEST_F(ChromeVariationsConfigurationTest, IgnoresInvalidConfigKeys) { … }
TEST_F(ChromeVariationsConfigurationTest, IgnoresInvalidEventConfigTokens) { … }
TEST_F(ChromeVariationsConfigurationTest,
MissingAllEventConfigParamsIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
MissingEventEventConfigParamIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
MissingComparatorEventConfigParamIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
MissingWindowEventConfigParamIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
MissingStorageEventConfigParamIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
EventSpecifiedMultipleTimesIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
ComparatorSpecifiedMultipleTimesIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
WindowSpecifiedMultipleTimesIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
StorageSpecifiedMultipleTimesIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
InvalidSessionRateCausesInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest,
InvalidAvailabilityCausesInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest, InvalidUsedCausesInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest, InvalidTriggerCausesInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest,
InvalidEventConfigCausesInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest,
InvalidTrackingOnlyCausesInvalidConfig) { … }
void RunTrackingOnlyTest(ChromeVariationsConfigurationTest* test,
ChromeVariationsConfiguration* configuration,
std::vector<const base::Feature*> features,
std::string tracking_only_definition,
bool expected_value,
bool is_valid) { … }
TEST_F(ChromeVariationsConfigurationTest, TrackingOnlyReturnsTrue) { … }
TEST_F(ChromeVariationsConfigurationTest,
TrackingOnlyReturnsTrueCaseInsensitive) { … }
TEST_F(ChromeVariationsConfigurationTest, TrackingOnlyReturnsFalse) { … }
TEST_F(ChromeVariationsConfigurationTest,
TrackingOnlyReturnsFalseCaseInsensitive) { … }
TEST_F(ChromeVariationsConfigurationTest, AllComparatorTypesWork) { … }
TEST_F(ChromeVariationsConfigurationTest, MultipleEventsWithSameName) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseMultipleFeatures) { … }
TEST_F(ChromeVariationsConfigurationTest, CheckedInConfigIsReadable) { … }
TEST_F(ChromeVariationsConfigurationTest,
CheckedInConfigButDisabledFeatureIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest, NonExistingConfigIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseValidSnoozeParams) { … }
TEST_F(ChromeVariationsConfigurationTest, UnorderedSnoozeParams) { … }
TEST_F(ChromeVariationsConfigurationTest, InvalidMaxLimitSnoozeParams) { … }
TEST_F(ChromeVariationsConfigurationTest, InvalidIntervalSnoozeParams) { … }
TEST_F(ChromeVariationsConfigurationTest, IncompleteSnoozeParams) { … }
TEST_F(ChromeVariationsConfigurationTest,
DisabledGroupShouldHaveInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseSingleGroup) { … }
TEST_F(ChromeVariationsConfigurationTest, EmptyGroupIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest, GroupOnlyTriggerIsValid) { … }
TEST_F(ChromeVariationsConfigurationTest, GroupIgnoresInvalidConfigKeys) { … }
TEST_F(ChromeVariationsConfigurationTest,
GroupInvalidSessionRateCausesInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest,
GroupInvalidTriggerCausesInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest,
GroupInvalidEventConfigCausesInvalidConfig) { … }
TEST_F(ChromeVariationsConfigurationTest, GroupMultipleEventsWithSameName) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseMultipleGroups) { … }
TEST_F(ChromeVariationsConfigurationTest, CheckedInGroupConfigIsReadable) { … }
TEST_F(ChromeVariationsConfigurationTest,
CheckedInGroupConfigButDisabledGroupIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest, NonExistingGroupConfigIsInvalid) { … }
TEST_F(ChromeVariationsConfigurationTest,
ParseExpandsBlockedByGroupNameIntoFeatures) { … }
TEST_F(ChromeVariationsConfigurationTest,
ParseExpandsBlockedByEmptyGroupIntoEmptyList) { … }
TEST_F(ChromeVariationsConfigurationTest,
ParseExpandsBlockedByGroupAndFeature) { … }
TEST_F(ChromeVariationsConfigurationTest, ParseExpandsBlockedByMultipleGroups) { … }
TEST_F(ChromeVariationsConfigurationTest,
ParseExpandsBlockedByFeatureAppearsMultipleTimes) { … }
TEST_F(ChromeVariationsConfigurationTest,
ParseExpandsSessionRateImpactGroupNameIntoFeatures) { … }
TEST_F(ChromeVariationsConfigurationTest,
ParseExpandsSessionRateEmptyGroupIntoEmptyList) { … }
#if BUILDFLAG(IS_CHROMEOS_ASH)
TEST_F(ChromeVariationsConfigurationTest, UpdateConfigs) {
FeatureConfig expected_foo;
expected_foo.valid = true;
expected_foo.used =
EventConfig("page_download_started", Comparator(ANY, 0), 0, 360);
expected_foo.trigger =
EventConfig("opened_chrome_home", Comparator(ANY, 0), 0, 360);
expected_foo.event_configs.insert(EventConfig(
"user_has_seen_dino", Comparator(GREATER_THAN_OR_EQUAL, 1), 120, 180));
expected_foo.event_configs.insert(EventConfig(
"user_opened_app_menu", Comparator(LESS_THAN_OR_EQUAL, 0), 120, 180));
expected_foo.event_configs.insert(
EventConfig("user_opened_downloads_home", Comparator(ANY, 0), 0, 360));
auto provider = std::make_unique<TestConfigurationProvider>();
provider->SetConfig(expected_foo);
configuration_.UpdateConfig(kChromeTestFeatureFoo, provider.get());
FeatureConfig foo = configuration_.GetFeatureConfig(kChromeTestFeatureFoo);
EXPECT_EQ(expected_foo, foo);
expected_foo = FeatureConfig();
expected_foo.valid = true;
expected_foo.used =
EventConfig("page_download_started", Comparator(ANY, 0), 0, 360);
expected_foo.trigger =
EventConfig("opened_chrome_home", Comparator(ANY, 0), 0, 360);
expected_foo.event_configs.insert(EventConfig(
"user_opened_app_menu", Comparator(LESS_THAN_OR_EQUAL, 0), 120, 180));
EXPECT_NE(expected_foo, foo);
provider->SetConfig(expected_foo);
configuration_.UpdateConfig(kChromeTestFeatureFoo, provider.get());
foo = configuration_.GetFeatureConfig(kChromeTestFeatureFoo);
EXPECT_EQ(expected_foo, foo);
}
TEST_F(ChromeVariationsConfigurationTest, GetEventPrefixes) {
ConfigurationProviderList providers;
providers.emplace_back(std::make_unique<TestConfigurationProvider>());
configuration_.LoadConfigs(providers, {&kChromeTestFeatureFoo},
{});
const auto& prefixes = configuration_.GetRegisteredAllowedEventPrefixes();
EXPECT_EQ(1u, prefixes.size());
EXPECT_TRUE(prefixes.contains("TestEventPrefix"));
}
#endif
}