installer_state_unittest.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
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 38using base::win::RegKey; 39using installer::InstallationState; 40using installer::InstallerState; 41using installer::MasterPreferences; 42using registry_util::RegistryOverrideManager; 43 44class InstallerStateTest : public TestWithTempDirAndDeleteTempOverrideKeys { 45 protected: 46}; 47 48// An installer state on which we can access otherwise protected members. 49class 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. 67void 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 76void 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 EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_FRAME) 87 == NULL); 88} 89 90wchar_t text_content_1[] = L"delete me"; 91wchar_t text_content_2[] = L"delete me as well"; 92 93// Delete version directories. Everything lower than the given version 94// should be deleted. 95TEST_F(InstallerStateTest, Delete) { 96 // TODO(grt): move common stuff into the test fixture. 97 // Create a Chrome dir 98 base::FilePath chrome_dir(test_dir_.path()); 99 chrome_dir = chrome_dir.AppendASCII("chrome"); 100 base::CreateDirectory(chrome_dir); 101 ASSERT_TRUE(base::PathExists(chrome_dir)); 102 103 base::FilePath chrome_dir_1(chrome_dir); 104 chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); 105 base::CreateDirectory(chrome_dir_1); 106 ASSERT_TRUE(base::PathExists(chrome_dir_1)); 107 108 base::FilePath chrome_dir_2(chrome_dir); 109 chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); 110 base::CreateDirectory(chrome_dir_2); 111 ASSERT_TRUE(base::PathExists(chrome_dir_2)); 112 113 base::FilePath chrome_dir_3(chrome_dir); 114 chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); 115 base::CreateDirectory(chrome_dir_3); 116 ASSERT_TRUE(base::PathExists(chrome_dir_3)); 117 118 base::FilePath chrome_dir_4(chrome_dir); 119 chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); 120 base::CreateDirectory(chrome_dir_4); 121 ASSERT_TRUE(base::PathExists(chrome_dir_4)); 122 123 base::FilePath chrome_dll_1(chrome_dir_1); 124 chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); 125 CreateTextFile(chrome_dll_1.value(), text_content_1); 126 ASSERT_TRUE(base::PathExists(chrome_dll_1)); 127 128 base::FilePath chrome_dll_2(chrome_dir_2); 129 chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); 130 CreateTextFile(chrome_dll_2.value(), text_content_1); 131 ASSERT_TRUE(base::PathExists(chrome_dll_2)); 132 133 base::FilePath chrome_dll_3(chrome_dir_3); 134 chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); 135 CreateTextFile(chrome_dll_3.value(), text_content_1); 136 ASSERT_TRUE(base::PathExists(chrome_dll_3)); 137 138 base::FilePath chrome_dll_4(chrome_dir_4); 139 chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); 140 CreateTextFile(chrome_dll_4.value(), text_content_1); 141 ASSERT_TRUE(base::PathExists(chrome_dll_4)); 142 143 MockInstallerState installer_state; 144 BuildSingleChromeState(chrome_dir, &installer_state); 145 Version latest_version("1.0.4.0"); 146 { 147 base::ScopedTempDir temp_dir; 148 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 149 installer_state.RemoveOldVersionDirectories(latest_version, NULL, 150 temp_dir.path()); 151 } 152 153 // old versions should be gone 154 EXPECT_FALSE(base::PathExists(chrome_dir_1)); 155 EXPECT_FALSE(base::PathExists(chrome_dir_2)); 156 EXPECT_FALSE(base::PathExists(chrome_dir_3)); 157 // the latest version should stay 158 EXPECT_TRUE(base::PathExists(chrome_dll_4)); 159} 160 161// Delete older version directories, keeping the one in used intact. 162TEST_F(InstallerStateTest, DeleteInUsed) { 163 // Create a Chrome dir 164 base::FilePath chrome_dir(test_dir_.path()); 165 chrome_dir = chrome_dir.AppendASCII("chrome"); 166 base::CreateDirectory(chrome_dir); 167 ASSERT_TRUE(base::PathExists(chrome_dir)); 168 169 base::FilePath chrome_dir_1(chrome_dir); 170 chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); 171 base::CreateDirectory(chrome_dir_1); 172 ASSERT_TRUE(base::PathExists(chrome_dir_1)); 173 174 base::FilePath chrome_dir_2(chrome_dir); 175 chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); 176 base::CreateDirectory(chrome_dir_2); 177 ASSERT_TRUE(base::PathExists(chrome_dir_2)); 178 179 base::FilePath chrome_dir_3(chrome_dir); 180 chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); 181 base::CreateDirectory(chrome_dir_3); 182 ASSERT_TRUE(base::PathExists(chrome_dir_3)); 183 184 base::FilePath chrome_dir_4(chrome_dir); 185 chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); 186 base::CreateDirectory(chrome_dir_4); 187 ASSERT_TRUE(base::PathExists(chrome_dir_4)); 188 189 base::FilePath chrome_dll_1(chrome_dir_1); 190 chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); 191 CreateTextFile(chrome_dll_1.value(), text_content_1); 192 ASSERT_TRUE(base::PathExists(chrome_dll_1)); 193 194 base::FilePath chrome_dll_2(chrome_dir_2); 195 chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); 196 CreateTextFile(chrome_dll_2.value(), text_content_1); 197 ASSERT_TRUE(base::PathExists(chrome_dll_2)); 198 199 // Open the file to make it in use. 200 std::ofstream file; 201 file.open(chrome_dll_2.value().c_str()); 202 203 base::FilePath chrome_othera_2(chrome_dir_2); 204 chrome_othera_2 = chrome_othera_2.AppendASCII("othera.dll"); 205 CreateTextFile(chrome_othera_2.value(), text_content_2); 206 ASSERT_TRUE(base::PathExists(chrome_othera_2)); 207 208 base::FilePath chrome_otherb_2(chrome_dir_2); 209 chrome_otherb_2 = chrome_otherb_2.AppendASCII("otherb.dll"); 210 CreateTextFile(chrome_otherb_2.value(), text_content_2); 211 ASSERT_TRUE(base::PathExists(chrome_otherb_2)); 212 213 base::FilePath chrome_dll_3(chrome_dir_3); 214 chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); 215 CreateTextFile(chrome_dll_3.value(), text_content_1); 216 ASSERT_TRUE(base::PathExists(chrome_dll_3)); 217 218 base::FilePath chrome_dll_4(chrome_dir_4); 219 chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); 220 CreateTextFile(chrome_dll_4.value(), text_content_1); 221 ASSERT_TRUE(base::PathExists(chrome_dll_4)); 222 223 MockInstallerState installer_state; 224 BuildSingleChromeState(chrome_dir, &installer_state); 225 Version latest_version("1.0.4.0"); 226 Version existing_version("1.0.1.0"); 227 { 228 base::ScopedTempDir temp_dir; 229 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 230 installer_state.RemoveOldVersionDirectories(latest_version, 231 &existing_version, 232 temp_dir.path()); 233 } 234 235 // the version defined as the existing version should stay 236 EXPECT_TRUE(base::PathExists(chrome_dir_1)); 237 // old versions not in used should be gone 238 EXPECT_FALSE(base::PathExists(chrome_dir_3)); 239 // every thing under in used version should stay 240 EXPECT_TRUE(base::PathExists(chrome_dir_2)); 241 EXPECT_TRUE(base::PathExists(chrome_dll_2)); 242 EXPECT_TRUE(base::PathExists(chrome_othera_2)); 243 EXPECT_TRUE(base::PathExists(chrome_otherb_2)); 244 // the latest version should stay 245 EXPECT_TRUE(base::PathExists(chrome_dll_4)); 246} 247 248// Tests a few basic things of the Package class. Makes sure that the path 249// operations are correct 250TEST_F(InstallerStateTest, Basic) { 251 const bool multi_install = false; 252 const bool system_level = true; 253 CommandLine cmd_line = CommandLine::FromString( 254 std::wstring(L"setup.exe") + 255 (multi_install ? L" --multi-install --chrome" : L"") + 256 (system_level ? L" --system-level" : L"")); 257 MasterPreferences prefs(cmd_line); 258 InstallationState machine_state; 259 machine_state.Initialize(); 260 MockInstallerState installer_state; 261 installer_state.Initialize(cmd_line, prefs, machine_state); 262 installer_state.set_target_path(test_dir_.path()); 263 EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value()); 264 EXPECT_EQ(1U, installer_state.products().size()); 265 266 const char kOldVersion[] = "1.2.3.4"; 267 const char kNewVersion[] = "2.3.4.5"; 268 269 Version new_version(kNewVersion); 270 Version old_version(kOldVersion); 271 ASSERT_TRUE(new_version.IsValid()); 272 ASSERT_TRUE(old_version.IsValid()); 273 274 base::FilePath installer_dir( 275 installer_state.GetInstallerDirectory(new_version)); 276 EXPECT_FALSE(installer_dir.empty()); 277 278 base::FilePath new_version_dir(installer_state.target_path().Append( 279 UTF8ToWide(new_version.GetString()))); 280 base::FilePath old_version_dir(installer_state.target_path().Append( 281 UTF8ToWide(old_version.GetString()))); 282 283 EXPECT_FALSE(base::PathExists(new_version_dir)); 284 EXPECT_FALSE(base::PathExists(old_version_dir)); 285 286 EXPECT_FALSE(base::PathExists(installer_dir)); 287 base::CreateDirectory(installer_dir); 288 EXPECT_TRUE(base::PathExists(new_version_dir)); 289 290 base::CreateDirectory(old_version_dir); 291 EXPECT_TRUE(base::PathExists(old_version_dir)); 292 293 // Create a fake chrome.dll key file in the old version directory. This 294 // should prevent the old version directory from getting deleted. 295 base::FilePath old_chrome_dll(old_version_dir.Append(installer::kChromeDll)); 296 EXPECT_FALSE(base::PathExists(old_chrome_dll)); 297 298 // Hold on to the file exclusively to prevent the directory from 299 // being deleted. 300 base::win::ScopedHandle file( 301 ::CreateFile(old_chrome_dll.value().c_str(), GENERIC_READ, 302 0, NULL, OPEN_ALWAYS, 0, NULL)); 303 EXPECT_TRUE(file.IsValid()); 304 EXPECT_TRUE(base::PathExists(old_chrome_dll)); 305 306 base::ScopedTempDir temp_dir; 307 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 308 309 // Don't explicitly tell the directory cleanup logic not to delete the 310 // old version, rely on the key files to keep it around. 311 installer_state.RemoveOldVersionDirectories(new_version, 312 NULL, 313 temp_dir.path()); 314 315 // The old directory should still exist. 316 EXPECT_TRUE(base::PathExists(old_version_dir)); 317 EXPECT_TRUE(base::PathExists(new_version_dir)); 318 319 // Now close the file handle to make it possible to delete our key file. 320 file.Close(); 321 322 installer_state.RemoveOldVersionDirectories(new_version, 323 NULL, 324 temp_dir.path()); 325 // The new directory should still exist. 326 EXPECT_TRUE(base::PathExists(new_version_dir)); 327 328 // Now, the old directory and key file should be gone. 329 EXPECT_FALSE(base::PathExists(old_chrome_dll)); 330 EXPECT_FALSE(base::PathExists(old_version_dir)); 331} 332 333TEST_F(InstallerStateTest, WithProduct) { 334 const bool multi_install = false; 335 const bool system_level = true; 336 CommandLine cmd_line = CommandLine::FromString( 337 std::wstring(L"setup.exe") + 338 (multi_install ? L" --multi-install --chrome" : L"") + 339 (system_level ? L" --system-level" : L"")); 340 MasterPreferences prefs(cmd_line); 341 InstallationState machine_state; 342 machine_state.Initialize(); 343 MockInstallerState installer_state; 344 installer_state.Initialize(cmd_line, prefs, machine_state); 345 installer_state.set_target_path(test_dir_.path()); 346 EXPECT_EQ(1U, installer_state.products().size()); 347 EXPECT_EQ(system_level, installer_state.system_install()); 348 349 const char kCurrentVersion[] = "1.2.3.4"; 350 Version current_version(kCurrentVersion); 351 352 HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 353 EXPECT_EQ(root, installer_state.root_key()); 354 355 { 356 RegistryOverrideManager override_manager; 357 override_manager.OverrideRegistry(root, L"root_pit"); 358 BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( 359 BrowserDistribution::CHROME_BROWSER); 360 RegKey chrome_key(root, dist->GetVersionKey().c_str(), KEY_ALL_ACCESS); 361 EXPECT_TRUE(chrome_key.Valid()); 362 if (chrome_key.Valid()) { 363 chrome_key.WriteValue(google_update::kRegVersionField, 364 UTF8ToWide(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 375TEST_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, L"root_inst_res"); 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, L"root_inst_res"); 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 450TEST_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 472TEST_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 != NULL); 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 499TEST_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(ASCIIToWide(kOldVersion)), 528 installer_state.target_path().Append(ASCIIToWide(kOldChromeExeVersion)), 529 installer_state.target_path().Append(L"2.1.1.0"), 530 installer_state.target_path().Append(ASCIIToWide(kChromeExeVersion)), 531 installer_state.target_path().Append(ASCIIToWide(kNewVersion)), 532 installer_state.target_path().Append(L"3.9.1.1"), 533 }; 534 535 // Create the version directories. 536 for (int i = 0; i < arraysize(version_dirs); i++) { 537 base::CreateDirectory(version_dirs[i]); 538 EXPECT_TRUE(base::PathExists(version_dirs[i])); 539 } 540 541 // Create exes with the appropriate version resource. 542 // Use the current test exe as a baseline. 543 base::FilePath exe_path; 544 ASSERT_TRUE(PathService::Get(base::FILE_EXE, &exe_path)); 545 546 struct target_info { 547 base::FilePath target_file; 548 const Version& target_version; 549 } targets[] = { 550 { installer_state.target_path().Append(installer::kChromeOldExe), 551 old_chrome_exe_version }, 552 { installer_state.target_path().Append(installer::kChromeExe), 553 chrome_exe_version }, 554 { installer_state.target_path().Append(installer::kChromeNewExe), 555 new_chrome_exe_version }, 556 }; 557 for (int i = 0; i < arraysize(targets); ++i) { 558 ASSERT_TRUE(upgrade_test::GenerateSpecificPEFileVersion( 559 exe_path, targets[i].target_file, targets[i].target_version)); 560 } 561 562 // Call GetExistingExeVersions, validate that picks up the 563 // exe resources. 564 std::set<std::string> expected_exe_versions; 565 expected_exe_versions.insert(kOldChromeExeVersion); 566 expected_exe_versions.insert(kChromeExeVersion); 567 expected_exe_versions.insert(kNewChromeExeVersion); 568 569 std::set<std::string> actual_exe_versions; 570 installer_state.GetExistingExeVersions(&actual_exe_versions); 571 EXPECT_EQ(expected_exe_versions, actual_exe_versions); 572 573 // Call RemoveOldVersionDirectories 574 installer_state.RemoveOldVersionDirectories(new_version, 575 &old_version, 576 installer_state.target_path()); 577 578 // What we expect to have left. 579 std::set<std::string> expected_remaining_dirs; 580 expected_remaining_dirs.insert(kOldVersion); 581 expected_remaining_dirs.insert(kNewVersion); 582 expected_remaining_dirs.insert(kOldChromeExeVersion); 583 expected_remaining_dirs.insert(kChromeExeVersion); 584 expected_remaining_dirs.insert(kNewChromeExeVersion); 585 586 // Enumerate dirs in target_path(), ensure only desired remain. 587 base::FileEnumerator version_enum(installer_state.target_path(), false, 588 base::FileEnumerator::DIRECTORIES); 589 for (base::FilePath next_version = version_enum.Next(); !next_version.empty(); 590 next_version = version_enum.Next()) { 591 base::FilePath dir_name(next_version.BaseName()); 592 Version version(WideToASCII(dir_name.value())); 593 if (version.IsValid()) { 594 EXPECT_TRUE(expected_remaining_dirs.erase(version.GetString())) 595 << "Unexpected version dir found: " << version.GetString(); 596 } 597 } 598 599 std::set<std::string>::const_iterator iter( 600 expected_remaining_dirs.begin()); 601 for (; iter != expected_remaining_dirs.end(); ++iter) 602 ADD_FAILURE() << "Expected to find version dir for " << *iter; 603} 604 605TEST_F(InstallerStateTest, InitializeTwice) { 606 InstallationState machine_state; 607 machine_state.Initialize(); 608 609 InstallerState installer_state; 610 611 // Initialize the instance to install multi Chrome. 612 { 613 CommandLine cmd_line( 614 CommandLine::FromString(L"setup.exe --multi-install --chrome")); 615 MasterPreferences prefs(cmd_line); 616 installer_state.Initialize(cmd_line, prefs, machine_state); 617 } 618 // Confirm the expected state. 619 EXPECT_EQ(InstallerState::USER_LEVEL, installer_state.level()); 620 EXPECT_EQ(InstallerState::MULTI_PACKAGE, installer_state.package_type()); 621 EXPECT_EQ(InstallerState::MULTI_INSTALL, installer_state.operation()); 622 EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(), 623 BrowserDistribution::GetSpecificDistribution( 624 BrowserDistribution::CHROME_BINARIES)-> 625 GetInstallSubDir().c_str())); 626 EXPECT_FALSE(installer_state.verbose_logging()); 627 EXPECT_EQ(installer_state.state_key(), 628 BrowserDistribution::GetSpecificDistribution( 629 BrowserDistribution::CHROME_BROWSER)->GetStateKey()); 630 EXPECT_EQ(installer_state.state_type(), BrowserDistribution::CHROME_BROWSER); 631 EXPECT_TRUE(installer_state.multi_package_binaries_distribution()); 632 EXPECT_TRUE(installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER)); 633 EXPECT_FALSE(installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)); 634 635 // Now initialize it to install system-level single Chrome Frame. 636 { 637 CommandLine cmd_line( 638 CommandLine::FromString(L"setup.exe --system-level --chrome-frame " 639 L"--verbose-logging")); 640 MasterPreferences prefs(cmd_line); 641 installer_state.Initialize(cmd_line, prefs, machine_state); 642 } 643 644 // Confirm that the old state is gone. 645 EXPECT_EQ(InstallerState::SYSTEM_LEVEL, installer_state.level()); 646 EXPECT_EQ(InstallerState::SINGLE_PACKAGE, installer_state.package_type()); 647 EXPECT_EQ(InstallerState::SINGLE_INSTALL_OR_UPDATE, 648 installer_state.operation()); 649 EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(), 650 BrowserDistribution::GetSpecificDistribution( 651 BrowserDistribution::CHROME_FRAME)-> 652 GetInstallSubDir().c_str())); 653 EXPECT_TRUE(installer_state.verbose_logging()); 654 // state_key and type are wrong in unittests since it is set based on the 655 // current process's BrowserDistribution. 656 // EXPECT_EQ(installer_state.state_key(), 657 // BrowserDistribution::GetSpecificDistribution( 658 // BrowserDistribution::CHROME_FRAME)->GetStateKey()); 659 // EXPECT_EQ(installer_state.state_type(), BrowserDistribution::CHROME_FRAME); 660 EXPECT_FALSE( 661 installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER)); 662 EXPECT_TRUE(installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)); 663} 664 665// A fixture for testing InstallerState::DetermineCriticalVersion. Individual 666// tests must invoke Initialize() with a critical version. 667class InstallerStateCriticalVersionTest : public ::testing::Test { 668 protected: 669 InstallerStateCriticalVersionTest() : cmd_line_(CommandLine::NO_PROGRAM) {} 670 671 // Creates a set of versions for use by all test runs. 672 static void SetUpTestCase() { 673 low_version_ = new Version("15.0.874.106"); 674 opv_version_ = new Version("15.0.874.255"); 675 middle_version_ = new Version("16.0.912.32"); 676 pv_version_ = new Version("16.0.912.255"); 677 high_version_ = new Version("17.0.932.0"); 678 } 679 680 // Cleans up versions used by all test runs. 681 static void TearDownTestCase() { 682 delete low_version_; 683 delete opv_version_; 684 delete middle_version_; 685 delete pv_version_; 686 delete high_version_; 687 } 688 689 // Initializes the InstallerState to use for a test run. The returned 690 // instance's critical update version is set to |version|. |version| may be 691 // NULL, in which case the critical update version is unset. 692 MockInstallerState& Initialize(const Version* version) { 693 cmd_line_ = version == NULL ? 694 CommandLine::FromString(L"setup.exe") : 695 CommandLine::FromString( 696 L"setup.exe --critical-update-version=" + 697 ASCIIToWide(version->GetString())); 698 prefs_.reset(new MasterPreferences(cmd_line_)); 699 machine_state_.Initialize(); 700 installer_state_.Initialize(cmd_line_, *prefs_, machine_state_); 701 return installer_state_; 702 } 703 704 static Version* low_version_; 705 static Version* opv_version_; 706 static Version* middle_version_; 707 static Version* pv_version_; 708 static Version* high_version_; 709 710 CommandLine cmd_line_; 711 scoped_ptr<MasterPreferences> prefs_; 712 InstallationState machine_state_; 713 MockInstallerState installer_state_; 714}; 715 716Version* InstallerStateCriticalVersionTest::low_version_ = NULL; 717Version* InstallerStateCriticalVersionTest::opv_version_ = NULL; 718Version* InstallerStateCriticalVersionTest::middle_version_ = NULL; 719Version* InstallerStateCriticalVersionTest::pv_version_ = NULL; 720Version* InstallerStateCriticalVersionTest::high_version_ = NULL; 721 722// Test the case where the critical version is less than the currently-running 723// Chrome. The critical version is ignored since it doesn't apply. 724TEST_F(InstallerStateCriticalVersionTest, CriticalBeforeOpv) { 725 MockInstallerState& installer_state(Initialize(low_version_)); 726 727 EXPECT_TRUE(installer_state.critical_update_version().Equals(*low_version_)); 728 // Unable to determine the installed version, so assume critical update. 729 EXPECT_TRUE( 730 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 731 // Installed version is past the critical update. 732 EXPECT_FALSE( 733 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 734 .IsValid()); 735 // Installed version is past the critical update. 736 EXPECT_FALSE( 737 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 738 .IsValid()); 739} 740 741// Test the case where the critical version is equal to the currently-running 742// Chrome. The critical version is ignored since it doesn't apply. 743TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsOpv) { 744 MockInstallerState& installer_state(Initialize(opv_version_)); 745 746 EXPECT_TRUE(installer_state.critical_update_version().Equals(*opv_version_)); 747 // Unable to determine the installed version, so assume critical update. 748 EXPECT_TRUE( 749 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 750 // Installed version equals the critical update. 751 EXPECT_FALSE( 752 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 753 .IsValid()); 754 // Installed version equals the critical update. 755 EXPECT_FALSE( 756 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 757 .IsValid()); 758} 759 760// Test the case where the critical version is between the currently-running 761// Chrome and the to-be-installed Chrome. 762TEST_F(InstallerStateCriticalVersionTest, CriticalBetweenOpvAndPv) { 763 MockInstallerState& installer_state(Initialize(middle_version_)); 764 765 EXPECT_TRUE(installer_state.critical_update_version().Equals( 766 *middle_version_)); 767 // Unable to determine the installed version, so assume critical update. 768 EXPECT_TRUE( 769 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 770 // Installed version before the critical update. 771 EXPECT_TRUE( 772 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 773 .IsValid()); 774 // Installed version is past the critical update. 775 EXPECT_FALSE( 776 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 777 .IsValid()); 778} 779 780// Test the case where the critical version is the same as the to-be-installed 781// Chrome. 782TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsPv) { 783 MockInstallerState& installer_state(Initialize(pv_version_)); 784 785 EXPECT_TRUE(installer_state.critical_update_version().Equals( 786 *pv_version_)); 787 // Unable to determine the installed version, so assume critical update. 788 EXPECT_TRUE( 789 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 790 // Installed version before the critical update. 791 EXPECT_TRUE( 792 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 793 .IsValid()); 794 // Installed version equals the critical update. 795 EXPECT_FALSE( 796 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 797 .IsValid()); 798} 799 800// Test the case where the critical version is greater than the to-be-installed 801// Chrome. 802TEST_F(InstallerStateCriticalVersionTest, CriticalAfterPv) { 803 MockInstallerState& installer_state(Initialize(high_version_)); 804 805 EXPECT_TRUE(installer_state.critical_update_version().Equals( 806 *high_version_)); 807 // Critical update newer than the new version. 808 EXPECT_FALSE( 809 installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); 810 EXPECT_FALSE( 811 installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) 812 .IsValid()); 813 EXPECT_FALSE( 814 installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) 815 .IsValid()); 816} 817