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