Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(108)

Unified Diff: chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc

Issue 2278013002: Add support for the ExperimentalSwReporterEngine field trial. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc
diff --git a/chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc b/chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc
index 3a2dd0ad372e52d1ed9df467209ab83cd0ae5d7f..09da209cc188609ebc3cbe88d082a42abf2ee37d 100644
--- a/chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc
+++ b/chrome/browser/component_updater/sw_reporter_installer_win_unittest.cc
@@ -4,40 +4,55 @@
#include "chrome/browser/component_updater/sw_reporter_installer_win.h"
+#include <map>
#include <memory>
+#include <string>
+#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/files/file_path.h"
+#include "base/json/json_reader.h"
#include "base/macros.h"
+#include "base/metrics/field_trial.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/values.h"
#include "base/version.h"
#include "chrome/browser/safe_browsing/srt_fetcher_win.h"
+#include "components/variations/variations_associated_data.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace component_updater {
+namespace {
+
+constexpr char kExperimentGroupName[] = "ExperimentalSwReporterEngine";
+
+// These MUST match the values for SwReporterExperimentError in histograms.xml.
+enum ExperimentError {
+ EXPERIMENT_ERROR_BAD_TAG = 0,
+ EXPERIMENT_ERROR_BAD_PARAMS = 1,
+ EXPERIMENT_ERROR_MAX,
+};
+
+}; // namespace
+
class SwReporterInstallerTest : public ::testing::Test {
public:
SwReporterInstallerTest()
- : traits_(base::Bind(&SwReporterInstallerTest::SwReporterLaunched,
- base::Unretained(this))),
+ : launched_callback_(
+ base::Bind(&SwReporterInstallerTest::SwReporterLaunched,
+ base::Unretained(this))),
default_version_("1.2.3"),
default_path_(L"C:\\full\\path\\to\\download") {}
protected:
- // Each test fixture inherits from |SwReporterInstallerTest|, and friendship
- // is not transitive so they will not have access to |ComponentReady|. Use
- // this helper function to call it.
- void TestComponentReady(const base::Version& version,
- const base::FilePath& path) {
- traits_.ComponentReady(version, path,
- std::make_unique<base::DictionaryValue>());
- }
-
void SwReporterLaunched(const safe_browsing::SwReporterInvocation& invocation,
const base::Version& version) {
ASSERT_TRUE(launched_invocations_.empty());
@@ -49,12 +64,27 @@ class SwReporterInstallerTest : public ::testing::Test {
return path.Append(L"software_reporter_tool.exe");
}
+ // Expect that the SwReporter was launched exactly once, with no arguments.
+ void ExpectDefaultInvocation() const {
+ EXPECT_EQ(default_version_, launched_version_);
+ ASSERT_EQ(1U, launched_invocations_.size());
+
+ const safe_browsing::SwReporterInvocation& invocation =
+ launched_invocations_[0];
+ EXPECT_EQ(MakeTestFilePath(default_path_),
+ invocation.command_line.GetProgram());
+ EXPECT_TRUE(invocation.command_line.GetSwitches().empty());
+ EXPECT_TRUE(invocation.command_line.GetArgs().empty());
+ EXPECT_TRUE(invocation.suffix.empty());
+ EXPECT_FALSE(invocation.is_experimental);
+ }
+
// |ComponentReady| asserts that it is run on the UI thread, so we must
// create test threads before calling it.
content::TestBrowserThreadBundle threads_;
- // The traits object to test.
- SwReporterInstallerTraits traits_;
+ // Bound callback to the |SwReporterLaunched| method.
+ SwReporterRunner launched_callback_;
// Default parameters for |ComponentReady|.
base::Version default_version_;
@@ -68,10 +98,296 @@ class SwReporterInstallerTest : public ::testing::Test {
DISALLOW_COPY_AND_ASSIGN(SwReporterInstallerTest);
};
+// This class contains extended setup that is only used for tests of the
+// experimental reporter.
+class ExperimentalSwReporterInstallerTest : public SwReporterInstallerTest {
+ public:
+ ExperimentalSwReporterInstallerTest() {}
+
+ protected:
+ void CreateFeatureWithoutTag() {
+ std::map<std::string, std::string> params;
+ CreateFeatureWithParams(params);
+ }
+
+ void CreateFeatureWithTag(const std::string& tag) {
+ std::map<std::string, std::string> params;
+ params["tag"] = tag;
+ CreateFeatureWithParams(params);
+ }
+
+ void CreateFeatureWithParams(
+ const std::map<std::string, std::string>& params) {
+ // Assign the given variation params to the experiment group until
+ // |variations_| goes out of scope when the test exits. This will also
+ // create a FieldTrial for this group.
+ variations_ = std::make_unique<variations::testing::VariationParamsManager>(
+ kExperimentGroupName, params);
+
+ // Create a feature list containing only the field trial for this group,
+ // and enable it for the length of the test.
+ base::FieldTrial* trial = base::FieldTrialList::Find(kExperimentGroupName);
+ ASSERT_TRUE(trial);
+ auto feature_list = std::make_unique<base::FeatureList>();
+ feature_list->RegisterFieldTrialOverride(
+ kExperimentGroupName, base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+ trial);
+ scoped_feature_list_.InitWithFeatureList(std::move(feature_list));
+ }
+
+ std::unique_ptr<variations::testing::VariationParamsManager> variations_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+ base::HistogramTester histograms_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ExperimentalSwReporterInstallerTest);
+};
+
TEST_F(SwReporterInstallerTest, Default) {
- TestComponentReady(default_version_, default_path_);
+ SwReporterInstallerTraits traits(launched_callback_, false);
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_TRUE(attributes.empty());
+
+ traits.ComponentReady(default_version_, default_path_,
+ std::make_unique<base::DictionaryValue>());
+ ExpectDefaultInvocation();
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, NoExperimentConfig) {
+ // Even if the experiment is supported on this hardware, the user shouldn't
+ // be enrolled unless enabled through variations.
+ SwReporterInstallerTraits traits(launched_callback_, true);
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_TRUE(attributes.empty());
+
+ traits.ComponentReady(default_version_, default_path_,
+ std::make_unique<base::DictionaryValue>());
+ ExpectDefaultInvocation();
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, ExperimentUnsupported) {
+ // Even if the experiment config is enabled in variations, the user shouldn't
+ // be enrolled if the hardware doesn't support it.
+ SwReporterInstallerTraits traits(launched_callback_, false);
+ CreateFeatureWithTag("experiment_tag");
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_TRUE(attributes.empty());
+
+ traits.ComponentReady(default_version_, default_path_,
+ std::make_unique<base::DictionaryValue>());
+ ExpectDefaultInvocation();
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, ExperimentMissingTag) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithoutTag();
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("missing_tag", attributes["tag"]);
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_TAG, 1);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, ExperimentInvalidTag) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithTag("tag with invalid whitespace chars");
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("missing_tag", attributes["tag"]);
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_TAG, 1);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, ExperimentTagTooLong) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ std::string tag_too_long(500, 'x');
+ CreateFeatureWithTag(tag_too_long);
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("missing_tag", attributes["tag"]);
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_TAG, 1);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, ExperimentEmptyTag) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithTag("");
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("missing_tag", attributes["tag"]);
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_TAG, 1);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, SingleInvocation) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithTag("experiment_tag");
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("experiment_tag", attributes["tag"]);
+
+ static constexpr char kTestManifest[] =
+ "{\"launch_params\": ["
+ " {"
+ " \"arguments\": [\"--engine=experimental\", \"random argument\"],"
+ " \"suffix\": \"Experimental\""
+ " }"
+ "]}";
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+
+ // The SwReporter should be launched once with the given arguments.
+ EXPECT_EQ(default_version_, launched_version_);
+ ASSERT_EQ(1U, launched_invocations_.size());
+
+ const safe_browsing::SwReporterInvocation& invocation =
+ launched_invocations_[0];
+ EXPECT_EQ(MakeTestFilePath(default_path_),
+ invocation.command_line.GetProgram());
+ EXPECT_EQ(2U, invocation.command_line.GetSwitches().size());
+ EXPECT_EQ("experimental",
+ invocation.command_line.GetSwitchValueASCII("engine"));
+ EXPECT_EQ("Experimental",
+ invocation.command_line.GetSwitchValueASCII("registry-suffix"));
+ ASSERT_EQ(1U, invocation.command_line.GetArgs().size());
+ EXPECT_EQ(L"random argument", invocation.command_line.GetArgs()[0]);
+ EXPECT_EQ("Experimental", invocation.suffix);
+ EXPECT_TRUE(invocation.is_experimental);
+ histograms_.ExpectTotalCount("SoftwareReporter.ExperimentErrors", 0);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, MissingSuffix) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithTag("experiment_tag");
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("experiment_tag", attributes["tag"]);
+
+ static constexpr char kTestManifest[] =
+ "{\"launch_params\": ["
+ " {"
+ " \"arguments\": [\"--engine=experimental\"]"
+ " }"
+ "]}";
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+
+ // The SwReporter should not be launched, and an error should be logged.
+ EXPECT_TRUE(launched_invocations_.empty());
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_PARAMS, 1);
+
+ static constexpr char kTestManifest2[] =
+ "{\"launch_params\": ["
+ " {"
+ " \"suffix\": \"\","
+ " \"arguments\": [\"--engine=experimental\"]"
+ " }"
+ "]}";
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest2)));
+
+ // The SwReporter should not be launched, and an error should be logged.
+ EXPECT_TRUE(launched_invocations_.empty());
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_PARAMS, 2);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, MissingArguments) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithTag("experiment_tag");
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("experiment_tag", attributes["tag"]);
+
+ static constexpr char kTestManifest[] =
+ "{\"launch_params\": ["
+ " {"
+ " \"suffix\": \"Experimental\""
+ " }"
+ "]}";
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+
+ // The SwReporter should be launched once with no arguments except the
+ // suffix.
+ EXPECT_EQ(default_version_, launched_version_);
+ ASSERT_EQ(1U, launched_invocations_.size());
+
+ const safe_browsing::SwReporterInvocation& invocation =
+ launched_invocations_[0];
+ EXPECT_EQ(MakeTestFilePath(default_path_),
+ invocation.command_line.GetProgram());
+ EXPECT_EQ(1U, invocation.command_line.GetSwitches().size());
+ EXPECT_EQ("Experimental",
+ invocation.command_line.GetSwitchValueASCII("registry-suffix"));
+ EXPECT_TRUE(invocation.command_line.GetArgs().empty());
+ EXPECT_EQ("Experimental", invocation.suffix);
+ EXPECT_TRUE(invocation.is_experimental);
+ histograms_.ExpectTotalCount("SoftwareReporter.ExperimentErrors", 0);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, EmptyManifest) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithTag("experiment_tag");
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("experiment_tag", attributes["tag"]);
+
+ static constexpr char kTestManifest[] = "{}";
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+
+ // The SwReporter should not be launched, but no error should be logged.
+ // (This tests the case where a non-experimental version of the reporter,
+ // which does not have "launch_params" in its manifest, is already present.)
+ EXPECT_TRUE(launched_invocations_.empty());
+ histograms_.ExpectTotalCount("SoftwareReporter.ExperimentErrors", 0);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, EmptyLaunchParams) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithTag("experiment_tag");
- // The SwReporter should be launched exactly once, with no arguments.
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("experiment_tag", attributes["tag"]);
+
+ static constexpr char kTestManifest[] = "{\"launch_params\": []}";
+
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+
+ // The SwReporter should be launched once with no arguments and no suffix.
EXPECT_EQ(default_version_, launched_version_);
ASSERT_EQ(1U, launched_invocations_.size());
@@ -81,6 +397,116 @@ TEST_F(SwReporterInstallerTest, Default) {
invocation.command_line.GetProgram());
EXPECT_TRUE(invocation.command_line.GetSwitches().empty());
EXPECT_TRUE(invocation.command_line.GetArgs().empty());
+ EXPECT_TRUE(invocation.suffix.empty());
+ EXPECT_TRUE(invocation.is_experimental);
+ histograms_.ExpectTotalCount("SoftwareReporter.ExperimentErrors", 0);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, BadSuffix) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithTag("experiment_tag");
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("experiment_tag", attributes["tag"]);
+
+ static constexpr char kTestManifest[] =
+ "{\"launch_params\": ["
+ " {"
+ " \"arguments\": [\"--engine=experimental\"],"
+ " \"suffix\": \"invalid whitespace characters\""
+ " }"
+ "]}";
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+
+ // The SwReporter should not be launched, and an error should be logged.
+ EXPECT_TRUE(launched_invocations_.empty());
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_PARAMS, 1);
+
+ static constexpr char kTestManifest2[] =
+ "{\"launch_params\": ["
+ " {"
+ " \"arguments\": [\"--engine=experimental\"],"
+ " \"suffix\": \"%s\""
+ " }"
+ "]}";
+ std::string suffix_too_long(500, 'x');
+ std::string manifest =
+ base::StringPrintf(kTestManifest2, suffix_too_long.c_str());
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(manifest)));
+
+ // The SwReporter should not be launched, and an error should be logged.
+ EXPECT_TRUE(launched_invocations_.empty());
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_PARAMS, 2);
+}
+
+TEST_F(ExperimentalSwReporterInstallerTest, BadTypesInManifest) {
+ SwReporterInstallerTraits traits(launched_callback_, true);
+ CreateFeatureWithTag("experiment_tag");
+
+ update_client::InstallerAttributes attributes =
+ traits.GetInstallerAttributes();
+ EXPECT_EQ(1U, attributes.size());
+ EXPECT_EQ("experiment_tag", attributes["tag"]);
+
+ // This has a string instead of a list for "arguments".
+ static constexpr char kTestManifest[] =
+ "{\"launch_params\": ["
+ " {"
+ " \"arguments\": \"--engine=experimental\","
+ " \"suffix\": \"Experimental\""
+ " }"
+ "]}";
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest)));
+
+ // The SwReporter should not be launched, and an error should be logged.
+ EXPECT_TRUE(launched_invocations_.empty());
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_PARAMS, 1);
+
+ // This has the invocation parameters as direct children of "launch_params",
+ // instead of using a list.
+ static constexpr char kTestManifest2[] =
+ "{\"launch_params\": "
+ " {"
+ " \"arguments\": [\"--engine=experimental\"],"
+ " \"suffix\": \"Experimental\""
+ " }"
+ "}";
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest2)));
+
+ // The SwReporter should not be launched, and an error should be logged.
+ EXPECT_TRUE(launched_invocations_.empty());
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_PARAMS, 2);
+
+ // This has a list for suffix as well as for arguments.
+ static constexpr char kTestManifest3[] =
+ "{\"launch_params\": ["
+ " {"
+ " \"arguments\": [\"--engine=experimental\"],"
+ " \"suffix\": [\"Experimental\"]"
+ " }"
+ "]}";
+ traits.ComponentReady(
+ default_version_, default_path_,
+ base::DictionaryValue::From(base::JSONReader::Read(kTestManifest3)));
+
+ // The SwReporter should not be launched, and an error should be logged.
+ EXPECT_TRUE(launched_invocations_.empty());
+ histograms_.ExpectUniqueSample("SoftwareReporter.ExperimentErrors",
+ EXPERIMENT_ERROR_BAD_PARAMS, 3);
}
} // namespace component_updater

Powered by Google App Engine
This is Rietveld 408576698