diff options
-rw-r--r-- | base/base.gyp | 3 | ||||
-rw-r--r-- | base/test/test_reg_util_win.cc | 100 | ||||
-rw-r--r-- | base/test/test_reg_util_win.h | 55 | ||||
-rw-r--r-- | base/test/test_reg_util_win_unittest.cc | 130 | ||||
-rw-r--r-- | chrome/installer/gcapi/gcapi_test_registry_overrider.cc | 8 | ||||
-rw-r--r-- | chrome/installer/setup/setup_util_unittest.cc | 4 | ||||
-rw-r--r-- | chrome/installer/util/product_state_unittest.cc | 20 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.cc | 4 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.h | 4 | ||||
-rw-r--r-- | chrome_frame/test/util_unittests.cc | 4 |
10 files changed, 240 insertions, 92 deletions
diff --git a/base/base.gyp b/base/base.gyp index 551aa712..fb096b9 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -638,6 +638,7 @@ 'template_util_unittest.cc', 'test/expectations/expectation_unittest.cc', 'test/expectations/parser_unittest.cc', + 'test/test_reg_util_win_unittest.cc', 'test/trace_event_analyzer_unittest.cc', 'threading/non_thread_safe_unittest.cc', 'threading/platform_thread_unittest.cc', @@ -825,8 +826,6 @@ ['exclude', '^win/'], ], 'sources!': [ - 'debug/trace_event_win_unittest.cc', - 'time/time_win_unittest.cc', 'win/win_util_unittest.cc', ], }], diff --git a/base/test/test_reg_util_win.cc b/base/test/test_reg_util_win.cc index e23c6e9..f33fa61 100644 --- a/base/test/test_reg_util_win.cc +++ b/base/test/test_reg_util_win.cc @@ -4,23 +4,67 @@ #include "base/test/test_reg_util_win.h" +#include "base/guid.h" #include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" namespace registry_util { -const wchar_t RegistryOverrideManager::kTempTestKeyPath[] = - L"Software\\Chromium\\TempTestKeys"; +namespace { + +const wchar_t kTimestampDelimiter[] = L"$"; +const wchar_t kTempTestKeyPath[] = L"Software\\Chromium\\TempTestKeys"; + +void DeleteStaleTestKeys(const base::Time& now, const string16& test_key_root) { + base::win::RegKey test_root_key; + if (test_root_key.Open(HKEY_CURRENT_USER, + test_key_root.c_str(), + KEY_ALL_ACCESS) != ERROR_SUCCESS) { + // This will occur on first-run, but is harmless. + return; + } + + base::win::RegistryKeyIterator iterator_test_root_key(HKEY_CURRENT_USER, + test_key_root.c_str()); + for (; iterator_test_root_key.Valid(); ++iterator_test_root_key) { + string16 key_name = iterator_test_root_key.Name(); + std::vector<string16> tokens; + Tokenize(key_name, string16(kTimestampDelimiter), &tokens); + int64 key_name_as_number = 0; + + if (!base::StringToInt64(tokens[0], &key_name_as_number)) { + test_root_key.DeleteKey(key_name.c_str()); + continue; + } + + base::Time key_time = base::Time::FromInternalValue(key_name_as_number); + base::TimeDelta age = now - key_time; + + if (age > base::TimeDelta::FromHours(24)) + test_root_key.DeleteKey(key_name.c_str()); + } +} + +string16 GenerateTempKeyPath(const string16& test_key_root, + const base::Time& timestamp) { + string16 key_path = test_key_root; + key_path += L"\\" + base::Int64ToString16(timestamp.ToInternalValue()); + key_path += kTimestampDelimiter + base::ASCIIToWide(base::GenerateGUID()); + + return key_path; +} + +} // namespace RegistryOverrideManager::ScopedRegistryKeyOverride::ScopedRegistryKeyOverride( HKEY override, - const std::wstring& temp_name) - : override_(override), - temp_name_(temp_name) { - DCHECK(!temp_name_.empty()); - std::wstring key_path(RegistryOverrideManager::kTempTestKeyPath); - key_path += L"\\" + temp_name_; - EXPECT_EQ(ERROR_SUCCESS, + const string16& key_path) + : override_(override) { + EXPECT_EQ( + ERROR_SUCCESS, temp_key_.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS)); EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(override_, temp_key_.Handle())); @@ -29,37 +73,31 @@ RegistryOverrideManager::ScopedRegistryKeyOverride::ScopedRegistryKeyOverride( RegistryOverrideManager:: ScopedRegistryKeyOverride::~ScopedRegistryKeyOverride() { ::RegOverridePredefKey(override_, NULL); - // The temp key will be deleted via a call to DeleteAllTempKeys(). + temp_key_.DeleteKey(L""); } -RegistryOverrideManager::RegistryOverrideManager() { - DeleteAllTempKeys(); +RegistryOverrideManager::RegistryOverrideManager() + : timestamp_(base::Time::Now()), test_key_root_(kTempTestKeyPath) { + DeleteStaleTestKeys(timestamp_, test_key_root_); } -RegistryOverrideManager::~RegistryOverrideManager() { - RemoveAllOverrides(); +RegistryOverrideManager::RegistryOverrideManager(const base::Time& timestamp, + const string16& test_key_root) + : timestamp_(timestamp), test_key_root_(test_key_root) { + DeleteStaleTestKeys(timestamp_, test_key_root_); } -void RegistryOverrideManager::OverrideRegistry(HKEY override, - const std::wstring& temp_name) { - overrides_.push_back(new ScopedRegistryKeyOverride(override, temp_name)); -} +RegistryOverrideManager::~RegistryOverrideManager() {} -void RegistryOverrideManager::RemoveAllOverrides() { - while (!overrides_.empty()) { - delete overrides_.back(); - overrides_.pop_back(); - } - - DeleteAllTempKeys(); +void RegistryOverrideManager::OverrideRegistry( + HKEY override, + const string16& /*override_name*/) { + string16 key_path = GenerateTempKeyPath(test_key_root_, timestamp_); + overrides_.push_back(new ScopedRegistryKeyOverride(override, key_path)); } -// static -void RegistryOverrideManager::DeleteAllTempKeys() { - base::win::RegKey key; - if (key.Open(HKEY_CURRENT_USER, L"", KEY_ALL_ACCESS) == ERROR_SUCCESS) { - key.DeleteKey(kTempTestKeyPath); - } +string16 GenerateTempKeyPath() { + return GenerateTempKeyPath(string16(kTempTestKeyPath), base::Time::Now()); } } // namespace registry_util diff --git a/base/test/test_reg_util_win.h b/base/test/test_reg_util_win.h index b71831f..5315b66 100644 --- a/base/test/test_reg_util_win.h +++ b/base/test/test_reg_util_win.h @@ -7,57 +7,72 @@ // Registry utility functions used only by tests. -#include <string> -#include <vector> - #include "base/basictypes.h" +#include "base/memory/scoped_vector.h" +#include "base/strings/string16.h" +#include "base/time/time.h" #include "base/win/registry.h" namespace registry_util { // Allows a test to easily override registry hives so that it can start from a // known good state, or make sure to not leave any side effects once the test -// completes. +// completes. This supports parallel tests. All the overrides are scoped to the +// lifetime of the override manager. Destroy the manager to undo the overrides. +// +// Overridden hives use keys stored at, for instance: +// HKCU\Software\Chromium\TempTestKeys\ +// 13028145911617809$02AB211C-CF73-478D-8D91-618E11998AED +// The key path are comprises of: +// - The test key root, HKCU\Software\Chromium\TempTestKeys\ +// - The base::Time::ToInternalValue of the creation time. This is used to +// delete stale keys left over from crashed tests. +// - A GUID used for preventing name collisions (although unlikely) between +// two RegistryOverrideManagers created with the same timestamp. class RegistryOverrideManager { public: - // All overridden hives will be descendents of this registry path under the - // main HKCU hive. - static const wchar_t kTempTestKeyPath[]; - RegistryOverrideManager(); ~RegistryOverrideManager(); // Override the given registry hive using a temporary key named by temp_name - // under the temporary test key path. - void OverrideRegistry(HKEY override, const std::wstring& temp_name); - - // Deletes all temporary test keys used by the overrides. - static void DeleteAllTempKeys(); - - // Removes all overrides and deletes all temporary test keys used by the - // overrides. - void RemoveAllOverrides(); + // under the temporary test key path. There is no need to randomize + // |override_name|, as a random parent key is generated. Multiple overrides to + // the same hive are not supported and lead to undefined behavior. + void OverrideRegistry(HKEY override, const string16& override_name); private: + friend class RegistryOverrideManagerTest; + // Keeps track of one override. class ScopedRegistryKeyOverride { public: - ScopedRegistryKeyOverride(HKEY override, const std::wstring& temp_name); + ScopedRegistryKeyOverride(HKEY override, const string16& key_path); ~ScopedRegistryKeyOverride(); private: HKEY override_; base::win::RegKey temp_key_; - std::wstring temp_name_; DISALLOW_COPY_AND_ASSIGN(ScopedRegistryKeyOverride); }; - std::vector<ScopedRegistryKeyOverride*> overrides_; + // Used for testing only. + RegistryOverrideManager(const base::Time& timestamp, + const string16& test_key_root); + + base::Time timestamp_; + string16 guid_; + + string16 test_key_root_; + ScopedVector<ScopedRegistryKeyOverride> overrides_; DISALLOW_COPY_AND_ASSIGN(RegistryOverrideManager); }; +// Generates a temporary key path that will be eventually deleted +// automatically if the process crashes. +string16 GenerateTempKeyPath(); + } // namespace registry_util #endif // BASE_TEST_TEST_REG_UTIL_H_ diff --git a/base/test/test_reg_util_win_unittest.cc b/base/test/test_reg_util_win_unittest.cc new file mode 100644 index 0000000..25f341f --- /dev/null +++ b/base/test/test_reg_util_win_unittest.cc @@ -0,0 +1,130 @@ +// Copyright 2013 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 "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" +#include "base/test/test_reg_util_win.h" +#include "base/time/time.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace registry_util { + +namespace { +const wchar_t kTestKeyPath[] = L"Software\\Chromium\\Foo\\Baz\\TestKey"; +const wchar_t kTestValueName[] = L"TestValue"; +} // namespace + +class RegistryOverrideManagerTest : public testing::Test { + protected: + RegistryOverrideManagerTest() { + // We assign a fake test key path to our test RegistryOverrideManager + // so we don't interfere with any actual RegistryOverrideManagers running + // on the system. This fake path will be auto-deleted by other + // RegistryOverrideManagers in case we crash. + fake_test_key_root_ = registry_util::GenerateTempKeyPath(); + + // Ensure a clean test environment. + base::win::RegKey key(HKEY_CURRENT_USER); + key.DeleteKey(fake_test_key_root_.c_str()); + key.DeleteKey(kTestKeyPath); + } + + virtual ~RegistryOverrideManagerTest() { + base::win::RegKey key(HKEY_CURRENT_USER); + key.DeleteKey(fake_test_key_root_.c_str()); + } + + void AssertKeyExists(const string16& key_path) { + base::win::RegKey key; + ASSERT_EQ(ERROR_SUCCESS, + key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ)) + << key_path << " does not exist."; + } + + void AssertKeyAbsent(const string16& key_path) { + base::win::RegKey key; + ASSERT_NE(ERROR_SUCCESS, + key.Open(HKEY_CURRENT_USER, key_path.c_str(), KEY_READ)) + << key_path << " exists but it should not."; + } + + void CreateKey(const string16& key_path) { + base::win::RegKey key; + EXPECT_EQ(ERROR_SUCCESS, + key.Create(HKEY_CURRENT_USER, key_path.c_str(), KEY_ALL_ACCESS)); + } + + string16 FakeOverrideManagerPath(const base::Time& time) { + return fake_test_key_root_ + L"\\" + + base::Int64ToString16(time.ToInternalValue()); + } + + void CreateManager(const base::Time& timestamp) { + manager_.reset(new RegistryOverrideManager(timestamp, fake_test_key_root_)); + manager_->OverrideRegistry(HKEY_CURRENT_USER, L"override_manager_unittest"); + } + + string16 fake_test_key_root_; + scoped_ptr<RegistryOverrideManager> manager_; +}; + +TEST_F(RegistryOverrideManagerTest, Basic) { + CreateManager(base::Time::Now()); + + base::win::RegKey create_key; + EXPECT_EQ(ERROR_SUCCESS, + create_key.Create(HKEY_CURRENT_USER, kTestKeyPath, KEY_ALL_ACCESS)); + EXPECT_TRUE(create_key.Valid()); + EXPECT_EQ(ERROR_SUCCESS, create_key.WriteValue(kTestValueName, 42)); + create_key.Close(); + + AssertKeyExists(kTestKeyPath); + + DWORD value; + base::win::RegKey read_key; + EXPECT_EQ(ERROR_SUCCESS, + read_key.Open(HKEY_CURRENT_USER, kTestKeyPath, KEY_READ)); + EXPECT_TRUE(read_key.Valid()); + EXPECT_EQ(ERROR_SUCCESS, read_key.ReadValueDW(kTestValueName, &value)); + EXPECT_EQ(42, value); + read_key.Close(); + + manager_.reset(); + + AssertKeyAbsent(kTestKeyPath); +} + +TEST_F(RegistryOverrideManagerTest, DeleteStaleKeys) { + base::Time::Exploded kTestTimeExploded = {2013, 11, 1, 4, 0, 0, 0, 0}; + base::Time kTestTime = base::Time::FromUTCExploded(kTestTimeExploded); + + string16 path_garbage = fake_test_key_root_ + L"\\Blah"; + string16 path_very_stale = + FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(100)); + string16 path_stale = + FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromDays(5)); + string16 path_current = + FakeOverrideManagerPath(kTestTime - base::TimeDelta::FromMinutes(1)); + string16 path_future = + FakeOverrideManagerPath(kTestTime + base::TimeDelta::FromMinutes(1)); + + CreateKey(path_garbage); + CreateKey(path_very_stale); + CreateKey(path_stale); + CreateKey(path_current); + CreateKey(path_future); + + CreateManager(kTestTime); + manager_.reset(); + + AssertKeyAbsent(path_garbage); + AssertKeyAbsent(path_very_stale); + AssertKeyAbsent(path_stale); + AssertKeyExists(path_current); + AssertKeyExists(path_future); +} + +} // namespace registry_util diff --git a/chrome/installer/gcapi/gcapi_test_registry_overrider.cc b/chrome/installer/gcapi/gcapi_test_registry_overrider.cc index 2df337f..be678a2 100644 --- a/chrome/installer/gcapi/gcapi_test_registry_overrider.cc +++ b/chrome/installer/gcapi/gcapi_test_registry_overrider.cc @@ -11,12 +11,8 @@ GCAPITestRegistryOverrider::GCAPITestRegistryOverrider() { // Override keys - this is undone during destruction. - string16 hkcu_override = base::StringPrintf( - L"hkcu_override\\%ls", ASCIIToWide(base::GenerateGUID())); - override_manager_.OverrideRegistry(HKEY_CURRENT_USER, hkcu_override); - string16 hklm_override = base::StringPrintf( - L"hklm_override\\%ls", ASCIIToWide(base::GenerateGUID())); - override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE, hklm_override); + override_manager_.OverrideRegistry(HKEY_CURRENT_USER, L"hkcu_override"); + override_manager_.OverrideRegistry(HKEY_LOCAL_MACHINE, L"hklm_override"); } GCAPITestRegistryOverrider::~GCAPITestRegistryOverrider() { diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc index 0391e3a..647d90f 100644 --- a/chrome/installer/setup/setup_util_unittest.cc +++ b/chrome/installer/setup/setup_util_unittest.cc @@ -410,10 +410,6 @@ class MigrateMultiToSingleTest : public testing::Test { L"MigrateMultiToSingleTest"); } - virtual void TearDown() OVERRIDE { - registry_override_manager_.RemoveAllOverrides(); - } - static const bool kSystemLevel = false; static const HKEY kRootKey; static const wchar_t kVersionString[]; diff --git a/chrome/installer/util/product_state_unittest.cc b/chrome/installer/util/product_state_unittest.cc index 4946f0a..42c4a99 100644 --- a/chrome/installer/util/product_state_unittest.cc +++ b/chrome/installer/util/product_state_unittest.cc @@ -31,15 +31,14 @@ class ProductStateTest : public testing::Test { void MinimallyInstallProduct(const wchar_t* version); static BrowserDistribution* dist_; - static std::wstring temp_key_path_; bool system_install_; HKEY overridden_; + registry_util::RegistryOverrideManager registry_override_manager_; RegKey clients_; RegKey client_state_; }; BrowserDistribution* ProductStateTest::dist_; -std::wstring ProductStateTest::temp_key_path_; // static void ProductStateTest::SetUpTestCase() { @@ -48,16 +47,10 @@ void ProductStateTest::SetUpTestCase() { // We'll use Chrome as our test subject. dist_ = BrowserDistribution::GetSpecificDistribution( BrowserDistribution::CHROME_BROWSER); - - // And we'll play in HKCU here: - temp_key_path_.assign(RegistryOverrideManager::kTempTestKeyPath) - .append(1, L'\\') - .append(L"ProductStateTest"); } // static void ProductStateTest::TearDownTestCase() { - temp_key_path_.clear(); dist_ = NULL; testing::Test::TearDownTestCase(); @@ -73,11 +66,8 @@ void ProductStateTest::SetUp() { // Override for test purposes. We don't use ScopedRegistryKeyOverride // directly because it doesn't suit itself to our use here. RegKey temp_key; - EXPECT_EQ(ERROR_SUCCESS, - temp_key.Create(HKEY_CURRENT_USER, temp_key_path_.c_str(), - KEY_ALL_ACCESS)); - EXPECT_EQ(ERROR_SUCCESS, - ::RegOverridePredefKey(overridden_, temp_key.Handle())); + + registry_override_manager_.OverrideRegistry(overridden_, L"ProductStateTest"); EXPECT_EQ(ERROR_SUCCESS, clients_.Create(overridden_, dist_->GetVersionKey().c_str(), @@ -91,13 +81,9 @@ void ProductStateTest::TearDown() { // Done with the keys. client_state_.Close(); clients_.Close(); - EXPECT_EQ(ERROR_SUCCESS, ::RegOverridePredefKey(overridden_, NULL)); overridden_ = NULL; system_install_ = false; - // Shotgun approach to clearing out data we may have written. - RegistryOverrideManager::DeleteAllTempKeys(); - testing::Test::TearDown(); } diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc index 298a7c2..6c7fb48 100644 --- a/chrome_frame/test/chrome_frame_test_utils.cc +++ b/chrome_frame/test/chrome_frame_test_utils.cc @@ -679,10 +679,6 @@ ScopedVirtualizeHklmAndHkcu::ScopedVirtualizeHklmAndHkcu() { ScopedVirtualizeHklmAndHkcu::~ScopedVirtualizeHklmAndHkcu() { } -void ScopedVirtualizeHklmAndHkcu::RemoveAllOverrides() { - override_manager_.RemoveAllOverrides(); -} - bool KillProcesses(const std::wstring& executable_name, int exit_code, bool wait) { bool result = true; diff --git a/chrome_frame/test/chrome_frame_test_utils.h b/chrome_frame/test/chrome_frame_test_utils.h index f9c08e2..316d57c 100644 --- a/chrome_frame/test/chrome_frame_test_utils.h +++ b/chrome_frame/test/chrome_frame_test_utils.h @@ -338,10 +338,6 @@ class ScopedVirtualizeHklmAndHkcu { ScopedVirtualizeHklmAndHkcu(); ~ScopedVirtualizeHklmAndHkcu(); - // Removes all overrides and deletes all temporary test keys used by the - // overrides. - void RemoveAllOverrides(); - protected: registry_util::RegistryOverrideManager override_manager_; }; diff --git a/chrome_frame/test/util_unittests.cc b/chrome_frame/test/util_unittests.cc index e6dbd65..74e41f9 100644 --- a/chrome_frame/test/util_unittests.cc +++ b/chrome_frame/test/util_unittests.cc @@ -34,10 +34,6 @@ class UtilTests : public testing::Test { DeleteAllSingletons(); } - void TearDown() { - registry_virtualization_.RemoveAllOverrides(); - } - // This is used to manage life cycle of PolicySettings singleton. // base::ShadowingAtExitManager at_exit_manager_; chrome_frame_test::ScopedVirtualizeHklmAndHkcu registry_virtualization_; |