blob: 2ed301f16f5f517101beaee77b9cb1327896547f [file] [log] [blame]
// Copyright 2021 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/autofill_assistant/browser/startup_util.h"
#include <array>
#include <memory>
#include <ostream>
#include "base/test/scoped_feature_list.h"
#include "components/autofill_assistant/browser/features.h"
#include "components/autofill_assistant/browser/script_parameters.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace autofill_assistant {
// Note: this operator must be defined in the same namespace as the type it is
// intended for, i.e., StartupUtil::StartupMode.
std::ostream& operator<<(std::ostream& out,
const StartupUtil::StartupMode& result) {
switch (result) {
case StartupUtil::StartupMode::FEATURE_DISABLED:
out << "FEATURE_DISABLED";
break;
case StartupUtil::StartupMode::MANDATORY_PARAMETERS_MISSING:
out << "MANDATORY_PARAMETERS_MISSING";
break;
case StartupUtil::StartupMode::SETTING_DISABLED:
out << "SETTING_DISABLED";
break;
case StartupUtil::StartupMode::NO_INITIAL_URL:
out << "NO_INITIAL_URL";
break;
case StartupUtil::StartupMode::START_REGULAR:
out << "START_REGULAR";
break;
case StartupUtil::StartupMode::START_BASE64_TRIGGER_SCRIPT:
out << "START_BASE64_TRIGGER_SCRIPT";
break;
case StartupUtil::StartupMode::START_RPC_TRIGGER_SCRIPT:
out << "START_RPC_TRIGGER_SCRIPT";
break;
}
return out;
}
namespace {
using StartupMode = StartupUtil::StartupMode;
using features::kAutofillAssistant;
using features::kAutofillAssistantChromeEntry;
using features::kAutofillAssistantLoadDFMForTriggerScripts;
using features::kAutofillAssistantProactiveHelp;
using ::testing::Eq;
using ::testing::ValuesIn;
// Feature configurations to instantiate tests with.
struct TestFeatureConfig {
std::vector<base::Feature> enabled_features;
};
// Shorthand for the full set of relevant features.
const std::array<base::Feature, 4> kFullFeatureSet = {
kAutofillAssistant, kAutofillAssistantProactiveHelp,
kAutofillAssistantChromeEntry, kAutofillAssistantLoadDFMForTriggerScripts};
// Common script parameters to reuse.
const std::map<std::string, std::string> kRegularScript = {
{"ENABLED", "true"},
{"START_IMMEDIATELY", "true"},
{"ORIGINAL_DEEPLINK", "https://www.example.com"}};
const std::map<std::string, std::string> kRequestTriggerScript = {
{"ENABLED", "true"},
{"START_IMMEDIATELY", "false"},
{"REQUEST_TRIGGER_SCRIPT", "true"},
{"ORIGINAL_DEEPLINK", "https://www.example.com"}};
const std::map<std::string, std::string> kBase64TriggerScript = {
{"ENABLED", "true"},
{"START_IMMEDIATELY", "false"},
{"TRIGGER_SCRIPTS_BASE64", "abc"},
{"ORIGINAL_DEEPLINK", "https://www.example.com"}};
const TriggerContext::Options kDefaultCCTOptions = {
std::string(), /* is_cct = */ true, false, false, std::string()};
const TriggerContext::Options kDefaultNonCCTOptions = {
std::string(), /* is_cct = */ false, false, false, std::string()};
// The set of feature combinations to test.
const TestFeatureConfig kTestFeatureConfigs[] = {
// All features are disabled.
{{}},
// Only AutofillAssistant is enabled.
{{kAutofillAssistant}},
// AutofillAssistant and ChromeEntry, but not ProactiveHelp.
{{kAutofillAssistant, kAutofillAssistantChromeEntry}},
// Everything except LoadDFMForTriggerScripts.
{{kAutofillAssistant, kAutofillAssistantChromeEntry,
kAutofillAssistantProactiveHelp}},
// All features are enabled.
{{kFullFeatureSet.begin(), kFullFeatureSet.end()}}};
// Custom output operator overloads to provide human-readable test outputs.
std::ostream& operator<<(std::ostream& out, const base::Feature& feature) {
out << feature.name;
return out;
}
template <typename T>
std::ostream& operator<<(std::ostream& out, const std::vector<T>& vec) {
out << "[";
std::string separator;
for (const auto& item : vec) {
out << separator << item;
separator.assign(",");
}
out << "]";
return out;
}
std::ostream& operator<<(std::ostream& out, const TestFeatureConfig& config) {
out << "enabled_features=" << config.enabled_features << ", ";
return out;
}
std::string ToString(const StartupUtil::StartupMode& result) {
std::ostringstream stream;
stream << result;
return stream.str();
}
// Custom matcher for |StartupMode| with human-readable output.
MATCHER_P(MatchingStartupMode,
expected_result,
ToString(StartupMode{expected_result})) {
return arg == expected_result;
}
// Regular test fixture for non-parametrized tests.
class StartupUtilTest : public testing::Test {};
// Parametrized test fixture for tests that should be run against a variety of
// different feature configurations.
class StartupUtilParametrizedTest
: public StartupUtilTest,
public testing::WithParamInterface<TestFeatureConfig> {
public:
void SetUp() override {
StartupUtilTest::SetUp();
std::vector<base::Feature> disabled_features;
for (const auto& feature : kFullFeatureSet) {
if (!IsFeatureEnabled(feature)) {
disabled_features.emplace_back(feature);
}
}
scoped_feature_list_ = std::make_unique<base::test::ScopedFeatureList>();
scoped_feature_list_->InitWithFeatures(
/* enabled_features = */ GetParam().enabled_features,
/* disabled_features = */ disabled_features);
}
void TearDown() override { scoped_feature_list_.reset(); }
bool AreFeaturesEnabled(const std::vector<base::Feature>& features) const {
for (const auto& feature : features) {
if (!IsFeatureEnabled(feature)) {
return false;
}
}
return true;
}
// Returns whether |feature| is enabled for the current run.
bool IsFeatureEnabled(const base::Feature& feature) const {
return std::find_if(GetParam().enabled_features.begin(),
GetParam().enabled_features.end(),
[&](const base::Feature& candidate) {
return candidate.name == feature.name;
}) != GetParam().enabled_features.end();
}
private:
std::unique_ptr<base::test::ScopedFeatureList> scoped_feature_list_;
};
TEST_P(StartupUtilParametrizedTest, StartRegularScript) {
// CCT, DFM installation required.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{std::make_unique<ScriptParameters>(kRegularScript),
kDefaultCCTOptions},
{.feature_module_installed = false}),
MatchingStartupMode(IsFeatureEnabled(kAutofillAssistant)
? StartupMode::START_REGULAR
: StartupMode::FEATURE_DISABLED));
// Regular tab, DFM installation required.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{std::make_unique<ScriptParameters>(kRegularScript),
kDefaultNonCCTOptions},
{.feature_module_installed = false}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantChromeEntry})
? StartupMode::START_REGULAR
: StartupMode::FEATURE_DISABLED));
// Regular tab, DFM already installed.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{std::make_unique<ScriptParameters>(kRegularScript),
kDefaultNonCCTOptions},
{.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantChromeEntry})
? StartupMode::START_REGULAR
: StartupMode::FEATURE_DISABLED));
}
TEST_P(StartupUtilParametrizedTest, StartRpcTriggerScript) {
// Everything true, DFM already installed.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(kRequestTriggerScript),
kDefaultCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = true,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantProactiveHelp})
? StartupMode::START_RPC_TRIGGER_SCRIPT
: StartupMode::FEATURE_DISABLED));
// Everything true, but DFM is not yet installed.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(kRequestTriggerScript),
kDefaultNonCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = true,
.feature_module_installed = false}),
MatchingStartupMode(
AreFeaturesEnabled({kAutofillAssistant, kAutofillAssistantChromeEntry,
kAutofillAssistantLoadDFMForTriggerScripts})
? StartupMode::START_RPC_TRIGGER_SCRIPT
: StartupMode::FEATURE_DISABLED));
// CCT, MSBB is off.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(kRequestTriggerScript),
kDefaultCCTOptions},
{.msbb_setting_enabled = false,
.proactive_help_setting_enabled = true,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantProactiveHelp})
? StartupMode::SETTING_DISABLED
: StartupMode::FEATURE_DISABLED));
// CCT, Proactive help is off.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(kRequestTriggerScript),
kDefaultCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = false,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantProactiveHelp})
? StartupMode::SETTING_DISABLED
: StartupMode::FEATURE_DISABLED));
}
TEST_P(StartupUtilParametrizedTest, StartBase64TriggerScript) {
// Everything true, DFM already installed.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(kBase64TriggerScript),
kDefaultCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = true,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantProactiveHelp})
? StartupMode::START_BASE64_TRIGGER_SCRIPT
: StartupMode::FEATURE_DISABLED));
// Everything true, but DFM is not yet installed.
EXPECT_THAT(StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(kBase64TriggerScript),
kDefaultCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = true,
.feature_module_installed = false}),
MatchingStartupMode(
AreFeaturesEnabled(
{kAutofillAssistant, kAutofillAssistantProactiveHelp,
kAutofillAssistantLoadDFMForTriggerScripts})
? StartupMode::START_BASE64_TRIGGER_SCRIPT
: StartupMode::FEATURE_DISABLED));
// MSBB is off, but should not be required by base64 trigger scripts.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(kBase64TriggerScript),
kDefaultCCTOptions},
{.msbb_setting_enabled = false,
.proactive_help_setting_enabled = true,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantProactiveHelp})
? StartupMode::START_BASE64_TRIGGER_SCRIPT
: StartupMode::FEATURE_DISABLED));
// Proactive help is off.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(kBase64TriggerScript),
kDefaultCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = false,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantProactiveHelp})
? StartupMode::SETTING_DISABLED
: StartupMode::FEATURE_DISABLED));
}
TEST_P(StartupUtilParametrizedTest, InvalidParameterCombinationsShouldFail) {
// START_IMMEDIATELY=false requires either REQUEST_TRIGGER_SCRIPT or
// TRIGGER_SCRIPTS_BASE64.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(
std::map<std::string, std::string>{
{"ENABLED", "true"},
{"START_IMMEDIATELY", "false"},
{"ORIGINAL_DEEPLINK", "https://www.example.com"}}),
kDefaultCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = false,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantProactiveHelp})
? StartupMode::MANDATORY_PARAMETERS_MISSING
: StartupMode::FEATURE_DISABLED));
// REQUEST_TRIGGER_SCRIPT must not only be specified, but set to true.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(
std::map<std::string, std::string>{
{"ENABLED", "true"},
{"START_IMMEDIATELY", "false"},
{"REQUEST_TRIGGER_SCRIPT", "false"},
{"ORIGINAL_DEEPLINK", "https://www.example.com"}}),
kDefaultCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = false,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantProactiveHelp})
? StartupMode::MANDATORY_PARAMETERS_MISSING
: StartupMode::FEATURE_DISABLED));
// TRIGGER_SCRIPTS_BASE64 must not be empty.
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(
std::map<std::string, std::string>{
{"ENABLED", "true"},
{"START_IMMEDIATELY", "false"},
{"TRIGGER_SCRIPTS_BASE64", ""},
{"ORIGINAL_DEEPLINK", "https://www.example.com"}}),
kDefaultCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = false,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant,
kAutofillAssistantProactiveHelp})
? StartupMode::MANDATORY_PARAMETERS_MISSING
: StartupMode::FEATURE_DISABLED));
// ORIGINAL_DEEPLINK or initial url must be specified and valid.
EXPECT_THAT(StartupUtil().ChooseStartupModeForIntent(
TriggerContext{std::make_unique<ScriptParameters>(
std::map<std::string, std::string>{
{"ENABLED", "true"},
{"START_IMMEDIATELY", "true"}}),
kDefaultCCTOptions},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = true,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant})
? StartupMode::NO_INITIAL_URL
: StartupMode::FEATURE_DISABLED));
EXPECT_THAT(
StartupUtil().ChooseStartupModeForIntent(
TriggerContext{
std::make_unique<ScriptParameters>(
std::map<std::string, std::string>{
{"ENABLED", "true"}, {"START_IMMEDIATELY", "true"}}),
{std::string(), /* is_cct = */ true, false, false,
/* initial_url = */ "https://www.example.com"}},
{.msbb_setting_enabled = true,
.proactive_help_setting_enabled = true,
.feature_module_installed = true}),
MatchingStartupMode(AreFeaturesEnabled({kAutofillAssistant})
? StartupMode::START_REGULAR
: StartupMode::FEATURE_DISABLED));
}
INSTANTIATE_TEST_SUITE_P(StartupParamTestSuite,
StartupUtilParametrizedTest,
ValuesIn(kTestFeatureConfigs));
TEST_F(StartupUtilTest, ChooseStartupUrlForIntentPrefersOriginalDeeplink) {
std::map<std::string, std::string> script_parameters = {
{"ORIGINAL_DEEPLINK", "https://www.original-deeplink.com"}};
EXPECT_THAT(StartupUtil().ChooseStartupUrlForIntent(
{std::make_unique<ScriptParameters>(script_parameters),
TriggerContext::Options{}}),
Eq(GURL("https://www.original-deeplink.com")));
TriggerContext::Options options;
options.initial_url = "https://www.initial-url.com";
EXPECT_THAT(
StartupUtil().ChooseStartupUrlForIntent(
{std::make_unique<ScriptParameters>(script_parameters), options}),
Eq(GURL("https://www.original-deeplink.com")));
}
TEST_F(StartupUtilTest, ChooseStartupUrlForIntentFallsBackToInitialUrl) {
TriggerContext::Options options;
options.initial_url = "https://www.initial-url.com";
EXPECT_THAT(StartupUtil().ChooseStartupUrlForIntent(
{std::make_unique<ScriptParameters>(), options}),
Eq(GURL("https://www.initial-url.com")));
}
TEST_F(StartupUtilTest, ChooseStartupUrlForIntentFailsIfNotSpecified) {
EXPECT_THAT(
StartupUtil().ChooseStartupUrlForIntent(
{std::make_unique<ScriptParameters>(), TriggerContext::Options{}}),
Eq(base::nullopt));
}
} // namespace
} // namespace autofill_assistant