1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <windows.h> 6 7 #include <fstream> 8 9 #include "base/base_paths.h" 10 #include "base/command_line.h" 11 #include "base/files/file_enumerator.h" 12 #include "base/files/file_path.h" 13 #include "base/files/file_util.h" 14 #include "base/files/scoped_temp_dir.h" 15 #include "base/path_service.h" 16 #include "base/strings/string_util.h" 17 #include "base/strings/utf_string_conversions.h" 18 #include "base/test/scoped_path_override.h" 19 #include "base/test/test_reg_util_win.h" 20 #include "base/version.h" 21 #include "base/win/registry.h" 22 #include "base/win/scoped_handle.h" 23 #include "chrome/common/chrome_constants.h" 24 #include "chrome/installer/test/alternate_version_generator.h" 25 #include "chrome/installer/util/fake_installation_state.h" 26 #include "chrome/installer/util/fake_product_state.h" 27 #include "chrome/installer/util/google_update_constants.h" 28 #include "chrome/installer/util/helper.h" 29 #include "chrome/installer/util/installation_state.h" 30 #include "chrome/installer/util/installer_state.h" 31 #include "chrome/installer/util/master_preferences.h" 32 #include "chrome/installer/util/product_unittest.h" 33 #include "chrome/installer/util/util_constants.h" 34 #include "chrome/installer/util/work_item.h" 35 #include "testing/gtest/include/gtest/gtest.h" 36 37 #include "installer_util_strings.h" // NOLINT 38 39 using base::win::RegKey; 40 using installer::InstallationState; 41 using installer::InstallerState; 42 using installer::MasterPreferences; 43 using registry_util::RegistryOverrideManager; 44 45 class InstallerStateTest : public TestWithTempDirAndDeleteTempOverrideKeys { 46 protected: 47 }; 48 49 // An installer state on which we can access otherwise protected members. 50 class MockInstallerState : public InstallerState { 51 public: 52 MockInstallerState() : InstallerState() { } 53 void set_target_path(const base::FilePath& target_path) { 54 target_path_ = target_path; 55 } 56 static bool IsFileInUse(const base::FilePath& file) { 57 return InstallerState::IsFileInUse(file); 58 } 59 const Version& critical_update_version() const { 60 return critical_update_version_; 61 } 62 void GetExistingExeVersions(std::set<std::string>* existing_version_strings) { 63 return InstallerState::GetExistingExeVersions(existing_version_strings); 64 } 65 }; 66 67 // Simple function to dump some text into a new file. 68 void CreateTextFile(const std::wstring& filename, 69 const std::wstring& contents) { 70 std::ofstream file; 71 file.open(filename.c_str()); 72 ASSERT_TRUE(file.is_open()); 73 file << contents; 74 file.close(); 75 } 76 77 void BuildSingleChromeState(const base::FilePath& target_dir, 78 MockInstallerState* installer_state) { 79 CommandLine cmd_line = CommandLine::FromString(L"setup.exe"); 80 MasterPreferences prefs(cmd_line); 81 InstallationState machine_state; 82 machine_state.Initialize(); 83 installer_state->Initialize(cmd_line, prefs, machine_state); 84 installer_state->set_target_path(target_dir); 85 EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER) 86 != NULL); 87 } 88 89 wchar_t text_content_1[] = L"delete me"; 90 wchar_t text_content_2[] = L"delete me as well"; 91 92 // Delete version directories. Everything lower than the given version 93 // should be deleted. 94 TEST_F(InstallerStateTest, Delete) { 95 // TODO(grt): move common stuff into the test fixture. 96 // Create a Chrome dir 97 base::FilePath chrome_dir(test_dir_.path()); 98 chrome_dir = chrome_dir.AppendASCII("chrome"); 99 base::CreateDirectory(chrome_dir); 100 ASSERT_TRUE(base::PathExists(chrome_dir)); 101 102 base::FilePath chrome_dir_1(chrome_dir); 103 chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); 104 base::CreateDirectory(chrome_dir_1); 105 ASSERT_TRUE(base::PathExists(chrome_dir_1)); 106 107 base::FilePath chrome_dir_2(chrome_dir); 108 chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); 109 base::CreateDirectory(chrome_dir_2); 110 ASSERT_TRUE(base::PathExists(chrome_dir_2)); 111 112 base::FilePath chrome_dir_3(chrome_dir); 113 chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); 114 base::CreateDirectory(chrome_dir_3); 115 ASSERT_TRUE(base::PathExists(chrome_dir_3)); 116 117 base::FilePath chrome_dir_4(chrome_dir); 118 chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); 119 base::CreateDirectory(chrome_dir_4); 120 ASSERT_TRUE(base::PathExists(chrome_dir_4)); 121 122 base::FilePath chrome_dll_1(chrome_dir_1); 123 chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); 124 CreateTextFile(chrome_dll_1.value(), text_content_1); 125 ASSERT_TRUE(base::PathExists(chrome_dll_1)); 126 127 base::FilePath chrome_dll_2(chrome_dir_2); 128 chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); 129 CreateTextFile(chrome_dll_2.value(), text_content_1); 130 ASSERT_TRUE(base::PathExists(chrome_dll_2)); 131 132 base::FilePath chrome_dll_3(chrome_dir_3); 133 chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); 134 CreateTextFile(chrome_dll_3.value(), text_content_1); 135 ASSERT_TRUE(base::PathExists(chrome_dll_3)); 136 137 base::FilePath chrome_dll_4(chrome_dir_4); 138 chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); 139 CreateTextFile(chrome_dll_4.value(), text_content_1); 140 ASSERT_TRUE(base::PathExists(chrome_dll_4)); 141 142 MockInstallerState installer_state; 143 BuildSingleChromeState(chrome_dir, &installer_state); 144 Version latest_version("1.0.4.0"); 145 { 146 base::ScopedTempDir temp_dir; 147 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 148 installer_state.RemoveOldVersionDirectories(latest_version, NULL, 149 temp_dir.path()); 150 } 151 152 // old versions should be gone 153 EXPECT_FALSE(base::PathExists(chrome_dir_1)); 154 EXPECT_FALSE(base::PathExists(chrome_dir_2)); 155 EXPECT_FALSE(base::PathExists(chrome_dir_3)); 156 // the latest version should stay 157 EXPECT_TRUE(base::PathExists(chrome_dll_4)); 158 } 159 160 // Delete older version directories, keeping the one in used intact. 161 TEST_F(InstallerStateTest, DeleteInUsed) { 162 // Create a Chrome dir 163 base::FilePath chrome_dir(test_dir_.path()); 164 chrome_dir = chrome_dir.AppendASCII("chrome"); 165 base::CreateDirectory(chrome_dir); 166 ASSERT_TRUE(base::PathExists(chrome_dir)); 167 168 base::FilePath chrome_dir_1(chrome_dir); 169 chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); 170 base::CreateDirectory(chrome_dir_1); 171 ASSERT_TRUE(base::PathExists(chrome_dir_1)); 172 173 base::FilePath chrome_dir_2(chrome_dir); 174 chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); 175 base::CreateDirectory(chrome_dir_2); 176 ASSERT_TRUE(base::PathExists(chrome_dir_2)); 177 178 base::FilePath chrome_dir_3(chrome_dir); 179 chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); 180 base::CreateDirectory(chrome_dir_3); 181 ASSERT_TRUE(base::PathExists(chrome_dir_3)); 182 183 base::FilePath chrome_dir_4(chrome_dir); 184 chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); 185 base::CreateDirectory(chrome_dir_4); 186 ASSERT_TRUE(base::PathExists(chrome_dir_4)); 187 188 base::FilePath chrome_dll_1(chrome_dir_1); 189 chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); 190 CreateTextFile(chrome_dll_1.value(), text_content_1); 191 ASSERT_TRUE(base::PathExists(chrome_dll_1)); 192 193 base::FilePath chrome_dll_2(chrome_dir_2); 194 chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); 195 CreateTextFile(chrome_dll_2.value(), text_content_1); 196 ASSERT_TRUE(base::PathExists(chrome_dll_2)); 197 198 // Open the file to make it in use. 199 std::ofstream file; 200 file.open(chrome_dll_2.value().c_str()); 201 202 base::FilePath chrome_othera_2(chrome_dir_2); 203 chrome_othera_2 = chrome_othera_2.AppendASCII("othera.dll"); 204 CreateTextFile(chrome_othera_2.value(), text_content_2); 205 ASSERT_TRUE(base::PathExists(chrome_othera_2)); 206 207 base::FilePath chrome_otherb_2(chrome_dir_2); 208 chrome_otherb_2 = chrome_otherb_2.AppendASCII("otherb.dll"); 209 CreateTextFile(chrome_otherb_2.value(), text_content_2); 210 ASSERT_TRUE(base::PathExists(chrome_otherb_2)); 211 212 base::FilePath chrome_dll_3(chrome_dir_3); 213 chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); 214 CreateTextFile(chrome_dll_3.value(), text_content_1); 215 ASSERT_TRUE(base::PathExists(chrome_dll_3)); 216 217 base::FilePath chrome_dll_4(chrome_dir_4); 218 chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); 219 CreateTextFile(chrome_dll_4.value(), text_content_1); 220 ASSERT_TRUE(base::PathExists(chrome_dll_4)); 221 222 MockInstallerState installer_state; 223 BuildSingleChromeState(chrome_dir, &installer_state); 224 Version latest_version("1.0.4.0"); 225 Version existing_version("1.0.1.0"); 226 { 227 base::ScopedTempDir temp_dir; 228 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 229 installer_state.RemoveOldVersionDirectories(latest_version, 230 &existing_version, 231 temp_dir.path()); 232 } 233 234 // the version defined as the existing version should stay 235 EXPECT_TRUE(base::PathExists(chrome_dir_1)); 236 // old versions not in used should be gone 237 EXPECT_FALSE(base::PathExists(chrome_dir_3)); 238 // every thing under in used version should stay 239 EXPECT_TRUE(base::PathExists(chrome_dir_2)); 240 EXPECT_TRUE(base::PathExists(chrome_dll_2)); 241 EXPECT_TRUE(base::PathExists(chrome_othera_2)); 242 EXPECT_TRUE(base::PathExists(chrome_otherb_2)); 243 // the latest version should stay 244 EXPECT_TRUE(base::PathExists(chrome_dll_4)); 245 } 246 247 // Tests a few basic things of the Package class. Makes sure that the path 248 // operations are correct 249 TEST_F(InstallerStateTest, Basic) { 250 const bool multi_install = false; 251 const bool system_level = true; 252 CommandLine cmd_line = CommandLine::FromString( 253 std::wstring(L"setup.exe") + 254 (multi_install ? L" --multi-install --chrome" : L"") + 255 (system_level ? L" --system-level" : L"")); 256 MasterPreferences prefs(cmd_line); 257 InstallationState machine_state; 258 machine_state.Initialize(); 259 MockInstallerState installer_state; 260 installer_state.Initialize(cmd_line, prefs, machine_state); 261 installer_state.set_target_path(test_dir_.path()); 262 EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value()); 263 EXPECT_EQ(1U, installer_state.products().size()); 264 265 const char kOldVersion[] = "1.2.3.4"; 266 const char kNewVersion[] = "2.3.4.5"; 267 268 Version new_version(kNewVersion); 269 Version old_version(kOldVersion); 270 ASSERT_TRUE(new_version.IsValid()); 271 ASSERT_TRUE(old_version.IsValid()); 272 273 base::FilePath installer_dir( 274 installer_state.GetInstallerDirectory(new_version)); 275 EXPECT_FALSE(installer_dir.empty()); 276 277 base::FilePath new_version_dir(installer_state.target_path().Append( 278 base::UTF8ToWide(new_version.GetString()))); 279 base::FilePath old_version_dir(installer_state.target_path().Append( 280 base::UTF8ToWide(old_version.GetString()))); 281 282 EXPECT_FALSE(base::PathExists(new_version_dir)); 283 EXPECT_FALSE(base::PathExists(old_version_dir)); 284 285 EXPECT_FALSE(base::PathExists(installer_dir)); 286 base::CreateDirectory(installer_dir); 287 EXPECT_TRUE(base::PathExists(new_version_dir)); 288 289 base::CreateDirectory(old_version_dir); 290 EXPECT_TRUE(base::PathExists(old_version_dir)); 291 292 // Create a fake chrome.dll key file in the old version directory. This 293 // should prevent the old version directory from getting deleted. 294 base::FilePath old_chrome_dll(old_version_dir.Append(installer::kChromeDll)); 295 EXPECT_FALSE(base::PathExists(old_chrome_dll)); 296 297 // Hold on to the file exclusively to prevent the directory from 298 // being deleted. 299 base::win::ScopedHandle file( 300 ::CreateFile(old_chrome_dll.value().c_str(), GENERIC_READ, 301 0, NULL, OPEN_ALWAYS, 0, NULL)); 302 EXPECT_TRUE(file.IsValid()); 303 EXPECT_TRUE(base::PathExists(old_chrome_dll)); 304 305 base::ScopedTempDir temp_dir; 306 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 307 308 // Don't explicitly tell the directory cleanup logic not to delete the 309 // old version, rely on the key files to keep it around. 310 installer_state.RemoveOldVersionDirectories(new_version, 311 NULL, 312 temp_dir.path()); 313 314 // The old directory should still exist. 315 EXPECT_TRUE(base::PathExists(old_version_dir)); 316 EXPECT_TRUE(base::PathExists(new_version_dir)); 317 318 // Now close the file handle to make it possible to delete our key file. 319 file.Close(); 320 321 installer_state.RemoveOldVersionDirectories(new_version, 322 NULL, 323 temp_dir.path()); 324 // The new directory should still exist. 325 EXPECT_TRUE(base::PathExists(new_version_dir)); 326 327 // Now, the old directory and key file should be gone. 328 EXPECT_FALSE(base::PathExists(old_chrome_dll)); 329 EXPECT_FALSE(base::PathExists(old_version_dir)); 330 } 331 332 TEST_F(InstallerStateTest, WithProduct) { 333 const bool multi_install = false; 334 const bool system_level = true; 335 CommandLine cmd_line = CommandLine::FromString( 336 std::wstring(L"setup.exe") + 337 (multi_install ? L" --multi-install --chrome" : L"") + 338 (system_level ? L" --system-level" : L"")); 339 MasterPreferences prefs(cmd_line); 340 InstallationState machine_state; 341 machine_state.Initialize(); 342 MockInstallerState installer_state; 343 installer_state.Initialize(cmd_line, prefs, machine_state); 344 installer_state.set_target_path(test_dir_.path()); 345 EXPECT_EQ(1U, installer_state.products().size()); 346 EXPECT_EQ(system_level, installer_state.system_install()); 347 348 const char kCurrentVersion[] = "1.2.3.4"; 349 Version current_version(kCurrentVersion); 350 351 HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 352 EXPECT_EQ(root, installer_state.root_key()); 353 354 { 355 RegistryOverrideManager override_manager; 356 override_manager.OverrideRegistry(root); 357 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( 358 BrowserDistribution::CHROME_BROWSER); 359 RegKey chrome_key(root, dist->GetVersionKey().c_str(), KEY_ALL_ACCESS); 360 EXPECT_TRUE(chrome_key.Valid()); 361 if (chrome_key.Valid()) { 362 chrome_key.WriteValue(google_update::kRegVersionField, 363 base::UTF8ToWide( 364 current_version.GetString()).c_str()); 365 machine_state.Initialize(); 366 // TODO(tommi): Also test for when there exists a new_chrome.exe. 367 Version found_version(*installer_state.GetCurrentVersion(machine_state)); 368 EXPECT_TRUE(found_version.IsValid()); 369 if (found_version.IsValid()) 370 EXPECT_TRUE(current_version.Equals(found_version)); 371 } 372 } 373 } 374 375 TEST_F(InstallerStateTest, InstallerResult) { 376 const bool system_level = true; 377 bool multi_install = false; 378 HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 379 380 RegKey key; 381 std::wstring launch_cmd = L"hey diddle diddle"; 382 std::wstring value; 383 DWORD dw_value; 384 385 // check results for a fresh install of single Chrome 386 { 387 RegistryOverrideManager override_manager; 388 override_manager.OverrideRegistry(root); 389 CommandLine cmd_line = CommandLine::FromString(L"setup.exe --system-level"); 390 const MasterPreferences prefs(cmd_line); 391 InstallationState machine_state; 392 machine_state.Initialize(); 393 InstallerState state; 394 state.Initialize(cmd_line, prefs, machine_state); 395 state.WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS, 396 IDS_INSTALL_OS_ERROR_BASE, &launch_cmd); 397 BrowserDistribution* distribution = 398 BrowserDistribution::GetSpecificDistribution( 399 BrowserDistribution::CHROME_BROWSER); 400 EXPECT_EQ(ERROR_SUCCESS, 401 key.Open(root, distribution->GetStateKey().c_str(), KEY_READ)); 402 EXPECT_EQ(ERROR_SUCCESS, 403 key.ReadValueDW(installer::kInstallerResult, &dw_value)); 404 EXPECT_EQ(static_cast<DWORD>(0), dw_value); 405 EXPECT_EQ(ERROR_SUCCESS, 406 key.ReadValueDW(installer::kInstallerError, &dw_value)); 407 EXPECT_EQ(static_cast<DWORD>(installer::FIRST_INSTALL_SUCCESS), dw_value); 408 EXPECT_EQ(ERROR_SUCCESS, 409 key.ReadValue(installer::kInstallerResultUIString, &value)); 410 EXPECT_FALSE(value.empty()); 411 EXPECT_EQ(ERROR_SUCCESS, 412 key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value)); 413 EXPECT_EQ(launch_cmd, value); 414 } 415 416 // check results for a fresh install of multi Chrome 417 { 418 RegistryOverrideManager override_manager; 419 override_manager.OverrideRegistry(root); 420 CommandLine cmd_line = CommandLine::FromString( 421 L"setup.exe --system-level --multi-install --chrome"); 422 const MasterPreferences prefs(cmd_line); 423 InstallationState machine_state; 424 machine_state.Initialize(); 425 InstallerState state; 426 state.Initialize(cmd_line, prefs, machine_state); 427 state.WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS, 0, 428 &launch_cmd); 429 BrowserDistribution* distribution = 430 BrowserDistribution::GetSpecificDistribution( 431 BrowserDistribution::CHROME_BROWSER); 432 BrowserDistribution* binaries = 433 BrowserDistribution::GetSpecificDistribution( 434 BrowserDistribution::CHROME_BINARIES); 435 EXPECT_EQ(ERROR_SUCCESS, 436 key.Open(root, distribution->GetStateKey().c_str(), KEY_READ)); 437 EXPECT_EQ(ERROR_SUCCESS, 438 key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value)); 439 EXPECT_EQ(launch_cmd, value); 440 EXPECT_EQ(ERROR_SUCCESS, 441 key.Open(root, binaries->GetStateKey().c_str(), KEY_READ)); 442 EXPECT_EQ(ERROR_SUCCESS, 443 key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value)); 444 EXPECT_EQ(launch_cmd, value); 445 key.Close(); 446 } 447 } 448 449 // Test GetCurrentVersion when migrating single Chrome to multi 450 TEST_F(InstallerStateTest, GetCurrentVersionMigrateChrome) { 451 using installer::FakeInstallationState; 452 453 const bool system_install = false; 454 FakeInstallationState machine_state; 455 456 // Pretend that this version of single-install Chrome is already installed. 457 machine_state.AddChrome(system_install, false, 458 new Version(chrome::kChromeVersion)); 459 460 // Now we're invoked to install multi Chrome. 461 CommandLine cmd_line( 462 CommandLine::FromString(L"setup.exe --multi-install --chrome")); 463 MasterPreferences prefs(cmd_line); 464 InstallerState installer_state; 465 installer_state.Initialize(cmd_line, prefs, machine_state); 466 467 // Is the Chrome version picked up? 468 scoped_ptr<Version> version(installer_state.GetCurrentVersion(machine_state)); 469 EXPECT_TRUE(version.get() != NULL); 470 } 471 472 TEST_F(InstallerStateTest, IsFileInUse) { 473 base::ScopedTempDir temp_dir; 474 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 475 476 base::FilePath temp_file; 477 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file)); 478 479 EXPECT_FALSE(MockInstallerState::IsFileInUse(temp_file)); 480 481 { 482 // Open a handle to the file with the same access mode and sharing options 483 // as the loader. 484 base::win::ScopedHandle temp_handle( 485 CreateFile(temp_file.value().c_str(), 486 SYNCHRONIZE | FILE_EXECUTE, 487 FILE_SHARE_DELETE | FILE_SHARE_READ, 488 NULL, OPEN_EXISTING, 0, 0)); 489 ASSERT_TRUE(temp_handle.IsValid()); 490 491 // The file should now be in use. 492 EXPECT_TRUE(MockInstallerState::IsFileInUse(temp_file)); 493 } 494 495 // And once the handle is gone, it should no longer be in use. 496 EXPECT_FALSE(MockInstallerState::IsFileInUse(temp_file)); 497 } 498 499 TEST_F(InstallerStateTest, RemoveOldVersionDirs) { 500 MockInstallerState installer_state; 501 installer_state.set_target_path(test_dir_.path()); 502 EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value()); 503 504 const char kOldVersion[] = "2.0.0.0"; 505 const char kNewVersion[] = "3.0.0.0"; 506 const char kOldChromeExeVersion[] = "2.1.0.0"; 507 const char kChromeExeVersion[] = "2.1.1.1"; 508 const char kNewChromeExeVersion[] = "3.0.0.0"; 509 510 Version new_version(kNewVersion); 511 Version old_version(kOldVersion); 512 Version old_chrome_exe_version(kOldChromeExeVersion); 513 Version chrome_exe_version(kChromeExeVersion); 514 Version new_chrome_exe_version(kNewChromeExeVersion); 515 516 ASSERT_TRUE(new_version.IsValid()); 517 ASSERT_TRUE(old_version.IsValid()); 518 ASSERT_TRUE(old_chrome_exe_version.IsValid()); 519 ASSERT_TRUE(chrome_exe_version.IsValid()); 520 ASSERT_TRUE(new_chrome_exe_version.IsValid()); 521 522 // Set up a bunch of version dir paths. 523 base::FilePath version_dirs[] = { 524 installer_state.target_path().Append(L"1.2.3.4"), 525 installer_state.target_path().Append(L"1.2.3.5"), 526 installer_state.target_path().Append(L"1.2.3.6"), 527 installer_state.target_path().Append(base::ASCIIToWide(kOldVersion)), 528 installer_state.target_path().Append( 529 base::ASCIIToWide(kOldChromeExeVersion)), 530 installer_state.target_path().Append(L"2.1.1.0"), 531 installer_state.target_path().Append(base::ASCIIToWide(kChromeExeVersion)), 532 installer_state.target_path().Append(base::ASCIIToWide(kNewVersion)), 533 installer_state.target_path().Append(L"3.9.1.1"), 534 }; 535 536 // Create the version directories. 537 for (int i = 0; i < arraysize(version_dirs); i++) { 538 base::CreateDirectory(version_dirs[i]); 539 EXPECT_TRUE(base::PathExists(version_dirs[i])); 540 } 541 542 // Create exes with the appropriate version resource. 543 // Use the current test exe as a baseline. 544 base::FilePath exe_path; 545 ASSERT_TRUE(PathService::Get(base::FILE_EXE, &exe_path)); 546 547 struct target_info { 548 base::FilePath target_file; 549 const Version& target_version; 550 } targets[] = { 551 { installer_state.target_path().Append(installer::kChromeOldExe), 552 old_chrome_exe_version }, 553 { installer_state.target_path().Append(installer::kChromeExe), 554 chrome_exe_version }, 555 { installer_state.target_path().Append(installer::kChromeNewExe), 556 new_chrome_exe_version }, 557 }; 558 for (int i = 0; i < arraysize(targets); ++i) { 559 ASSERT_TRUE(upgrade_test::GenerateSpecificPEFileVersion( 560 exe_path, targets[i].target_file, targets[i].target_version)); 561 } 562 563 // Call GetExistingExeVersions, validate that picks up the 564 // exe resources. 565 std::set<std::string> expected_exe_versions; 566 expected_exe_versions.insert(kOldChromeExeVersion); 567 expected_exe_versions.insert(kChromeExeVersion); 568 expected_exe_versions.insert(kNewChromeExeVersion); 569 570 std::set<std::string> actual_exe_versions; 571 installer_state.GetExistingExeVersions(&actual_exe_versions); 572 EXPECT_EQ(expected_exe_versions, actual_exe_versions); 573 574 // Call RemoveOldVersionDirectories 575 installer_state.RemoveOldVersionDirectories(new_version, 576 &old_version, 577 installer_state.target_path()); 578 579 // What we expect to have left. 580 std::set<std::string> expected_remaining_dirs; 581 expected_remaining_dirs.insert(kOldVersion); 582 expected_remaining_dirs.insert(kNewVersion); 583 expected_remaining_dirs.insert(kOldChromeExeVersion); 584 expected_remaining_dirs.insert(kChromeExeVersion); 585 expected_remaining_dirs.insert(kNewChromeExeVersion); 586 587 // Enumerate dirs in target_path(), ensure only desired remain. 588 base::FileEnumerator version_enum(installer_state.target_path(), false, 589 base::FileEnumerator::DIRECTORIES); 590 for (base::FilePath next_version = version_enum.Next(); !next_version.empty(); 591 next_version = version_enum.Next()) { 592 base::FilePath dir_name(next_version.BaseName()); 593 Version version(base::UTF16ToASCII(dir_name.value())); 594 if (version.IsValid()) { 595 EXPECT_TRUE(expected_remaining_dirs.erase(version.GetString())) 596 << "Unexpected version dir found: " << version.GetString(); 597 } 598 } 599 600 std::set<std::string>::const_iterator iter( 601 expected_remaining_dirs.begin()); 602 for (; iter != expected_remaining_dirs.end(); ++iter) 603 ADD_FAILURE() << "Expected to find version dir for " << *iter; 604 } 605 606 TEST_F(InstallerStateTest, InitializeTwice) { 607 // Override these paths so that they can be found after the registry override 608 // manager is in place. 609 base::FilePath temp; 610 PathService::Get(base::DIR_PROGRAM_FILES, &temp); 611 base::ScopedPathOverride program_files_override(base::DIR_PROGRAM_FILES, 612 temp); 613 PathService::Get(base::DIR_PROGRAM_FILESX86, &temp); 614 base::ScopedPathOverride program_filesx86_override(base::DIR_PROGRAM_FILESX86, 615 temp); 616 PathService::Get(base::DIR_LOCAL_APP_DATA, &temp); 617 base::ScopedPathOverride local_app_data_override(base::DIR_LOCAL_APP_DATA, 618 temp); 619 registry_util::RegistryOverrideManager override_manager; 620 override_manager.OverrideRegistry(HKEY_CURRENT_USER); 621 override_manager.OverrideRegistry(HKEY_LOCAL_MACHINE); 622 623 InstallationState machine_state; 624 machine_state.Initialize(); 625 626 InstallerState installer_state; 627 628 // Initialize the instance to install multi Chrome. 629 { 630 CommandLine cmd_line( 631 CommandLine::FromString(L"setup.exe --multi-install --chrome")); 632 MasterPreferences prefs(cmd_line); 633 installer_state.Initialize(cmd_line, prefs, machine_state); 634 } 635 // Confirm the expected state. 636 EXPECT_EQ(InstallerState::USER_LEVEL, installer_state.level()); 637 EXPECT_EQ(InstallerState::MULTI_PACKAGE, installer_state.package_type()); 638 EXPECT_EQ(InstallerState::MULTI_INSTALL, installer_state.operation()); 639 EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(), 640 BrowserDistribution::GetSpecificDistribution( 641 BrowserDistribution::CHROME_BINARIES)-> 642 GetInstallSubDir().c_str())); 643 EXPECT_FALSE(installer_state.verbose_logging()); 644 EXPECT_EQ(installer_state.state_key(), 645 BrowserDistribution::GetSpecificDistribution( 646 BrowserDistribution::CHROME_BROWSER)->GetStateKey()); 647 EXPECT_EQ(installer_state.state_type(), BrowserDistribution::CHROME_BROWSER); 648 EXPECT_TRUE(installer_state.multi_package_binaries_distribution()); 649 EXPECT_TRUE(installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER)); 650 651 // Now initialize it to install system-level single Chrome. 652 { 653 CommandLine cmd_line( 654 CommandLine::FromString(L"setup.exe --system-level --verbose-logging")); 655 MasterPreferences prefs(cmd_line); 656 installer_state.Initialize(cmd_line, prefs, machine_state); 657 } 658 659 // Confirm that the old state is gone. 660 EXPECT_EQ(InstallerState::SYSTEM_LEVEL, installer_state.level()); 661 EXPECT_EQ(InstallerState::SINGLE_PACKAGE, installer_state.package_type()); 662 EXPECT_EQ(InstallerState::SINGLE_INSTALL_OR_UPDATE, 663 installer_state.operation()); 664 EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(), 665 BrowserDistribution::GetSpecificDistribution( 666 BrowserDistribution::CHROME_BROWSER)-> 667 GetInstallSubDir().c_str())); 668 EXPECT_TRUE(installer_state.verbose_logging()); 669 EXPECT_EQ(installer_state.state_key(), 670 BrowserDistribution::GetSpecificDistribution( 671 BrowserDistribution::CHROME_BROWSER)->GetStateKey()); 672 EXPECT_EQ(installer_state.state_type(), BrowserDistribution::CHROME_BROWSER); 673 EXPECT_TRUE(installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER)); 674 } 675 676 // A fixture for testing InstallerState::DetermineCriticalVersion. Individual 677 // tests must invoke Initialize() with a critical version. 678 class InstallerStateCriticalVersionTest : public ::testing::Test { 679 protected: 680 InstallerStateCriticalVersionTest() : cmd_line_(CommandLine::NO_PROGRAM) {} 681 682 // Creates a set of versions for use by all test runs. 683 static void SetUpTestCase() { 684 low_version_ = new Version("15.0.874.106"); 685 opv_version_ = new Version("15.0.874.255"); 686 middle_version_ = new Version("16.0.912.32"); 687 pv_version_ = new Version("16.0.912.255"); 688 high_version_ = new Version("17.0.932.0"); 689 } 690 691 // Cleans up versions used by all test runs. 692 static void TearDownTestCase() { 693 delete low_version_; 694 delete opv_version_; 695 delete middle_version_; 696 delete pv_version_; 697 delete high_version_; 698 } 699 700 // Initializes the InstallerState to use for a test run. The returned 701 // instance's critical update version is set to |version|. |version| may be 702 // NULL, in which case the critical update version is unset. 703 MockInstallerState& Initialize(const Version* version) { 704 cmd_line_ = version == NULL ? 705 CommandLine::FromString(L"setup.exe") : 706 CommandLine::FromString( 707 L"setup.exe --critical-update-version=" + 708 base::ASCIIToWide(version->GetString())); 709 prefs_.reset(new MasterPreferences(cmd_line_)); 710 machine_state_.Initialize(); 711 installer_state_.Initialize(cmd_line_, *prefs_, machine_state_); 712 return installer_state_; 713 } 714 715 static Version* low_version_; 716 static Version* opv_version_; 717 static Version* middle_version_; 718 static Version* pv_version_; 719 static Version* high_version_; 720 721 CommandLine cmd_line_; 722 scoped_ptr<MasterPreferences> prefs_; 723 InstallationState machine_state_; 724 MockInstallerState installer_state_; 725 }; 726 727 Version* InstallerStateCriticalVersionTest::low_version_ = NULL; 728 Version* InstallerStateCriticalVersionTest::opv_version_ = NULL; 729 Version* InstallerStateCriticalVersionTest::middle_version_ = NULL; 730 Version* InstallerStateCriticalVersionTest::pv_version_ = NULL; 731 Version* InstallerStateCriticalVersionTest::high_version_ = NULL; 732 733 // Test the case where the critical version is less than the currently-running 734 // Chrome. The critical version is ignored since it doesn't apply. 735 TEST_F(InstallerStateCriticalVersionTest, CriticalBeforeOpv) { 736 MockInstallerState& installer_state(Initialize(low_version_)); 737 738 EXPECT_TRUE(installer_state.critical_update_version().Equals(*low_version_)); 739 // Unable to determine the installed version, so assume critical update. 740 EXPECT_TRUE( 741 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 742 // Installed version is past the critical update. 743 EXPECT_FALSE( 744 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 745 .IsValid()); 746 // Installed version is past the critical update. 747 EXPECT_FALSE( 748 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 749 .IsValid()); 750 } 751 752 // Test the case where the critical version is equal to the currently-running 753 // Chrome. The critical version is ignored since it doesn't apply. 754 TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsOpv) { 755 MockInstallerState& installer_state(Initialize(opv_version_)); 756 757 EXPECT_TRUE(installer_state.critical_update_version().Equals(*opv_version_)); 758 // Unable to determine the installed version, so assume critical update. 759 EXPECT_TRUE( 760 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 761 // Installed version equals the critical update. 762 EXPECT_FALSE( 763 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 764 .IsValid()); 765 // Installed version equals the critical update. 766 EXPECT_FALSE( 767 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 768 .IsValid()); 769 } 770 771 // Test the case where the critical version is between the currently-running 772 // Chrome and the to-be-installed Chrome. 773 TEST_F(InstallerStateCriticalVersionTest, CriticalBetweenOpvAndPv) { 774 MockInstallerState& installer_state(Initialize(middle_version_)); 775 776 EXPECT_TRUE(installer_state.critical_update_version().Equals( 777 *middle_version_)); 778 // Unable to determine the installed version, so assume critical update. 779 EXPECT_TRUE( 780 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 781 // Installed version before the critical update. 782 EXPECT_TRUE( 783 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 784 .IsValid()); 785 // Installed version is past the critical update. 786 EXPECT_FALSE( 787 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 788 .IsValid()); 789 } 790 791 // Test the case where the critical version is the same as the to-be-installed 792 // Chrome. 793 TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsPv) { 794 MockInstallerState& installer_state(Initialize(pv_version_)); 795 796 EXPECT_TRUE(installer_state.critical_update_version().Equals( 797 *pv_version_)); 798 // Unable to determine the installed version, so assume critical update. 799 EXPECT_TRUE( 800 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 801 // Installed version before the critical update. 802 EXPECT_TRUE( 803 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 804 .IsValid()); 805 // Installed version equals the critical update. 806 EXPECT_FALSE( 807 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 808 .IsValid()); 809 } 810 811 // Test the case where the critical version is greater than the to-be-installed 812 // Chrome. 813 TEST_F(InstallerStateCriticalVersionTest, CriticalAfterPv) { 814 MockInstallerState& installer_state(Initialize(high_version_)); 815 816 EXPECT_TRUE(installer_state.critical_update_version().Equals( 817 *high_version_)); 818 // Critical update newer than the new version. 819 EXPECT_FALSE( 820 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 821 EXPECT_FALSE( 822 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 823 .IsValid()); 824 EXPECT_FALSE( 825 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 826 .IsValid()); 827 } 828