setup_util_unittest.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
15267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// found in the LICENSE file. 45267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 55267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "chrome/installer/setup/setup_util_unittest.h" 65267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 75267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <windows.h> 85267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 95267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include <string> 105267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 115267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/command_line.h" 125267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/file_util.h" 135267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/files/scoped_temp_dir.h" 145267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 155267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/process/kill.h" 165267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/process/launch.h" 175267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/process/process_handle.h" 185267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/test/test_reg_util_win.h" 195267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/threading/platform_thread.h" 205267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/time/time.h" 215267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/version.h" 225267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/win/scoped_handle.h" 235267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "base/win/windows_version.h" 245267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "chrome/installer/setup/setup_util.h" 255267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "chrome/installer/setup/setup_constants.h" 265267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "chrome/installer/util/google_update_constants.h" 275267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "chrome/installer/util/installation_state.h" 285267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "chrome/installer/util/installer_state.h" 295267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "chrome/installer/util/util_constants.h" 305267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 315267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 325267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)namespace { 335267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 345267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)class SetupUtilTestWithDir : public testing::Test { 355267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) protected: 365267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) virtual void SetUp() OVERRIDE { 37c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) // Create a temp directory for testing. 385267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) ASSERT_TRUE(test_dir_.CreateUniqueTempDir()); 395267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) } 405267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 415267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) virtual void TearDown() OVERRIDE { 425267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) // Clean up test directory manually so we can fail if it leaks. 435267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) ASSERT_TRUE(test_dir_.Delete()); 445267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) } 455267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 465267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) // The temporary directory used to contain the test operations. 475267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) base::ScopedTempDir test_dir_; 4806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles)}; 495267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 5009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// The privilege tested in ScopeTokenPrivilege tests below. 5109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// Use SE_RESTORE_NAME as it is one of the many privileges that is available, 5209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// but not enabled by default on processes running at high integrity. 5309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static const wchar_t kTestedPrivilege[] = SE_RESTORE_NAME; 5409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) 555267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles)// Returns true if the current process' token has privilege |privilege_name| 5609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)// enabled. 5709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)bool CurrentProcessHasPrivilege(const wchar_t* privilege_name) { 585267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) HANDLE temp_handle; 595267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) if (!::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, 605267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) &temp_handle)) { 615267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) ADD_FAILURE(); 625267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) return false; 635267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) } 645267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 6509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) base::win::ScopedHandle token(temp_handle); 6609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) 672fb29a03d7c71253319f61b77edc6c1e3a8fc8e2Torne (Richard Coles) // First get the size of the buffer needed for |privileges| below. 682fb29a03d7c71253319f61b77edc6c1e3a8fc8e2Torne (Richard Coles) DWORD size; 699e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles) EXPECT_FALSE(::GetTokenInformation(token, TokenPrivileges, NULL, 0, &size)); 702fb29a03d7c71253319f61b77edc6c1e3a8fc8e2Torne (Richard Coles) 712fb29a03d7c71253319f61b77edc6c1e3a8fc8e2Torne (Richard Coles) scoped_ptr<BYTE[]> privileges_bytes(new BYTE[size]); 729e12abdf8c3a23d52091ea54ebb6a04d327f9300Torne (Richard Coles) TOKEN_PRIVILEGES* privileges = 7309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) reinterpret_cast<TOKEN_PRIVILEGES*>(privileges_bytes.get()); 7409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles) 755267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) if (!::GetTokenInformation(token, TokenPrivileges, privileges, size, &size)) { 765267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) ADD_FAILURE(); 7751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) return false; 785267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) } 795267f701546148b83dfbe1d151cb184385bb5c22Torne (Richard Coles) 80 // There is no point getting a buffer to store more than |privilege_name|\0 as 81 // anything longer will obviously not be equal to |privilege_name|. 82 const DWORD desired_size = wcslen(privilege_name); 83 const DWORD buffer_size = desired_size + 1; 84 scoped_ptr<wchar_t[]> name_buffer(new wchar_t[buffer_size]); 85 for (int i = privileges->PrivilegeCount - 1; i >= 0 ; --i) { 86 LUID_AND_ATTRIBUTES& luid_and_att = privileges->Privileges[i]; 87 DWORD size = buffer_size; 88 ::LookupPrivilegeName(NULL, &luid_and_att.Luid, name_buffer.get(), &size); 89 if (size == desired_size && 90 wcscmp(name_buffer.get(), privilege_name) == 0) { 91 return luid_and_att.Attributes == SE_PRIVILEGE_ENABLED; 92 } 93 } 94 return false; 95} 96 97} // namespace 98 99// Test that we are parsing Chrome version correctly. 100TEST_F(SetupUtilTestWithDir, GetMaxVersionFromArchiveDirTest) { 101 // Create a version dir 102 base::FilePath chrome_dir = test_dir_.path().AppendASCII("1.0.0.0"); 103 base::CreateDirectory(chrome_dir); 104 ASSERT_TRUE(base::PathExists(chrome_dir)); 105 scoped_ptr<Version> version( 106 installer::GetMaxVersionFromArchiveDir(test_dir_.path())); 107 ASSERT_EQ(version->GetString(), "1.0.0.0"); 108 109 base::DeleteFile(chrome_dir, true); 110 ASSERT_FALSE(base::PathExists(chrome_dir)); 111 ASSERT_TRUE(installer::GetMaxVersionFromArchiveDir(test_dir_.path()) == NULL); 112 113 chrome_dir = test_dir_.path().AppendASCII("ABC"); 114 base::CreateDirectory(chrome_dir); 115 ASSERT_TRUE(base::PathExists(chrome_dir)); 116 ASSERT_TRUE(installer::GetMaxVersionFromArchiveDir(test_dir_.path()) == NULL); 117 118 chrome_dir = test_dir_.path().AppendASCII("2.3.4.5"); 119 base::CreateDirectory(chrome_dir); 120 ASSERT_TRUE(base::PathExists(chrome_dir)); 121 version.reset(installer::GetMaxVersionFromArchiveDir(test_dir_.path())); 122 ASSERT_EQ(version->GetString(), "2.3.4.5"); 123 124 // Create multiple version dirs, ensure that we select the greatest. 125 chrome_dir = test_dir_.path().AppendASCII("9.9.9.9"); 126 base::CreateDirectory(chrome_dir); 127 ASSERT_TRUE(base::PathExists(chrome_dir)); 128 chrome_dir = test_dir_.path().AppendASCII("1.1.1.1"); 129 base::CreateDirectory(chrome_dir); 130 ASSERT_TRUE(base::PathExists(chrome_dir)); 131 132 version.reset(installer::GetMaxVersionFromArchiveDir(test_dir_.path())); 133 ASSERT_EQ(version->GetString(), "9.9.9.9"); 134} 135 136TEST_F(SetupUtilTestWithDir, DeleteFileFromTempProcess) { 137 base::FilePath test_file; 138 base::CreateTemporaryFileInDir(test_dir_.path(), &test_file); 139 ASSERT_TRUE(base::PathExists(test_file)); 140 base::WriteFile(test_file, "foo", 3); 141 EXPECT_TRUE(installer::DeleteFileFromTempProcess(test_file, 0)); 142 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(200)); 143 EXPECT_FALSE(base::PathExists(test_file)); 144} 145 146// Note: This test is only valid when run at high integrity (i.e. it will fail 147// at medium integrity). 148TEST(SetupUtilTest, ScopedTokenPrivilegeBasic) { 149 ASSERT_FALSE(CurrentProcessHasPrivilege(kTestedPrivilege)); 150 151 { 152 installer::ScopedTokenPrivilege test_scoped_privilege(kTestedPrivilege); 153 ASSERT_TRUE(test_scoped_privilege.is_enabled()); 154 ASSERT_TRUE(CurrentProcessHasPrivilege(kTestedPrivilege)); 155 } 156 157 ASSERT_FALSE(CurrentProcessHasPrivilege(kTestedPrivilege)); 158} 159 160// Note: This test is only valid when run at high integrity (i.e. it will fail 161// at medium integrity). 162TEST(SetupUtilTest, ScopedTokenPrivilegeAlreadyEnabled) { 163 ASSERT_FALSE(CurrentProcessHasPrivilege(kTestedPrivilege)); 164 165 { 166 installer::ScopedTokenPrivilege test_scoped_privilege(kTestedPrivilege); 167 ASSERT_TRUE(test_scoped_privilege.is_enabled()); 168 ASSERT_TRUE(CurrentProcessHasPrivilege(kTestedPrivilege)); 169 { 170 installer::ScopedTokenPrivilege dup_scoped_privilege(kTestedPrivilege); 171 ASSERT_TRUE(dup_scoped_privilege.is_enabled()); 172 ASSERT_TRUE(CurrentProcessHasPrivilege(kTestedPrivilege)); 173 } 174 ASSERT_TRUE(CurrentProcessHasPrivilege(kTestedPrivilege)); 175 } 176 177 ASSERT_FALSE(CurrentProcessHasPrivilege(kTestedPrivilege)); 178} 179 180const char kAdjustProcessPriority[] = "adjust-process-priority"; 181 182PriorityClassChangeResult DoProcessPriorityAdjustment() { 183 return installer::AdjustProcessPriority() ? PCCR_CHANGED : PCCR_UNCHANGED; 184} 185 186namespace { 187 188// A scoper that sets/resets the current process's priority class. 189class ScopedPriorityClass { 190 public: 191 // Applies |priority_class|, returning an instance if a change was made. 192 // Otherwise, returns an empty scoped_ptr. 193 static scoped_ptr<ScopedPriorityClass> Create(DWORD priority_class); 194 ~ScopedPriorityClass(); 195 196 private: 197 explicit ScopedPriorityClass(DWORD original_priority_class); 198 DWORD original_priority_class_; 199 DISALLOW_COPY_AND_ASSIGN(ScopedPriorityClass); 200}; 201 202scoped_ptr<ScopedPriorityClass> ScopedPriorityClass::Create( 203 DWORD priority_class) { 204 HANDLE this_process = ::GetCurrentProcess(); 205 DWORD original_priority_class = ::GetPriorityClass(this_process); 206 EXPECT_NE(0U, original_priority_class); 207 if (original_priority_class && original_priority_class != priority_class) { 208 BOOL result = ::SetPriorityClass(this_process, priority_class); 209 EXPECT_NE(FALSE, result); 210 if (result) { 211 return scoped_ptr<ScopedPriorityClass>( 212 new ScopedPriorityClass(original_priority_class)); 213 } 214 } 215 return scoped_ptr<ScopedPriorityClass>(); 216} 217 218ScopedPriorityClass::ScopedPriorityClass(DWORD original_priority_class) 219 : original_priority_class_(original_priority_class) {} 220 221ScopedPriorityClass::~ScopedPriorityClass() { 222 BOOL result = ::SetPriorityClass(::GetCurrentProcess(), 223 original_priority_class_); 224 EXPECT_NE(FALSE, result); 225} 226 227PriorityClassChangeResult RelaunchAndDoProcessPriorityAdjustment() { 228 CommandLine cmd_line(*CommandLine::ForCurrentProcess()); 229 cmd_line.AppendSwitch(kAdjustProcessPriority); 230 base::ProcessHandle process_handle = NULL; 231 int exit_code = 0; 232 if (!base::LaunchProcess(cmd_line, base::LaunchOptions(), 233 &process_handle)) { 234 ADD_FAILURE() << " to launch subprocess."; 235 } else if (!base::WaitForExitCode(process_handle, &exit_code)) { 236 ADD_FAILURE() << " to wait for subprocess to exit."; 237 } else { 238 return static_cast<PriorityClassChangeResult>(exit_code); 239 } 240 return PCCR_UNKNOWN; 241} 242 243} // namespace 244 245// Launching a subprocess at normal priority class is a noop. 246TEST(SetupUtilTest, AdjustFromNormalPriority) { 247 ASSERT_EQ(NORMAL_PRIORITY_CLASS, ::GetPriorityClass(::GetCurrentProcess())); 248 EXPECT_EQ(PCCR_UNCHANGED, RelaunchAndDoProcessPriorityAdjustment()); 249} 250 251// Launching a subprocess below normal priority class drops it to bg mode for 252// sufficiently recent operating systems. 253TEST(SetupUtilTest, AdjustFromBelowNormalPriority) { 254 scoped_ptr<ScopedPriorityClass> below_normal = 255 ScopedPriorityClass::Create(BELOW_NORMAL_PRIORITY_CLASS); 256 ASSERT_TRUE(below_normal); 257 if (base::win::GetVersion() > base::win::VERSION_SERVER_2003) 258 EXPECT_EQ(PCCR_CHANGED, RelaunchAndDoProcessPriorityAdjustment()); 259 else 260 EXPECT_EQ(PCCR_UNCHANGED, RelaunchAndDoProcessPriorityAdjustment()); 261} 262 263namespace { 264 265// A test fixture that configures an InstallationState and an InstallerState 266// with a product being updated. 267class FindArchiveToPatchTest : public SetupUtilTestWithDir { 268 protected: 269 class FakeInstallationState : public installer::InstallationState { 270 }; 271 272 class FakeProductState : public installer::ProductState { 273 public: 274 static FakeProductState* FromProductState(const ProductState* product) { 275 return static_cast<FakeProductState*>(const_cast<ProductState*>(product)); 276 } 277 278 void set_version(const Version& version) { 279 if (version.IsValid()) 280 version_.reset(new Version(version)); 281 else 282 version_.reset(); 283 } 284 285 void set_uninstall_command(const CommandLine& uninstall_command) { 286 uninstall_command_ = uninstall_command; 287 } 288 }; 289 290 virtual void SetUp() OVERRIDE { 291 SetupUtilTestWithDir::SetUp(); 292 product_version_ = Version("30.0.1559.0"); 293 max_version_ = Version("47.0.1559.0"); 294 295 // Install the product according to the version. 296 original_state_.reset(new FakeInstallationState()); 297 InstallProduct(); 298 299 // Prepare to update the product in the temp dir. 300 installer_state_.reset(new installer::InstallerState( 301 kSystemInstall_ ? installer::InstallerState::SYSTEM_LEVEL : 302 installer::InstallerState::USER_LEVEL)); 303 installer_state_->AddProductFromState( 304 kProductType_, 305 *original_state_->GetProductState(kSystemInstall_, kProductType_)); 306 307 // Create archives in the two version dirs. 308 ASSERT_TRUE( 309 base::CreateDirectory(GetProductVersionArchivePath().DirName())); 310 ASSERT_EQ(1, base::WriteFile(GetProductVersionArchivePath(), "a", 1)); 311 ASSERT_TRUE( 312 base::CreateDirectory(GetMaxVersionArchivePath().DirName())); 313 ASSERT_EQ(1, base::WriteFile(GetMaxVersionArchivePath(), "b", 1)); 314 } 315 316 virtual void TearDown() OVERRIDE { 317 original_state_.reset(); 318 SetupUtilTestWithDir::TearDown(); 319 } 320 321 base::FilePath GetArchivePath(const Version& version) const { 322 return test_dir_.path() 323 .AppendASCII(version.GetString()) 324 .Append(installer::kInstallerDir) 325 .Append(installer::kChromeArchive); 326 } 327 328 base::FilePath GetMaxVersionArchivePath() const { 329 return GetArchivePath(max_version_); 330 } 331 332 base::FilePath GetProductVersionArchivePath() const { 333 return GetArchivePath(product_version_); 334 } 335 336 void InstallProduct() { 337 FakeProductState* product = FakeProductState::FromProductState( 338 original_state_->GetNonVersionedProductState(kSystemInstall_, 339 kProductType_)); 340 341 product->set_version(product_version_); 342 CommandLine uninstall_command( 343 test_dir_.path().AppendASCII(product_version_.GetString()) 344 .Append(installer::kInstallerDir) 345 .Append(installer::kSetupExe)); 346 uninstall_command.AppendSwitch(installer::switches::kUninstall); 347 product->set_uninstall_command(uninstall_command); 348 } 349 350 void UninstallProduct() { 351 FakeProductState::FromProductState( 352 original_state_->GetNonVersionedProductState(kSystemInstall_, 353 kProductType_)) 354 ->set_version(Version()); 355 } 356 357 static const bool kSystemInstall_; 358 static const BrowserDistribution::Type kProductType_; 359 Version product_version_; 360 Version max_version_; 361 scoped_ptr<FakeInstallationState> original_state_; 362 scoped_ptr<installer::InstallerState> installer_state_; 363}; 364 365const bool FindArchiveToPatchTest::kSystemInstall_ = false; 366const BrowserDistribution::Type FindArchiveToPatchTest::kProductType_ = 367 BrowserDistribution::CHROME_BROWSER; 368 369} // namespace 370 371// Test that the path to the advertised product version is found. 372TEST_F(FindArchiveToPatchTest, ProductVersionFound) { 373 base::FilePath patch_source(installer::FindArchiveToPatch( 374 *original_state_, *installer_state_)); 375 EXPECT_EQ(GetProductVersionArchivePath().value(), patch_source.value()); 376} 377 378// Test that the path to the max version is found if the advertised version is 379// missing. 380TEST_F(FindArchiveToPatchTest, MaxVersionFound) { 381 // The patch file is absent. 382 ASSERT_TRUE(base::DeleteFile(GetProductVersionArchivePath(), false)); 383 base::FilePath patch_source(installer::FindArchiveToPatch( 384 *original_state_, *installer_state_)); 385 EXPECT_EQ(GetMaxVersionArchivePath().value(), patch_source.value()); 386 387 // The product doesn't appear to be installed, so the max version is found. 388 UninstallProduct(); 389 patch_source = installer::FindArchiveToPatch( 390 *original_state_, *installer_state_); 391 EXPECT_EQ(GetMaxVersionArchivePath().value(), patch_source.value()); 392} 393 394// Test that an empty path is returned if no version is found. 395TEST_F(FindArchiveToPatchTest, NoVersionFound) { 396 // The product doesn't appear to be installed and no archives are present. 397 UninstallProduct(); 398 ASSERT_TRUE(base::DeleteFile(GetProductVersionArchivePath(), false)); 399 ASSERT_TRUE(base::DeleteFile(GetMaxVersionArchivePath(), false)); 400 401 base::FilePath patch_source(installer::FindArchiveToPatch( 402 *original_state_, *installer_state_)); 403 EXPECT_EQ(base::FilePath::StringType(), patch_source.value()); 404} 405 406namespace { 407 408class MigrateMultiToSingleTest : public testing::Test { 409 protected: 410 virtual void SetUp() OVERRIDE { 411 registry_override_manager_.OverrideRegistry(kRootKey, 412 L"MigrateMultiToSingleTest"); 413 } 414 415 static const bool kSystemLevel = false; 416 static const HKEY kRootKey; 417 static const wchar_t kVersionString[]; 418 static const wchar_t kMultiChannel[]; 419 registry_util::RegistryOverrideManager registry_override_manager_; 420}; 421 422const bool MigrateMultiToSingleTest::kSystemLevel; 423const HKEY MigrateMultiToSingleTest::kRootKey = 424 kSystemLevel ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 425const wchar_t MigrateMultiToSingleTest::kVersionString[] = L"30.0.1574.0"; 426const wchar_t MigrateMultiToSingleTest::kMultiChannel[] = 427 L"2.0-dev-multi-chromeframe"; 428 429} // namespace 430 431// Test migrating Chrome Frame from multi to single. 432TEST_F(MigrateMultiToSingleTest, ChromeFrame) { 433 installer::ProductState chrome_frame; 434 installer::ProductState binaries; 435 DWORD usagestats = 0; 436 437 // Set up a config with dev-channel multi-install GCF. 438 base::win::RegKey key; 439 440 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( 441 BrowserDistribution::CHROME_BINARIES); 442 ASSERT_EQ(ERROR_SUCCESS, 443 base::win::RegKey(kRootKey, dist->GetVersionKey().c_str(), 444 KEY_SET_VALUE) 445 .WriteValue(google_update::kRegVersionField, kVersionString)); 446 ASSERT_EQ(ERROR_SUCCESS, 447 base::win::RegKey(kRootKey, dist->GetStateKey().c_str(), 448 KEY_SET_VALUE) 449 .WriteValue(google_update::kRegApField, kMultiChannel)); 450 ASSERT_EQ(ERROR_SUCCESS, 451 base::win::RegKey(kRootKey, dist->GetStateKey().c_str(), 452 KEY_SET_VALUE) 453 .WriteValue(google_update::kRegUsageStatsField, 1U)); 454 455 dist = BrowserDistribution::GetSpecificDistribution( 456 BrowserDistribution::CHROME_FRAME); 457 ASSERT_EQ(ERROR_SUCCESS, 458 base::win::RegKey(kRootKey, dist->GetVersionKey().c_str(), 459 KEY_SET_VALUE) 460 .WriteValue(google_update::kRegVersionField, kVersionString)); 461 ASSERT_EQ(ERROR_SUCCESS, 462 base::win::RegKey(kRootKey, dist->GetStateKey().c_str(), 463 KEY_SET_VALUE) 464 .WriteValue(google_update::kRegApField, kMultiChannel)); 465 466 // Do the registry migration. 467 installer::InstallationState machine_state; 468 machine_state.Initialize(); 469 470 installer::MigrateGoogleUpdateStateMultiToSingle( 471 kSystemLevel, 472 BrowserDistribution::CHROME_FRAME, 473 machine_state); 474 475 // Confirm that usagestats were copied to CF and that its channel was 476 // stripped. 477 ASSERT_TRUE(chrome_frame.Initialize(kSystemLevel, 478 BrowserDistribution::CHROME_FRAME)); 479 EXPECT_TRUE(chrome_frame.GetUsageStats(&usagestats)); 480 EXPECT_EQ(1U, usagestats); 481 EXPECT_EQ(L"2.0-dev", chrome_frame.channel().value()); 482 483 // Confirm that the binaries' channel no longer contains GCF. 484 ASSERT_TRUE(binaries.Initialize(kSystemLevel, 485 BrowserDistribution::CHROME_BINARIES)); 486 EXPECT_EQ(L"2.0-dev-multi", binaries.channel().value()); 487} 488 489TEST(SetupUtilTest, ContainsUnsupportedSwitch) { 490 EXPECT_FALSE(installer::ContainsUnsupportedSwitch( 491 CommandLine::FromString(L"foo.exe"))); 492 EXPECT_FALSE(installer::ContainsUnsupportedSwitch( 493 CommandLine::FromString(L"foo.exe --multi-install --chrome"))); 494 EXPECT_TRUE(installer::ContainsUnsupportedSwitch( 495 CommandLine::FromString(L"foo.exe --chrome-frame"))); 496} 497