installer_state_unittest.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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/process_util.h" 17#include "base/strings/string_util.h" 18#include "base/strings/utf_string_conversions.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 39using base::win::RegKey; 40using installer::InstallationState; 41using installer::InstallerState; 42using installer::MasterPreferences; 43using registry_util::RegistryOverrideManager; 44 45class InstallerStateTest : public TestWithTempDirAndDeleteTempOverrideKeys { 46 protected: 47}; 48 49// An installer state on which we can access otherwise protected members. 50class 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. 68void 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 77void 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 EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_FRAME) 88 == NULL); 89} 90 91wchar_t text_content_1[] = L"delete me"; 92wchar_t text_content_2[] = L"delete me as well"; 93 94// Delete version directories. Everything lower than the given version 95// should be deleted. 96TEST_F(InstallerStateTest, Delete) { 97 // TODO(grt): move common stuff into the test fixture. 98 // Create a Chrome dir 99 base::FilePath chrome_dir(test_dir_.path()); 100 chrome_dir = chrome_dir.AppendASCII("chrome"); 101 file_util::CreateDirectory(chrome_dir); 102 ASSERT_TRUE(base::PathExists(chrome_dir)); 103 104 base::FilePath chrome_dir_1(chrome_dir); 105 chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); 106 file_util::CreateDirectory(chrome_dir_1); 107 ASSERT_TRUE(base::PathExists(chrome_dir_1)); 108 109 base::FilePath chrome_dir_2(chrome_dir); 110 chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); 111 file_util::CreateDirectory(chrome_dir_2); 112 ASSERT_TRUE(base::PathExists(chrome_dir_2)); 113 114 base::FilePath chrome_dir_3(chrome_dir); 115 chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); 116 file_util::CreateDirectory(chrome_dir_3); 117 ASSERT_TRUE(base::PathExists(chrome_dir_3)); 118 119 base::FilePath chrome_dir_4(chrome_dir); 120 chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); 121 file_util::CreateDirectory(chrome_dir_4); 122 ASSERT_TRUE(base::PathExists(chrome_dir_4)); 123 124 base::FilePath chrome_dll_1(chrome_dir_1); 125 chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); 126 CreateTextFile(chrome_dll_1.value(), text_content_1); 127 ASSERT_TRUE(base::PathExists(chrome_dll_1)); 128 129 base::FilePath chrome_dll_2(chrome_dir_2); 130 chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); 131 CreateTextFile(chrome_dll_2.value(), text_content_1); 132 ASSERT_TRUE(base::PathExists(chrome_dll_2)); 133 134 base::FilePath chrome_dll_3(chrome_dir_3); 135 chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); 136 CreateTextFile(chrome_dll_3.value(), text_content_1); 137 ASSERT_TRUE(base::PathExists(chrome_dll_3)); 138 139 base::FilePath chrome_dll_4(chrome_dir_4); 140 chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); 141 CreateTextFile(chrome_dll_4.value(), text_content_1); 142 ASSERT_TRUE(base::PathExists(chrome_dll_4)); 143 144 MockInstallerState installer_state; 145 BuildSingleChromeState(chrome_dir, &installer_state); 146 Version latest_version("1.0.4.0"); 147 { 148 base::ScopedTempDir temp_dir; 149 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 150 installer_state.RemoveOldVersionDirectories(latest_version, NULL, 151 temp_dir.path()); 152 } 153 154 // old versions should be gone 155 EXPECT_FALSE(base::PathExists(chrome_dir_1)); 156 EXPECT_FALSE(base::PathExists(chrome_dir_2)); 157 EXPECT_FALSE(base::PathExists(chrome_dir_3)); 158 // the latest version should stay 159 EXPECT_TRUE(base::PathExists(chrome_dll_4)); 160} 161 162// Delete older version directories, keeping the one in used intact. 163TEST_F(InstallerStateTest, DeleteInUsed) { 164 // Create a Chrome dir 165 base::FilePath chrome_dir(test_dir_.path()); 166 chrome_dir = chrome_dir.AppendASCII("chrome"); 167 file_util::CreateDirectory(chrome_dir); 168 ASSERT_TRUE(base::PathExists(chrome_dir)); 169 170 base::FilePath chrome_dir_1(chrome_dir); 171 chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); 172 file_util::CreateDirectory(chrome_dir_1); 173 ASSERT_TRUE(base::PathExists(chrome_dir_1)); 174 175 base::FilePath chrome_dir_2(chrome_dir); 176 chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); 177 file_util::CreateDirectory(chrome_dir_2); 178 ASSERT_TRUE(base::PathExists(chrome_dir_2)); 179 180 base::FilePath chrome_dir_3(chrome_dir); 181 chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); 182 file_util::CreateDirectory(chrome_dir_3); 183 ASSERT_TRUE(base::PathExists(chrome_dir_3)); 184 185 base::FilePath chrome_dir_4(chrome_dir); 186 chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); 187 file_util::CreateDirectory(chrome_dir_4); 188 ASSERT_TRUE(base::PathExists(chrome_dir_4)); 189 190 base::FilePath chrome_dll_1(chrome_dir_1); 191 chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); 192 CreateTextFile(chrome_dll_1.value(), text_content_1); 193 ASSERT_TRUE(base::PathExists(chrome_dll_1)); 194 195 base::FilePath chrome_dll_2(chrome_dir_2); 196 chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); 197 CreateTextFile(chrome_dll_2.value(), text_content_1); 198 ASSERT_TRUE(base::PathExists(chrome_dll_2)); 199 200 // Open the file to make it in use. 201 std::ofstream file; 202 file.open(chrome_dll_2.value().c_str()); 203 204 base::FilePath chrome_othera_2(chrome_dir_2); 205 chrome_othera_2 = chrome_othera_2.AppendASCII("othera.dll"); 206 CreateTextFile(chrome_othera_2.value(), text_content_2); 207 ASSERT_TRUE(base::PathExists(chrome_othera_2)); 208 209 base::FilePath chrome_otherb_2(chrome_dir_2); 210 chrome_otherb_2 = chrome_otherb_2.AppendASCII("otherb.dll"); 211 CreateTextFile(chrome_otherb_2.value(), text_content_2); 212 ASSERT_TRUE(base::PathExists(chrome_otherb_2)); 213 214 base::FilePath chrome_dll_3(chrome_dir_3); 215 chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); 216 CreateTextFile(chrome_dll_3.value(), text_content_1); 217 ASSERT_TRUE(base::PathExists(chrome_dll_3)); 218 219 base::FilePath chrome_dll_4(chrome_dir_4); 220 chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); 221 CreateTextFile(chrome_dll_4.value(), text_content_1); 222 ASSERT_TRUE(base::PathExists(chrome_dll_4)); 223 224 MockInstallerState installer_state; 225 BuildSingleChromeState(chrome_dir, &installer_state); 226 Version latest_version("1.0.4.0"); 227 Version existing_version("1.0.1.0"); 228 { 229 base::ScopedTempDir temp_dir; 230 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 231 installer_state.RemoveOldVersionDirectories(latest_version, 232 &existing_version, 233 temp_dir.path()); 234 } 235 236 // the version defined as the existing version should stay 237 EXPECT_TRUE(base::PathExists(chrome_dir_1)); 238 // old versions not in used should be gone 239 EXPECT_FALSE(base::PathExists(chrome_dir_3)); 240 // every thing under in used version should stay 241 EXPECT_TRUE(base::PathExists(chrome_dir_2)); 242 EXPECT_TRUE(base::PathExists(chrome_dll_2)); 243 EXPECT_TRUE(base::PathExists(chrome_othera_2)); 244 EXPECT_TRUE(base::PathExists(chrome_otherb_2)); 245 // the latest version should stay 246 EXPECT_TRUE(base::PathExists(chrome_dll_4)); 247} 248 249// Tests a few basic things of the Package class. Makes sure that the path 250// operations are correct 251TEST_F(InstallerStateTest, Basic) { 252 const bool multi_install = false; 253 const bool system_level = true; 254 CommandLine cmd_line = CommandLine::FromString( 255 std::wstring(L"setup.exe") + 256 (multi_install ? L" --multi-install --chrome" : L"") + 257 (system_level ? L" --system-level" : L"")); 258 MasterPreferences prefs(cmd_line); 259 InstallationState machine_state; 260 machine_state.Initialize(); 261 MockInstallerState installer_state; 262 installer_state.Initialize(cmd_line, prefs, machine_state); 263 installer_state.set_target_path(test_dir_.path()); 264 EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value()); 265 EXPECT_EQ(1U, installer_state.products().size()); 266 267 const char kOldVersion[] = "1.2.3.4"; 268 const char kNewVersion[] = "2.3.4.5"; 269 270 Version new_version(kNewVersion); 271 Version old_version(kOldVersion); 272 ASSERT_TRUE(new_version.IsValid()); 273 ASSERT_TRUE(old_version.IsValid()); 274 275 base::FilePath installer_dir( 276 installer_state.GetInstallerDirectory(new_version)); 277 EXPECT_FALSE(installer_dir.empty()); 278 279 base::FilePath new_version_dir(installer_state.target_path().Append( 280 UTF8ToWide(new_version.GetString()))); 281 base::FilePath old_version_dir(installer_state.target_path().Append( 282 UTF8ToWide(old_version.GetString()))); 283 284 EXPECT_FALSE(base::PathExists(new_version_dir)); 285 EXPECT_FALSE(base::PathExists(old_version_dir)); 286 287 EXPECT_FALSE(base::PathExists(installer_dir)); 288 file_util::CreateDirectory(installer_dir); 289 EXPECT_TRUE(base::PathExists(new_version_dir)); 290 291 file_util::CreateDirectory(old_version_dir); 292 EXPECT_TRUE(base::PathExists(old_version_dir)); 293 294 // Create a fake chrome.dll key file in the old version directory. This 295 // should prevent the old version directory from getting deleted. 296 base::FilePath old_chrome_dll(old_version_dir.Append(installer::kChromeDll)); 297 EXPECT_FALSE(base::PathExists(old_chrome_dll)); 298 299 // Hold on to the file exclusively to prevent the directory from 300 // being deleted. 301 base::win::ScopedHandle file( 302 ::CreateFile(old_chrome_dll.value().c_str(), GENERIC_READ, 303 0, NULL, OPEN_ALWAYS, 0, NULL)); 304 EXPECT_TRUE(file.IsValid()); 305 EXPECT_TRUE(base::PathExists(old_chrome_dll)); 306 307 base::ScopedTempDir temp_dir; 308 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 309 310 // Don't explicitly tell the directory cleanup logic not to delete the 311 // old version, rely on the key files to keep it around. 312 installer_state.RemoveOldVersionDirectories(new_version, 313 NULL, 314 temp_dir.path()); 315 316 // The old directory should still exist. 317 EXPECT_TRUE(base::PathExists(old_version_dir)); 318 EXPECT_TRUE(base::PathExists(new_version_dir)); 319 320 // Now close the file handle to make it possible to delete our key file. 321 file.Close(); 322 323 installer_state.RemoveOldVersionDirectories(new_version, 324 NULL, 325 temp_dir.path()); 326 // The new directory should still exist. 327 EXPECT_TRUE(base::PathExists(new_version_dir)); 328 329 // Now, the old directory and key file should be gone. 330 EXPECT_FALSE(base::PathExists(old_chrome_dll)); 331 EXPECT_FALSE(base::PathExists(old_version_dir)); 332} 333 334TEST_F(InstallerStateTest, WithProduct) { 335 const bool multi_install = false; 336 const bool system_level = true; 337 CommandLine cmd_line = CommandLine::FromString( 338 std::wstring(L"setup.exe") + 339 (multi_install ? L" --multi-install --chrome" : L"") + 340 (system_level ? L" --system-level" : L"")); 341 MasterPreferences prefs(cmd_line); 342 InstallationState machine_state; 343 machine_state.Initialize(); 344 MockInstallerState installer_state; 345 installer_state.Initialize(cmd_line, prefs, machine_state); 346 installer_state.set_target_path(test_dir_.path()); 347 EXPECT_EQ(1U, installer_state.products().size()); 348 EXPECT_EQ(system_level, installer_state.system_install()); 349 350 const char kCurrentVersion[] = "1.2.3.4"; 351 Version current_version(kCurrentVersion); 352 353 HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 354 EXPECT_EQ(root, installer_state.root_key()); 355 356 { 357 RegistryOverrideManager override_manager; 358 override_manager.OverrideRegistry(root, L"root_pit"); 359 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( 360 BrowserDistribution::CHROME_BROWSER); 361 RegKey chrome_key(root, dist->GetVersionKey().c_str(), KEY_ALL_ACCESS); 362 EXPECT_TRUE(chrome_key.Valid()); 363 if (chrome_key.Valid()) { 364 chrome_key.WriteValue(google_update::kRegVersionField, 365 UTF8ToWide(current_version.GetString()).c_str()); 366 machine_state.Initialize(); 367 // TODO(tommi): Also test for when there exists a new_chrome.exe. 368 Version found_version(*installer_state.GetCurrentVersion(machine_state)); 369 EXPECT_TRUE(found_version.IsValid()); 370 if (found_version.IsValid()) 371 EXPECT_TRUE(current_version.Equals(found_version)); 372 } 373 } 374} 375 376TEST_F(InstallerStateTest, InstallerResult) { 377 const bool system_level = true; 378 bool multi_install = false; 379 HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 380 381 RegKey key; 382 std::wstring launch_cmd = L"hey diddle diddle"; 383 std::wstring value; 384 DWORD dw_value; 385 386 // check results for a fresh install of single Chrome 387 { 388 RegistryOverrideManager override_manager; 389 override_manager.OverrideRegistry(root, L"root_inst_res"); 390 CommandLine cmd_line = CommandLine::FromString(L"setup.exe --system-level"); 391 const MasterPreferences prefs(cmd_line); 392 InstallationState machine_state; 393 machine_state.Initialize(); 394 InstallerState state; 395 state.Initialize(cmd_line, prefs, machine_state); 396 state.WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS, 397 IDS_INSTALL_OS_ERROR_BASE, &launch_cmd); 398 BrowserDistribution* distribution = 399 BrowserDistribution::GetSpecificDistribution( 400 BrowserDistribution::CHROME_BROWSER); 401 EXPECT_EQ(ERROR_SUCCESS, 402 key.Open(root, distribution->GetStateKey().c_str(), KEY_READ)); 403 EXPECT_EQ(ERROR_SUCCESS, 404 key.ReadValueDW(installer::kInstallerResult, &dw_value)); 405 EXPECT_EQ(static_cast<DWORD>(0), dw_value); 406 EXPECT_EQ(ERROR_SUCCESS, 407 key.ReadValueDW(installer::kInstallerError, &dw_value)); 408 EXPECT_EQ(static_cast<DWORD>(installer::FIRST_INSTALL_SUCCESS), dw_value); 409 EXPECT_EQ(ERROR_SUCCESS, 410 key.ReadValue(installer::kInstallerResultUIString, &value)); 411 EXPECT_FALSE(value.empty()); 412 EXPECT_EQ(ERROR_SUCCESS, 413 key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value)); 414 EXPECT_EQ(launch_cmd, value); 415 } 416 417 // check results for a fresh install of multi Chrome 418 { 419 RegistryOverrideManager override_manager; 420 override_manager.OverrideRegistry(root, L"root_inst_res"); 421 CommandLine cmd_line = CommandLine::FromString( 422 L"setup.exe --system-level --multi-install --chrome"); 423 const MasterPreferences prefs(cmd_line); 424 InstallationState machine_state; 425 machine_state.Initialize(); 426 InstallerState state; 427 state.Initialize(cmd_line, prefs, machine_state); 428 state.WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS, 0, 429 &launch_cmd); 430 BrowserDistribution* distribution = 431 BrowserDistribution::GetSpecificDistribution( 432 BrowserDistribution::CHROME_BROWSER); 433 BrowserDistribution* binaries = 434 BrowserDistribution::GetSpecificDistribution( 435 BrowserDistribution::CHROME_BINARIES); 436 EXPECT_EQ(ERROR_SUCCESS, 437 key.Open(root, distribution->GetStateKey().c_str(), KEY_READ)); 438 EXPECT_EQ(ERROR_SUCCESS, 439 key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value)); 440 EXPECT_EQ(launch_cmd, value); 441 EXPECT_EQ(ERROR_SUCCESS, 442 key.Open(root, binaries->GetStateKey().c_str(), KEY_READ)); 443 EXPECT_EQ(ERROR_SUCCESS, 444 key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value)); 445 EXPECT_EQ(launch_cmd, value); 446 key.Close(); 447 } 448} 449 450// Test GetCurrentVersion when migrating single Chrome to multi 451TEST_F(InstallerStateTest, GetCurrentVersionMigrateChrome) { 452 using installer::FakeInstallationState; 453 454 const bool system_install = false; 455 FakeInstallationState machine_state; 456 457 // Pretend that this version of single-install Chrome is already installed. 458 machine_state.AddChrome(system_install, false, 459 new Version(chrome::kChromeVersion)); 460 461 // Now we're invoked to install multi Chrome. 462 CommandLine cmd_line( 463 CommandLine::FromString(L"setup.exe --multi-install --chrome")); 464 MasterPreferences prefs(cmd_line); 465 InstallerState installer_state; 466 installer_state.Initialize(cmd_line, prefs, machine_state); 467 468 // Is the Chrome version picked up? 469 scoped_ptr<Version> version(installer_state.GetCurrentVersion(machine_state)); 470 EXPECT_TRUE(version.get() != NULL); 471} 472 473TEST_F(InstallerStateTest, IsFileInUse) { 474 base::ScopedTempDir temp_dir; 475 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 476 477 base::FilePath temp_file; 478 ASSERT_TRUE(file_util::CreateTemporaryFileInDir(temp_dir.path(), &temp_file)); 479 480 EXPECT_FALSE(MockInstallerState::IsFileInUse(temp_file)); 481 482 { 483 // Open a handle to the file with the same access mode and sharing options 484 // as the loader. 485 base::win::ScopedHandle temp_handle( 486 CreateFile(temp_file.value().c_str(), 487 SYNCHRONIZE | FILE_EXECUTE, 488 FILE_SHARE_DELETE | FILE_SHARE_READ, 489 NULL, OPEN_EXISTING, 0, 0)); 490 ASSERT_TRUE(temp_handle != NULL); 491 492 // The file should now be in use. 493 EXPECT_TRUE(MockInstallerState::IsFileInUse(temp_file)); 494 } 495 496 // And once the handle is gone, it should no longer be in use. 497 EXPECT_FALSE(MockInstallerState::IsFileInUse(temp_file)); 498} 499 500TEST_F(InstallerStateTest, RemoveOldVersionDirs) { 501 MockInstallerState installer_state; 502 installer_state.set_target_path(test_dir_.path()); 503 EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value()); 504 505 const char kOldVersion[] = "2.0.0.0"; 506 const char kNewVersion[] = "3.0.0.0"; 507 const char kOldChromeExeVersion[] = "2.1.0.0"; 508 const char kChromeExeVersion[] = "2.1.1.1"; 509 const char kNewChromeExeVersion[] = "3.0.0.0"; 510 511 Version new_version(kNewVersion); 512 Version old_version(kOldVersion); 513 Version old_chrome_exe_version(kOldChromeExeVersion); 514 Version chrome_exe_version(kChromeExeVersion); 515 Version new_chrome_exe_version(kNewChromeExeVersion); 516 517 ASSERT_TRUE(new_version.IsValid()); 518 ASSERT_TRUE(old_version.IsValid()); 519 ASSERT_TRUE(old_chrome_exe_version.IsValid()); 520 ASSERT_TRUE(chrome_exe_version.IsValid()); 521 ASSERT_TRUE(new_chrome_exe_version.IsValid()); 522 523 // Set up a bunch of version dir paths. 524 base::FilePath version_dirs[] = { 525 installer_state.target_path().Append(L"1.2.3.4"), 526 installer_state.target_path().Append(L"1.2.3.5"), 527 installer_state.target_path().Append(L"1.2.3.6"), 528 installer_state.target_path().Append(ASCIIToWide(kOldVersion)), 529 installer_state.target_path().Append(ASCIIToWide(kOldChromeExeVersion)), 530 installer_state.target_path().Append(L"2.1.1.0"), 531 installer_state.target_path().Append(ASCIIToWide(kChromeExeVersion)), 532 installer_state.target_path().Append(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 file_util::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(WideToASCII(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 607// A fixture for testing InstallerState::DetermineCriticalVersion. Individual 608// tests must invoke Initialize() with a critical version. 609class InstallerStateCriticalVersionTest : public ::testing::Test { 610 protected: 611 InstallerStateCriticalVersionTest() : cmd_line_(CommandLine::NO_PROGRAM) {} 612 613 // Creates a set of versions for use by all test runs. 614 static void SetUpTestCase() { 615 low_version_ = new Version("15.0.874.106"); 616 opv_version_ = new Version("15.0.874.255"); 617 middle_version_ = new Version("16.0.912.32"); 618 pv_version_ = new Version("16.0.912.255"); 619 high_version_ = new Version("17.0.932.0"); 620 } 621 622 // Cleans up versions used by all test runs. 623 static void TearDownTestCase() { 624 delete low_version_; 625 delete opv_version_; 626 delete middle_version_; 627 delete pv_version_; 628 delete high_version_; 629 } 630 631 // Initializes the InstallerState to use for a test run. The returned 632 // instance's critical update version is set to |version|. |version| may be 633 // NULL, in which case the critical update version is unset. 634 MockInstallerState& Initialize(const Version* version) { 635 cmd_line_ = version == NULL ? 636 CommandLine::FromString(L"setup.exe") : 637 CommandLine::FromString( 638 L"setup.exe --critical-update-version=" + 639 ASCIIToWide(version->GetString())); 640 prefs_.reset(new MasterPreferences(cmd_line_)); 641 machine_state_.Initialize(); 642 installer_state_.Initialize(cmd_line_, *prefs_, machine_state_); 643 return installer_state_; 644 } 645 646 static Version* low_version_; 647 static Version* opv_version_; 648 static Version* middle_version_; 649 static Version* pv_version_; 650 static Version* high_version_; 651 652 CommandLine cmd_line_; 653 scoped_ptr<MasterPreferences> prefs_; 654 InstallationState machine_state_; 655 MockInstallerState installer_state_; 656}; 657 658Version* InstallerStateCriticalVersionTest::low_version_ = NULL; 659Version* InstallerStateCriticalVersionTest::opv_version_ = NULL; 660Version* InstallerStateCriticalVersionTest::middle_version_ = NULL; 661Version* InstallerStateCriticalVersionTest::pv_version_ = NULL; 662Version* InstallerStateCriticalVersionTest::high_version_ = NULL; 663 664// Test the case where the critical version is less than the currently-running 665// Chrome. The critical version is ignored since it doesn't apply. 666TEST_F(InstallerStateCriticalVersionTest, CriticalBeforeOpv) { 667 MockInstallerState& installer_state(Initialize(low_version_)); 668 669 EXPECT_TRUE(installer_state.critical_update_version().Equals(*low_version_)); 670 // Unable to determine the installed version, so assume critical update. 671 EXPECT_TRUE( 672 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 673 // Installed version is past the critical update. 674 EXPECT_FALSE( 675 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 676 .IsValid()); 677 // Installed version is past the critical update. 678 EXPECT_FALSE( 679 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 680 .IsValid()); 681} 682 683// Test the case where the critical version is equal to the currently-running 684// Chrome. The critical version is ignored since it doesn't apply. 685TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsOpv) { 686 MockInstallerState& installer_state(Initialize(opv_version_)); 687 688 EXPECT_TRUE(installer_state.critical_update_version().Equals(*opv_version_)); 689 // Unable to determine the installed version, so assume critical update. 690 EXPECT_TRUE( 691 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 692 // Installed version equals the critical update. 693 EXPECT_FALSE( 694 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 695 .IsValid()); 696 // Installed version equals the critical update. 697 EXPECT_FALSE( 698 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 699 .IsValid()); 700} 701 702// Test the case where the critical version is between the currently-running 703// Chrome and the to-be-installed Chrome. 704TEST_F(InstallerStateCriticalVersionTest, CriticalBetweenOpvAndPv) { 705 MockInstallerState& installer_state(Initialize(middle_version_)); 706 707 EXPECT_TRUE(installer_state.critical_update_version().Equals( 708 *middle_version_)); 709 // Unable to determine the installed version, so assume critical update. 710 EXPECT_TRUE( 711 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 712 // Installed version before the critical update. 713 EXPECT_TRUE( 714 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 715 .IsValid()); 716 // Installed version is past the critical update. 717 EXPECT_FALSE( 718 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 719 .IsValid()); 720} 721 722// Test the case where the critical version is the same as the to-be-installed 723// Chrome. 724TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsPv) { 725 MockInstallerState& installer_state(Initialize(pv_version_)); 726 727 EXPECT_TRUE(installer_state.critical_update_version().Equals( 728 *pv_version_)); 729 // Unable to determine the installed version, so assume critical update. 730 EXPECT_TRUE( 731 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 732 // Installed version before the critical update. 733 EXPECT_TRUE( 734 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 735 .IsValid()); 736 // Installed version equals the critical update. 737 EXPECT_FALSE( 738 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 739 .IsValid()); 740} 741 742// Test the case where the critical version is greater than the to-be-installed 743// Chrome. 744TEST_F(InstallerStateCriticalVersionTest, CriticalAfterPv) { 745 MockInstallerState& installer_state(Initialize(high_version_)); 746 747 EXPECT_TRUE(installer_state.critical_update_version().Equals( 748 *high_version_)); 749 // Critical update newer than the new version. 750 EXPECT_FALSE( 751 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 752 EXPECT_FALSE( 753 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 754 .IsValid()); 755 EXPECT_FALSE( 756 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 757 .IsValid()); 758} 759