summaryrefslogtreecommitdiffstats
path: root/chrome/installer/setup
diff options
context:
space:
mode:
authorgab <gab@chromium.org>2015-07-13 10:55:05 -0700
committerCommit bot <commit-bot@chromium.org>2015-07-13 17:56:00 +0000
commit3861555fdf3bd6238cb177b66a83ac34fe06752e (patch)
treef4640ecb67400fc247201549775897566339fafc /chrome/installer/setup
parentd46fb2c684affce12b619a432ec0c2ba3b0518cc (diff)
downloadchromium_src-3861555fdf3bd6238cb177b66a83ac34fe06752e.zip
chromium_src-3861555fdf3bd6238cb177b66a83ac34fe06752e.tar.gz
chromium_src-3861555fdf3bd6238cb177b66a83ac34fe06752e.tar.bz2
Introduce UpdateActiveSetupVersionWorkItem
A cleaner solution coming out of an attempt to support two similar use cases differently in https://codereview.chromium.org/1213913002/ and https://codereview.chromium.org/1214163008/. Actual use cases implemented in a follow-up CL (https://codereview.chromium.org/1223933005/). BUG=488247, 502363 TEST=setup_unittests.exe --gtest_filter=UpdateActiveSetupVersionWorkItemTest* Review URL: https://codereview.chromium.org/1223953003 Cr-Commit-Position: refs/heads/master@{#338528}
Diffstat (limited to 'chrome/installer/setup')
-rw-r--r--chrome/installer/setup/BUILD.gn3
-rw-r--r--chrome/installer/setup/update_active_setup_version_work_item.cc73
-rw-r--r--chrome/installer/setup/update_active_setup_version_work_item.h66
-rw-r--r--chrome/installer/setup/update_active_setup_version_work_item_unittest.cc153
4 files changed, 295 insertions, 0 deletions
diff --git a/chrome/installer/setup/BUILD.gn b/chrome/installer/setup/BUILD.gn
index 449f16f..5809a9d 100644
--- a/chrome/installer/setup/BUILD.gn
+++ b/chrome/installer/setup/BUILD.gn
@@ -39,6 +39,9 @@ if (is_win) {
"setup_util.cc",
"setup_util_unittest.cc",
"setup_util_unittest.h",
+ "update_active_setup_version_work_item.cc", # Move to lib
+ "update_active_setup_version_work_item.h", # Move to lib
+ "update_active_setup_version_work_item_unittest.cc",
]
deps = [
diff --git a/chrome/installer/setup/update_active_setup_version_work_item.cc b/chrome/installer/setup/update_active_setup_version_work_item.cc
new file mode 100644
index 0000000..4d35494
--- /dev/null
+++ b/chrome/installer/setup/update_active_setup_version_work_item.cc
@@ -0,0 +1,73 @@
+// Copyright 2015 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 "chrome/installer/setup/update_active_setup_version_work_item.h"
+
+#include <stdint.h>
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+namespace {
+
+// The major version and first component of the version identifying the work
+// done by setup.exe --configure-user-settings on user login by way of Active
+// Setup. Increase this value if the work done when handling Active Setup
+// should be executed again for all existing users.
+const base::char16 kActiveSetupMajorVersion[] = L"43";
+
+} // namespace
+
+UpdateActiveSetupVersionWorkItem::UpdateActiveSetupVersionWorkItem(
+ const base::string16& active_setup_path,
+ Operation operation)
+ : set_reg_value_work_item_(
+ HKEY_LOCAL_MACHINE,
+ active_setup_path,
+ WorkItem::kWow64Default,
+ L"Version",
+ base::Bind(
+ &UpdateActiveSetupVersionWorkItem::GetUpdatedActiveSetupVersion,
+ base::Unretained(this))),
+ operation_(operation) {
+}
+
+bool UpdateActiveSetupVersionWorkItem::Do() {
+ return set_reg_value_work_item_.Do();
+}
+
+void UpdateActiveSetupVersionWorkItem::Rollback() {
+ set_reg_value_work_item_.Rollback();
+}
+
+base::string16 UpdateActiveSetupVersionWorkItem::GetUpdatedActiveSetupVersion(
+ const base::string16& existing_version) {
+ std::vector<base::string16> version_components = base::SplitString(
+ existing_version, L",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+ // If |existing_version| was empty or otherwise corrupted, turn it into a
+ // valid one.
+ if (version_components.size() != 4U)
+ version_components.assign(4U, L"0");
+
+ // Unconditionally update the major version.
+ version_components[MAJOR] = kActiveSetupMajorVersion;
+
+ if (operation_ == UPDATE_AND_BUMP_OS_UPGRADES_COMPONENT) {
+ uint32_t previous_value;
+ if (!base::StringToUint(version_components[OS_UPGRADES], &previous_value)) {
+ LOG(WARNING) << "Couldn't process previous OS_UPGRADES Active Setup "
+ "version component: " << version_components[OS_UPGRADES];
+ previous_value = 0;
+ }
+ version_components[OS_UPGRADES] = base::UintToString16(previous_value + 1);
+ }
+
+ return JoinString(version_components, L',');
+}
diff --git a/chrome/installer/setup/update_active_setup_version_work_item.h b/chrome/installer/setup/update_active_setup_version_work_item.h
new file mode 100644
index 0000000..03aec44
--- /dev/null
+++ b/chrome/installer/setup/update_active_setup_version_work_item.h
@@ -0,0 +1,66 @@
+// Copyright 2015 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.
+
+#ifndef CHROME_INSTALLER_SETUP_UPDATE_ACTIVE_SETUP_VERSION_WORK_ITEM_H_
+#define CHROME_INSTALLER_SETUP_UPDATE_ACTIVE_SETUP_VERSION_WORK_ITEM_H_
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "chrome/installer/util/set_reg_value_work_item.h"
+#include "chrome/installer/util/work_item.h"
+
+// A WorkItem that updates (or installs if not present) the Active Setup
+// "Version" field in the registry. Optionally bumping the OS_UPGRADES component
+// on demand. This WorkItem is only viable on machine-wide installs.
+class UpdateActiveSetupVersionWorkItem : public WorkItem {
+ public:
+ // The operation to be performed by this UpdateActiveSetupVersionWorkItem.
+ enum Operation {
+ // Update (or install if not present) the Active Setup "Version" in the
+ // registry.
+ UPDATE,
+ // Also bump the OS_UPGRADES component on top of updating the version
+ // (will default to 1 if the version was absent or invalid).
+ UPDATE_AND_BUMP_OS_UPGRADES_COMPONENT,
+ };
+
+ // Constructs an UpdateActiveSetupVersionWorkItem that will perform
+ // |operation| on the |active_setup_path| key in the registry. This key needs
+ // to exist when this WorkItem is ran.
+ UpdateActiveSetupVersionWorkItem(const base::string16& active_setup_path,
+ Operation operation);
+
+ // Overriden from WorkItem.
+ bool Do() override;
+ void Rollback() override;
+
+ private:
+ // The components of the Active Setup Version entry, in order.
+ enum ActiveSetupVersionComponent {
+ // The major version.
+ MAJOR,
+ // Unused component, always 0 for now.
+ UNUSED1,
+ // Number of OS upgrades handled since original install.
+ OS_UPGRADES,
+ // Unused component, always 0 for now.
+ UNUSED2,
+ };
+
+ // Returns the updated Active Setup version to be used based on the
+ // |existing_version|.
+ base::string16 GetUpdatedActiveSetupVersion(
+ const base::string16& existing_version);
+
+ // The underlying WorkItem re-used to operate forward and backward on the
+ // registry.
+ SetRegValueWorkItem set_reg_value_work_item_;
+
+ // The Operation to be performed by this WorkItem when executed.
+ const Operation operation_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateActiveSetupVersionWorkItem);
+};
+
+#endif // CHROME_INSTALLER_SETUP_UPDATE_ACTIVE_SETUP_VERSION_WORK_ITEM_H_
diff --git a/chrome/installer/setup/update_active_setup_version_work_item_unittest.cc b/chrome/installer/setup/update_active_setup_version_work_item_unittest.cc
new file mode 100644
index 0000000..bf3ca46
--- /dev/null
+++ b/chrome/installer/setup/update_active_setup_version_work_item_unittest.cc
@@ -0,0 +1,153 @@
+// Copyright 2015 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 "chrome/installer/setup/update_active_setup_version_work_item.h"
+
+#include <windows.h>
+
+#include <ostream>
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/win/registry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::ValuesIn;
+
+namespace {
+
+const HKEY kActiveSetupRoot = HKEY_LOCAL_MACHINE;
+const base::char16 kActiveSetupPath[] = L"Active Setup\\test";
+
+struct UpdateActiveSetupVersionWorkItemTestCase {
+ // The initial value to be set in the registry prior to executing the
+ // UpdateActiveSetupVersionWorkItem. No value will be set if this null.
+ const wchar_t* initial_value;
+
+ // Whether to ask the UpdateActiveSetupVersionWorkItem to bump the OS_UPGRADES
+ // component of the Active Setup version.
+ bool bump_os_upgrades_component;
+
+ // The expected value after executing the UpdateActiveSetupVersionWorkItem.
+ const wchar_t* expected_result;
+} const kUpdateActiveSetupVersionWorkItemTestCases[] = {
+ // Initial install.
+ {nullptr, false, L"43,0,0,0"},
+ // No-op update.
+ {L"43.0.0.0", false, L"43,0,0,0"},
+ // Update only major component.
+ {L"24,1,2,3", false, L"43,1,2,3"},
+ // Reset from bogus value.
+ {L"zzz", false, L"43,0,0,0"},
+ // Reset from invalid version (too few components).
+ {L"1,2", false, L"43,0,0,0"},
+ // Reset from invalid version (too many components).
+ {L"43,1,2,3,10", false, L"43,0,0,0"},
+ // Reset from empty string.
+ {L"", false, L"43,0,0,0"},
+
+ // Same tests with an OS_UPGRADES component bump.
+ {nullptr, true, L"43,0,1,0"},
+ {L"43.0.0.0", true, L"43,0,1,0"},
+ {L"24,1,2,3", true, L"43,1,3,3"},
+ {L"zzz", true, L"43,0,1,0"},
+ {L"1,2", true, L"43,0,1,0"},
+ {L"43,1,2,3,10", true, L"43,0,1,0"},
+ {L"", true, L"43,0,1,0"},
+ // Bumping a negative OS upgrade component should result in it being
+ // reset and subsequently bumped to 1 as usual.
+ {L"43,11,-123,33", true, L"43,11,1,33"},
+};
+
+// Implements PrintTo in order for gtest to be able to print the problematic
+// UpdateActiveSetupVersionWorkItemTestCase on failure.
+void PrintTo(const UpdateActiveSetupVersionWorkItemTestCase& test_case,
+ ::std::ostream* os) {
+ *os << "Initial value: "
+ << (test_case.initial_value ? test_case.initial_value : L"(empty)")
+ << ", bump_os_upgrades_component: "
+ << test_case.bump_os_upgrades_component
+ << ", expected result: " << test_case.expected_result;
+}
+
+} // namespace
+
+class UpdateActiveSetupVersionWorkItemTest
+ : public testing::TestWithParam<UpdateActiveSetupVersionWorkItemTestCase> {
+ public:
+ UpdateActiveSetupVersionWorkItemTest() {}
+
+ void SetUp() override {
+ registry_override_manager_.OverrideRegistry(kActiveSetupRoot);
+ }
+
+ private:
+ registry_util::RegistryOverrideManager registry_override_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(UpdateActiveSetupVersionWorkItemTest);
+};
+
+TEST_P(UpdateActiveSetupVersionWorkItemTest, Execute) {
+ // Get the parametrized |test_case| which defines 5 steps:
+ // 1) Maybe set an initial Active Setup version in the registry according to
+ // |test_case.initial_value|.
+ // 2) Declare the work to be done by the UpdateActiveSetupVersionWorkItem
+ // based on |test_case.bump_os_upgrades_component|.
+ // 3) Unconditionally execute the Active Setup work items.
+ // 4) Verify that the updated Active Setup version is as expected by
+ // |test_case.expected_result|.
+ // 5) Rollback and verify that |test_case.initial_value| is back.
+ const UpdateActiveSetupVersionWorkItemTestCase& test_case = GetParam();
+
+ base::win::RegKey test_key;
+
+ ASSERT_EQ(ERROR_FILE_NOT_FOUND,
+ test_key.Open(kActiveSetupRoot, kActiveSetupPath, KEY_READ));
+
+ UpdateActiveSetupVersionWorkItem active_setup_work_item(
+ kActiveSetupPath, test_case.bump_os_upgrades_component
+ ? UpdateActiveSetupVersionWorkItem::
+ UPDATE_AND_BUMP_OS_UPGRADES_COMPONENT
+ : UpdateActiveSetupVersionWorkItem::UPDATE);
+
+ // Create the key and set the |initial_value| *after* the WorkItem to confirm
+ // that all of the work is done when executing the item, not when creating it.
+ ASSERT_EQ(ERROR_SUCCESS,
+ test_key.Create(kActiveSetupRoot, kActiveSetupPath, KEY_SET_VALUE));
+ if (test_case.initial_value) {
+ ASSERT_EQ(ERROR_SUCCESS,
+ test_key.WriteValue(L"Version", test_case.initial_value));
+ }
+
+ EXPECT_TRUE(active_setup_work_item.Do());
+
+ {
+ base::string16 version_out;
+ EXPECT_EQ(ERROR_SUCCESS, test_key.Open(kActiveSetupRoot, kActiveSetupPath,
+ KEY_QUERY_VALUE));
+ EXPECT_EQ(ERROR_SUCCESS, test_key.ReadValue(L"Version", &version_out));
+ EXPECT_EQ(test_case.expected_result, version_out);
+ }
+
+ active_setup_work_item.Rollback();
+
+ {
+ EXPECT_EQ(ERROR_SUCCESS, test_key.Open(kActiveSetupRoot, kActiveSetupPath,
+ KEY_QUERY_VALUE));
+
+ base::string16 version_out;
+ LONG read_result = test_key.ReadValue(L"Version", &version_out);
+ if (test_case.initial_value) {
+ EXPECT_EQ(ERROR_SUCCESS, read_result);
+ EXPECT_EQ(test_case.initial_value, version_out);
+ } else {
+ EXPECT_EQ(ERROR_FILE_NOT_FOUND, read_result);
+ }
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(UpdateActiveSetupVersionWorkItemTestInstance,
+ UpdateActiveSetupVersionWorkItemTest,
+ ValuesIn(kUpdateActiveSetupVersionWorkItemTestCases));