| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <windows.h> |
| |
| #include <fstream> |
| |
| #include "base/base_paths.h" |
| #include "base/command_line.h" |
| #include "base/file_util.h" |
| #include "base/files/file_enumerator.h" |
| #include "base/files/file_path.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/path_service.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/test_reg_util_win.h" |
| #include "base/version.h" |
| #include "base/win/registry.h" |
| #include "base/win/scoped_handle.h" |
| #include "chrome/common/chrome_constants.h" |
| #include "chrome/installer/test/alternate_version_generator.h" |
| #include "chrome/installer/util/fake_installation_state.h" |
| #include "chrome/installer/util/fake_product_state.h" |
| #include "chrome/installer/util/google_update_constants.h" |
| #include "chrome/installer/util/helper.h" |
| #include "chrome/installer/util/installation_state.h" |
| #include "chrome/installer/util/installer_state.h" |
| #include "chrome/installer/util/master_preferences.h" |
| #include "chrome/installer/util/product_unittest.h" |
| #include "chrome/installer/util/util_constants.h" |
| #include "chrome/installer/util/work_item.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #include "installer_util_strings.h" // NOLINT |
| |
| using base::win::RegKey; |
| using installer::InstallationState; |
| using installer::InstallerState; |
| using installer::MasterPreferences; |
| using registry_util::RegistryOverrideManager; |
| |
| class InstallerStateTest : public TestWithTempDirAndDeleteTempOverrideKeys { |
| protected: |
| }; |
| |
| // An installer state on which we can access otherwise protected members. |
| class MockInstallerState : public InstallerState { |
| public: |
| MockInstallerState() : InstallerState() { } |
| void set_target_path(const base::FilePath& target_path) { |
| target_path_ = target_path; |
| } |
| static bool IsFileInUse(const base::FilePath& file) { |
| return InstallerState::IsFileInUse(file); |
| } |
| const Version& critical_update_version() const { |
| return critical_update_version_; |
| } |
| void GetExistingExeVersions(std::set<std::string>* existing_version_strings) { |
| return InstallerState::GetExistingExeVersions(existing_version_strings); |
| } |
| }; |
| |
| // Simple function to dump some text into a new file. |
| void CreateTextFile(const std::wstring& filename, |
| const std::wstring& contents) { |
| std::ofstream file; |
| file.open(filename.c_str()); |
| ASSERT_TRUE(file.is_open()); |
| file << contents; |
| file.close(); |
| } |
| |
| void BuildSingleChromeState(const base::FilePath& target_dir, |
| MockInstallerState* installer_state) { |
| CommandLine cmd_line = CommandLine::FromString(L"setup.exe"); |
| MasterPreferences prefs(cmd_line); |
| InstallationState machine_state; |
| machine_state.Initialize(); |
| installer_state->Initialize(cmd_line, prefs, machine_state); |
| installer_state->set_target_path(target_dir); |
| EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER) |
| != NULL); |
| } |
| |
| wchar_t text_content_1[] = L"delete me"; |
| wchar_t text_content_2[] = L"delete me as well"; |
| |
| // Delete version directories. Everything lower than the given version |
| // should be deleted. |
| TEST_F(InstallerStateTest, Delete) { |
| // TODO(grt): move common stuff into the test fixture. |
| // Create a Chrome dir |
| base::FilePath chrome_dir(test_dir_.path()); |
| chrome_dir = chrome_dir.AppendASCII("chrome"); |
| base::CreateDirectory(chrome_dir); |
| ASSERT_TRUE(base::PathExists(chrome_dir)); |
| |
| base::FilePath chrome_dir_1(chrome_dir); |
| chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); |
| base::CreateDirectory(chrome_dir_1); |
| ASSERT_TRUE(base::PathExists(chrome_dir_1)); |
| |
| base::FilePath chrome_dir_2(chrome_dir); |
| chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); |
| base::CreateDirectory(chrome_dir_2); |
| ASSERT_TRUE(base::PathExists(chrome_dir_2)); |
| |
| base::FilePath chrome_dir_3(chrome_dir); |
| chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); |
| base::CreateDirectory(chrome_dir_3); |
| ASSERT_TRUE(base::PathExists(chrome_dir_3)); |
| |
| base::FilePath chrome_dir_4(chrome_dir); |
| chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); |
| base::CreateDirectory(chrome_dir_4); |
| ASSERT_TRUE(base::PathExists(chrome_dir_4)); |
| |
| base::FilePath chrome_dll_1(chrome_dir_1); |
| chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); |
| CreateTextFile(chrome_dll_1.value(), text_content_1); |
| ASSERT_TRUE(base::PathExists(chrome_dll_1)); |
| |
| base::FilePath chrome_dll_2(chrome_dir_2); |
| chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); |
| CreateTextFile(chrome_dll_2.value(), text_content_1); |
| ASSERT_TRUE(base::PathExists(chrome_dll_2)); |
| |
| base::FilePath chrome_dll_3(chrome_dir_3); |
| chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); |
| CreateTextFile(chrome_dll_3.value(), text_content_1); |
| ASSERT_TRUE(base::PathExists(chrome_dll_3)); |
| |
| base::FilePath chrome_dll_4(chrome_dir_4); |
| chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); |
| CreateTextFile(chrome_dll_4.value(), text_content_1); |
| ASSERT_TRUE(base::PathExists(chrome_dll_4)); |
| |
| MockInstallerState installer_state; |
| BuildSingleChromeState(chrome_dir, &installer_state); |
| Version latest_version("1.0.4.0"); |
| { |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| installer_state.RemoveOldVersionDirectories(latest_version, NULL, |
| temp_dir.path()); |
| } |
| |
| // old versions should be gone |
| EXPECT_FALSE(base::PathExists(chrome_dir_1)); |
| EXPECT_FALSE(base::PathExists(chrome_dir_2)); |
| EXPECT_FALSE(base::PathExists(chrome_dir_3)); |
| // the latest version should stay |
| EXPECT_TRUE(base::PathExists(chrome_dll_4)); |
| } |
| |
| // Delete older version directories, keeping the one in used intact. |
| TEST_F(InstallerStateTest, DeleteInUsed) { |
| // Create a Chrome dir |
| base::FilePath chrome_dir(test_dir_.path()); |
| chrome_dir = chrome_dir.AppendASCII("chrome"); |
| base::CreateDirectory(chrome_dir); |
| ASSERT_TRUE(base::PathExists(chrome_dir)); |
| |
| base::FilePath chrome_dir_1(chrome_dir); |
| chrome_dir_1 = chrome_dir_1.AppendASCII("1.0.1.0"); |
| base::CreateDirectory(chrome_dir_1); |
| ASSERT_TRUE(base::PathExists(chrome_dir_1)); |
| |
| base::FilePath chrome_dir_2(chrome_dir); |
| chrome_dir_2 = chrome_dir_2.AppendASCII("1.0.2.0"); |
| base::CreateDirectory(chrome_dir_2); |
| ASSERT_TRUE(base::PathExists(chrome_dir_2)); |
| |
| base::FilePath chrome_dir_3(chrome_dir); |
| chrome_dir_3 = chrome_dir_3.AppendASCII("1.0.3.0"); |
| base::CreateDirectory(chrome_dir_3); |
| ASSERT_TRUE(base::PathExists(chrome_dir_3)); |
| |
| base::FilePath chrome_dir_4(chrome_dir); |
| chrome_dir_4 = chrome_dir_4.AppendASCII("1.0.4.0"); |
| base::CreateDirectory(chrome_dir_4); |
| ASSERT_TRUE(base::PathExists(chrome_dir_4)); |
| |
| base::FilePath chrome_dll_1(chrome_dir_1); |
| chrome_dll_1 = chrome_dll_1.AppendASCII("chrome.dll"); |
| CreateTextFile(chrome_dll_1.value(), text_content_1); |
| ASSERT_TRUE(base::PathExists(chrome_dll_1)); |
| |
| base::FilePath chrome_dll_2(chrome_dir_2); |
| chrome_dll_2 = chrome_dll_2.AppendASCII("chrome.dll"); |
| CreateTextFile(chrome_dll_2.value(), text_content_1); |
| ASSERT_TRUE(base::PathExists(chrome_dll_2)); |
| |
| // Open the file to make it in use. |
| std::ofstream file; |
| file.open(chrome_dll_2.value().c_str()); |
| |
| base::FilePath chrome_othera_2(chrome_dir_2); |
| chrome_othera_2 = chrome_othera_2.AppendASCII("othera.dll"); |
| CreateTextFile(chrome_othera_2.value(), text_content_2); |
| ASSERT_TRUE(base::PathExists(chrome_othera_2)); |
| |
| base::FilePath chrome_otherb_2(chrome_dir_2); |
| chrome_otherb_2 = chrome_otherb_2.AppendASCII("otherb.dll"); |
| CreateTextFile(chrome_otherb_2.value(), text_content_2); |
| ASSERT_TRUE(base::PathExists(chrome_otherb_2)); |
| |
| base::FilePath chrome_dll_3(chrome_dir_3); |
| chrome_dll_3 = chrome_dll_3.AppendASCII("chrome.dll"); |
| CreateTextFile(chrome_dll_3.value(), text_content_1); |
| ASSERT_TRUE(base::PathExists(chrome_dll_3)); |
| |
| base::FilePath chrome_dll_4(chrome_dir_4); |
| chrome_dll_4 = chrome_dll_4.AppendASCII("chrome.dll"); |
| CreateTextFile(chrome_dll_4.value(), text_content_1); |
| ASSERT_TRUE(base::PathExists(chrome_dll_4)); |
| |
| MockInstallerState installer_state; |
| BuildSingleChromeState(chrome_dir, &installer_state); |
| Version latest_version("1.0.4.0"); |
| Version existing_version("1.0.1.0"); |
| { |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| installer_state.RemoveOldVersionDirectories(latest_version, |
| &existing_version, |
| temp_dir.path()); |
| } |
| |
| // the version defined as the existing version should stay |
| EXPECT_TRUE(base::PathExists(chrome_dir_1)); |
| // old versions not in used should be gone |
| EXPECT_FALSE(base::PathExists(chrome_dir_3)); |
| // every thing under in used version should stay |
| EXPECT_TRUE(base::PathExists(chrome_dir_2)); |
| EXPECT_TRUE(base::PathExists(chrome_dll_2)); |
| EXPECT_TRUE(base::PathExists(chrome_othera_2)); |
| EXPECT_TRUE(base::PathExists(chrome_otherb_2)); |
| // the latest version should stay |
| EXPECT_TRUE(base::PathExists(chrome_dll_4)); |
| } |
| |
| // Tests a few basic things of the Package class. Makes sure that the path |
| // operations are correct |
| TEST_F(InstallerStateTest, Basic) { |
| const bool multi_install = false; |
| const bool system_level = true; |
| CommandLine cmd_line = CommandLine::FromString( |
| std::wstring(L"setup.exe") + |
| (multi_install ? L" --multi-install --chrome" : L"") + |
| (system_level ? L" --system-level" : L"")); |
| MasterPreferences prefs(cmd_line); |
| InstallationState machine_state; |
| machine_state.Initialize(); |
| MockInstallerState installer_state; |
| installer_state.Initialize(cmd_line, prefs, machine_state); |
| installer_state.set_target_path(test_dir_.path()); |
| EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value()); |
| EXPECT_EQ(1U, installer_state.products().size()); |
| |
| const char kOldVersion[] = "1.2.3.4"; |
| const char kNewVersion[] = "2.3.4.5"; |
| |
| Version new_version(kNewVersion); |
| Version old_version(kOldVersion); |
| ASSERT_TRUE(new_version.IsValid()); |
| ASSERT_TRUE(old_version.IsValid()); |
| |
| base::FilePath installer_dir( |
| installer_state.GetInstallerDirectory(new_version)); |
| EXPECT_FALSE(installer_dir.empty()); |
| |
| base::FilePath new_version_dir(installer_state.target_path().Append( |
| base::UTF8ToWide(new_version.GetString()))); |
| base::FilePath old_version_dir(installer_state.target_path().Append( |
| base::UTF8ToWide(old_version.GetString()))); |
| |
| EXPECT_FALSE(base::PathExists(new_version_dir)); |
| EXPECT_FALSE(base::PathExists(old_version_dir)); |
| |
| EXPECT_FALSE(base::PathExists(installer_dir)); |
| base::CreateDirectory(installer_dir); |
| EXPECT_TRUE(base::PathExists(new_version_dir)); |
| |
| base::CreateDirectory(old_version_dir); |
| EXPECT_TRUE(base::PathExists(old_version_dir)); |
| |
| // Create a fake chrome.dll key file in the old version directory. This |
| // should prevent the old version directory from getting deleted. |
| base::FilePath old_chrome_dll(old_version_dir.Append(installer::kChromeDll)); |
| EXPECT_FALSE(base::PathExists(old_chrome_dll)); |
| |
| // Hold on to the file exclusively to prevent the directory from |
| // being deleted. |
| base::win::ScopedHandle file( |
| ::CreateFile(old_chrome_dll.value().c_str(), GENERIC_READ, |
| 0, NULL, OPEN_ALWAYS, 0, NULL)); |
| EXPECT_TRUE(file.IsValid()); |
| EXPECT_TRUE(base::PathExists(old_chrome_dll)); |
| |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| |
| // Don't explicitly tell the directory cleanup logic not to delete the |
| // old version, rely on the key files to keep it around. |
| installer_state.RemoveOldVersionDirectories(new_version, |
| NULL, |
| temp_dir.path()); |
| |
| // The old directory should still exist. |
| EXPECT_TRUE(base::PathExists(old_version_dir)); |
| EXPECT_TRUE(base::PathExists(new_version_dir)); |
| |
| // Now close the file handle to make it possible to delete our key file. |
| file.Close(); |
| |
| installer_state.RemoveOldVersionDirectories(new_version, |
| NULL, |
| temp_dir.path()); |
| // The new directory should still exist. |
| EXPECT_TRUE(base::PathExists(new_version_dir)); |
| |
| // Now, the old directory and key file should be gone. |
| EXPECT_FALSE(base::PathExists(old_chrome_dll)); |
| EXPECT_FALSE(base::PathExists(old_version_dir)); |
| } |
| |
| TEST_F(InstallerStateTest, WithProduct) { |
| const bool multi_install = false; |
| const bool system_level = true; |
| CommandLine cmd_line = CommandLine::FromString( |
| std::wstring(L"setup.exe") + |
| (multi_install ? L" --multi-install --chrome" : L"") + |
| (system_level ? L" --system-level" : L"")); |
| MasterPreferences prefs(cmd_line); |
| InstallationState machine_state; |
| machine_state.Initialize(); |
| MockInstallerState installer_state; |
| installer_state.Initialize(cmd_line, prefs, machine_state); |
| installer_state.set_target_path(test_dir_.path()); |
| EXPECT_EQ(1U, installer_state.products().size()); |
| EXPECT_EQ(system_level, installer_state.system_install()); |
| |
| const char kCurrentVersion[] = "1.2.3.4"; |
| Version current_version(kCurrentVersion); |
| |
| HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
| EXPECT_EQ(root, installer_state.root_key()); |
| |
| { |
| RegistryOverrideManager override_manager; |
| override_manager.OverrideRegistry(root, L"root_pit"); |
| BrowserDistribution* dist = BrowserDistribution::GetSpecificDistribution( |
| BrowserDistribution::CHROME_BROWSER); |
| RegKey chrome_key(root, dist->GetVersionKey().c_str(), KEY_ALL_ACCESS); |
| EXPECT_TRUE(chrome_key.Valid()); |
| if (chrome_key.Valid()) { |
| chrome_key.WriteValue(google_update::kRegVersionField, |
| base::UTF8ToWide( |
| current_version.GetString()).c_str()); |
| machine_state.Initialize(); |
| // TODO(tommi): Also test for when there exists a new_chrome.exe. |
| Version found_version(*installer_state.GetCurrentVersion(machine_state)); |
| EXPECT_TRUE(found_version.IsValid()); |
| if (found_version.IsValid()) |
| EXPECT_TRUE(current_version.Equals(found_version)); |
| } |
| } |
| } |
| |
| TEST_F(InstallerStateTest, InstallerResult) { |
| const bool system_level = true; |
| bool multi_install = false; |
| HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
| |
| RegKey key; |
| std::wstring launch_cmd = L"hey diddle diddle"; |
| std::wstring value; |
| DWORD dw_value; |
| |
| // check results for a fresh install of single Chrome |
| { |
| RegistryOverrideManager override_manager; |
| override_manager.OverrideRegistry(root, L"root_inst_res"); |
| CommandLine cmd_line = CommandLine::FromString(L"setup.exe --system-level"); |
| const MasterPreferences prefs(cmd_line); |
| InstallationState machine_state; |
| machine_state.Initialize(); |
| InstallerState state; |
| state.Initialize(cmd_line, prefs, machine_state); |
| state.WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS, |
| IDS_INSTALL_OS_ERROR_BASE, &launch_cmd); |
| BrowserDistribution* distribution = |
| BrowserDistribution::GetSpecificDistribution( |
| BrowserDistribution::CHROME_BROWSER); |
| EXPECT_EQ(ERROR_SUCCESS, |
| key.Open(root, distribution->GetStateKey().c_str(), KEY_READ)); |
| EXPECT_EQ(ERROR_SUCCESS, |
| key.ReadValueDW(installer::kInstallerResult, &dw_value)); |
| EXPECT_EQ(static_cast<DWORD>(0), dw_value); |
| EXPECT_EQ(ERROR_SUCCESS, |
| key.ReadValueDW(installer::kInstallerError, &dw_value)); |
| EXPECT_EQ(static_cast<DWORD>(installer::FIRST_INSTALL_SUCCESS), dw_value); |
| EXPECT_EQ(ERROR_SUCCESS, |
| key.ReadValue(installer::kInstallerResultUIString, &value)); |
| EXPECT_FALSE(value.empty()); |
| EXPECT_EQ(ERROR_SUCCESS, |
| key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value)); |
| EXPECT_EQ(launch_cmd, value); |
| } |
| |
| // check results for a fresh install of multi Chrome |
| { |
| RegistryOverrideManager override_manager; |
| override_manager.OverrideRegistry(root, L"root_inst_res"); |
| CommandLine cmd_line = CommandLine::FromString( |
| L"setup.exe --system-level --multi-install --chrome"); |
| const MasterPreferences prefs(cmd_line); |
| InstallationState machine_state; |
| machine_state.Initialize(); |
| InstallerState state; |
| state.Initialize(cmd_line, prefs, machine_state); |
| state.WriteInstallerResult(installer::FIRST_INSTALL_SUCCESS, 0, |
| &launch_cmd); |
| BrowserDistribution* distribution = |
| BrowserDistribution::GetSpecificDistribution( |
| BrowserDistribution::CHROME_BROWSER); |
| BrowserDistribution* binaries = |
| BrowserDistribution::GetSpecificDistribution( |
| BrowserDistribution::CHROME_BINARIES); |
| EXPECT_EQ(ERROR_SUCCESS, |
| key.Open(root, distribution->GetStateKey().c_str(), KEY_READ)); |
| EXPECT_EQ(ERROR_SUCCESS, |
| key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value)); |
| EXPECT_EQ(launch_cmd, value); |
| EXPECT_EQ(ERROR_SUCCESS, |
| key.Open(root, binaries->GetStateKey().c_str(), KEY_READ)); |
| EXPECT_EQ(ERROR_SUCCESS, |
| key.ReadValue(installer::kInstallerSuccessLaunchCmdLine, &value)); |
| EXPECT_EQ(launch_cmd, value); |
| key.Close(); |
| } |
| } |
| |
| // Test GetCurrentVersion when migrating single Chrome to multi |
| TEST_F(InstallerStateTest, GetCurrentVersionMigrateChrome) { |
| using installer::FakeInstallationState; |
| |
| const bool system_install = false; |
| FakeInstallationState machine_state; |
| |
| // Pretend that this version of single-install Chrome is already installed. |
| machine_state.AddChrome(system_install, false, |
| new Version(chrome::kChromeVersion)); |
| |
| // Now we're invoked to install multi Chrome. |
| CommandLine cmd_line( |
| CommandLine::FromString(L"setup.exe --multi-install --chrome")); |
| MasterPreferences prefs(cmd_line); |
| InstallerState installer_state; |
| installer_state.Initialize(cmd_line, prefs, machine_state); |
| |
| // Is the Chrome version picked up? |
| scoped_ptr<Version> version(installer_state.GetCurrentVersion(machine_state)); |
| EXPECT_TRUE(version.get() != NULL); |
| } |
| |
| TEST_F(InstallerStateTest, IsFileInUse) { |
| base::ScopedTempDir temp_dir; |
| ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| |
| base::FilePath temp_file; |
| ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file)); |
| |
| EXPECT_FALSE(MockInstallerState::IsFileInUse(temp_file)); |
| |
| { |
| // Open a handle to the file with the same access mode and sharing options |
| // as the loader. |
| base::win::ScopedHandle temp_handle( |
| CreateFile(temp_file.value().c_str(), |
| SYNCHRONIZE | FILE_EXECUTE, |
| FILE_SHARE_DELETE | FILE_SHARE_READ, |
| NULL, OPEN_EXISTING, 0, 0)); |
| ASSERT_TRUE(temp_handle != NULL); |
| |
| // The file should now be in use. |
| EXPECT_TRUE(MockInstallerState::IsFileInUse(temp_file)); |
| } |
| |
| // And once the handle is gone, it should no longer be in use. |
| EXPECT_FALSE(MockInstallerState::IsFileInUse(temp_file)); |
| } |
| |
| TEST_F(InstallerStateTest, RemoveOldVersionDirs) { |
| MockInstallerState installer_state; |
| installer_state.set_target_path(test_dir_.path()); |
| EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value()); |
| |
| const char kOldVersion[] = "2.0.0.0"; |
| const char kNewVersion[] = "3.0.0.0"; |
| const char kOldChromeExeVersion[] = "2.1.0.0"; |
| const char kChromeExeVersion[] = "2.1.1.1"; |
| const char kNewChromeExeVersion[] = "3.0.0.0"; |
| |
| Version new_version(kNewVersion); |
| Version old_version(kOldVersion); |
| Version old_chrome_exe_version(kOldChromeExeVersion); |
| Version chrome_exe_version(kChromeExeVersion); |
| Version new_chrome_exe_version(kNewChromeExeVersion); |
| |
| ASSERT_TRUE(new_version.IsValid()); |
| ASSERT_TRUE(old_version.IsValid()); |
| ASSERT_TRUE(old_chrome_exe_version.IsValid()); |
| ASSERT_TRUE(chrome_exe_version.IsValid()); |
| ASSERT_TRUE(new_chrome_exe_version.IsValid()); |
| |
| // Set up a bunch of version dir paths. |
| base::FilePath version_dirs[] = { |
| installer_state.target_path().Append(L"1.2.3.4"), |
| installer_state.target_path().Append(L"1.2.3.5"), |
| installer_state.target_path().Append(L"1.2.3.6"), |
| installer_state.target_path().Append(base::ASCIIToWide(kOldVersion)), |
| installer_state.target_path().Append( |
| base::ASCIIToWide(kOldChromeExeVersion)), |
| installer_state.target_path().Append(L"2.1.1.0"), |
| installer_state.target_path().Append(base::ASCIIToWide(kChromeExeVersion)), |
| installer_state.target_path().Append(base::ASCIIToWide(kNewVersion)), |
| installer_state.target_path().Append(L"3.9.1.1"), |
| }; |
| |
| // Create the version directories. |
| for (int i = 0; i < arraysize(version_dirs); i++) { |
| base::CreateDirectory(version_dirs[i]); |
| EXPECT_TRUE(base::PathExists(version_dirs[i])); |
| } |
| |
| // Create exes with the appropriate version resource. |
| // Use the current test exe as a baseline. |
| base::FilePath exe_path; |
| ASSERT_TRUE(PathService::Get(base::FILE_EXE, &exe_path)); |
| |
| struct target_info { |
| base::FilePath target_file; |
| const Version& target_version; |
| } targets[] = { |
| { installer_state.target_path().Append(installer::kChromeOldExe), |
| old_chrome_exe_version }, |
| { installer_state.target_path().Append(installer::kChromeExe), |
| chrome_exe_version }, |
| { installer_state.target_path().Append(installer::kChromeNewExe), |
| new_chrome_exe_version }, |
| }; |
| for (int i = 0; i < arraysize(targets); ++i) { |
| ASSERT_TRUE(upgrade_test::GenerateSpecificPEFileVersion( |
| exe_path, targets[i].target_file, targets[i].target_version)); |
| } |
| |
| // Call GetExistingExeVersions, validate that picks up the |
| // exe resources. |
| std::set<std::string> expected_exe_versions; |
| expected_exe_versions.insert(kOldChromeExeVersion); |
| expected_exe_versions.insert(kChromeExeVersion); |
| expected_exe_versions.insert(kNewChromeExeVersion); |
| |
| std::set<std::string> actual_exe_versions; |
| installer_state.GetExistingExeVersions(&actual_exe_versions); |
| EXPECT_EQ(expected_exe_versions, actual_exe_versions); |
| |
| // Call RemoveOldVersionDirectories |
| installer_state.RemoveOldVersionDirectories(new_version, |
| &old_version, |
| installer_state.target_path()); |
| |
| // What we expect to have left. |
| std::set<std::string> expected_remaining_dirs; |
| expected_remaining_dirs.insert(kOldVersion); |
| expected_remaining_dirs.insert(kNewVersion); |
| expected_remaining_dirs.insert(kOldChromeExeVersion); |
| expected_remaining_dirs.insert(kChromeExeVersion); |
| expected_remaining_dirs.insert(kNewChromeExeVersion); |
| |
| // Enumerate dirs in target_path(), ensure only desired remain. |
| base::FileEnumerator version_enum(installer_state.target_path(), false, |
| base::FileEnumerator::DIRECTORIES); |
| for (base::FilePath next_version = version_enum.Next(); !next_version.empty(); |
| next_version = version_enum.Next()) { |
| base::FilePath dir_name(next_version.BaseName()); |
| Version version(base::UTF16ToASCII(dir_name.value())); |
| if (version.IsValid()) { |
| EXPECT_TRUE(expected_remaining_dirs.erase(version.GetString())) |
| << "Unexpected version dir found: " << version.GetString(); |
| } |
| } |
| |
| std::set<std::string>::const_iterator iter( |
| expected_remaining_dirs.begin()); |
| for (; iter != expected_remaining_dirs.end(); ++iter) |
| ADD_FAILURE() << "Expected to find version dir for " << *iter; |
| } |
| |
| TEST_F(InstallerStateTest, InitializeTwice) { |
| InstallationState machine_state; |
| machine_state.Initialize(); |
| |
| InstallerState installer_state; |
| |
| // Initialize the instance to install multi Chrome. |
| { |
| CommandLine cmd_line( |
| CommandLine::FromString(L"setup.exe --multi-install --chrome")); |
| MasterPreferences prefs(cmd_line); |
| installer_state.Initialize(cmd_line, prefs, machine_state); |
| } |
| // Confirm the expected state. |
| EXPECT_EQ(InstallerState::USER_LEVEL, installer_state.level()); |
| EXPECT_EQ(InstallerState::MULTI_PACKAGE, installer_state.package_type()); |
| EXPECT_EQ(InstallerState::MULTI_INSTALL, installer_state.operation()); |
| EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(), |
| BrowserDistribution::GetSpecificDistribution( |
| BrowserDistribution::CHROME_BINARIES)-> |
| GetInstallSubDir().c_str())); |
| EXPECT_FALSE(installer_state.verbose_logging()); |
| EXPECT_EQ(installer_state.state_key(), |
| BrowserDistribution::GetSpecificDistribution( |
| BrowserDistribution::CHROME_BROWSER)->GetStateKey()); |
| EXPECT_EQ(installer_state.state_type(), BrowserDistribution::CHROME_BROWSER); |
| EXPECT_TRUE(installer_state.multi_package_binaries_distribution()); |
| EXPECT_TRUE(installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER)); |
| |
| // Now initialize it to install system-level single Chrome. |
| { |
| CommandLine cmd_line( |
| CommandLine::FromString(L"setup.exe --system-level --verbose-logging")); |
| MasterPreferences prefs(cmd_line); |
| installer_state.Initialize(cmd_line, prefs, machine_state); |
| } |
| |
| // Confirm that the old state is gone. |
| EXPECT_EQ(InstallerState::SYSTEM_LEVEL, installer_state.level()); |
| EXPECT_EQ(InstallerState::SINGLE_PACKAGE, installer_state.package_type()); |
| EXPECT_EQ(InstallerState::SINGLE_INSTALL_OR_UPDATE, |
| installer_state.operation()); |
| EXPECT_TRUE(wcsstr(installer_state.target_path().value().c_str(), |
| BrowserDistribution::GetSpecificDistribution( |
| BrowserDistribution::CHROME_BROWSER)-> |
| GetInstallSubDir().c_str())); |
| EXPECT_TRUE(installer_state.verbose_logging()); |
| EXPECT_EQ(installer_state.state_key(), |
| BrowserDistribution::GetSpecificDistribution( |
| BrowserDistribution::CHROME_BROWSER)->GetStateKey()); |
| EXPECT_EQ(installer_state.state_type(), BrowserDistribution::CHROME_BROWSER); |
| EXPECT_TRUE(installer_state.FindProduct(BrowserDistribution::CHROME_BROWSER)); |
| } |
| |
| // A fixture for testing InstallerState::DetermineCriticalVersion. Individual |
| // tests must invoke Initialize() with a critical version. |
| class InstallerStateCriticalVersionTest : public ::testing::Test { |
| protected: |
| InstallerStateCriticalVersionTest() : cmd_line_(CommandLine::NO_PROGRAM) {} |
| |
| // Creates a set of versions for use by all test runs. |
| static void SetUpTestCase() { |
| low_version_ = new Version("15.0.874.106"); |
| opv_version_ = new Version("15.0.874.255"); |
| middle_version_ = new Version("16.0.912.32"); |
| pv_version_ = new Version("16.0.912.255"); |
| high_version_ = new Version("17.0.932.0"); |
| } |
| |
| // Cleans up versions used by all test runs. |
| static void TearDownTestCase() { |
| delete low_version_; |
| delete opv_version_; |
| delete middle_version_; |
| delete pv_version_; |
| delete high_version_; |
| } |
| |
| // Initializes the InstallerState to use for a test run. The returned |
| // instance's critical update version is set to |version|. |version| may be |
| // NULL, in which case the critical update version is unset. |
| MockInstallerState& Initialize(const Version* version) { |
| cmd_line_ = version == NULL ? |
| CommandLine::FromString(L"setup.exe") : |
| CommandLine::FromString( |
| L"setup.exe --critical-update-version=" + |
| base::ASCIIToWide(version->GetString())); |
| prefs_.reset(new MasterPreferences(cmd_line_)); |
| machine_state_.Initialize(); |
| installer_state_.Initialize(cmd_line_, *prefs_, machine_state_); |
| return installer_state_; |
| } |
| |
| static Version* low_version_; |
| static Version* opv_version_; |
| static Version* middle_version_; |
| static Version* pv_version_; |
| static Version* high_version_; |
| |
| CommandLine cmd_line_; |
| scoped_ptr<MasterPreferences> prefs_; |
| InstallationState machine_state_; |
| MockInstallerState installer_state_; |
| }; |
| |
| Version* InstallerStateCriticalVersionTest::low_version_ = NULL; |
| Version* InstallerStateCriticalVersionTest::opv_version_ = NULL; |
| Version* InstallerStateCriticalVersionTest::middle_version_ = NULL; |
| Version* InstallerStateCriticalVersionTest::pv_version_ = NULL; |
| Version* InstallerStateCriticalVersionTest::high_version_ = NULL; |
| |
| // Test the case where the critical version is less than the currently-running |
| // Chrome. The critical version is ignored since it doesn't apply. |
| TEST_F(InstallerStateCriticalVersionTest, CriticalBeforeOpv) { |
| MockInstallerState& installer_state(Initialize(low_version_)); |
| |
| EXPECT_TRUE(installer_state.critical_update_version().Equals(*low_version_)); |
| // Unable to determine the installed version, so assume critical update. |
| EXPECT_TRUE( |
| installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); |
| // Installed version is past the critical update. |
| EXPECT_FALSE( |
| installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) |
| .IsValid()); |
| // Installed version is past the critical update. |
| EXPECT_FALSE( |
| installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) |
| .IsValid()); |
| } |
| |
| // Test the case where the critical version is equal to the currently-running |
| // Chrome. The critical version is ignored since it doesn't apply. |
| TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsOpv) { |
| MockInstallerState& installer_state(Initialize(opv_version_)); |
| |
| EXPECT_TRUE(installer_state.critical_update_version().Equals(*opv_version_)); |
| // Unable to determine the installed version, so assume critical update. |
| EXPECT_TRUE( |
| installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); |
| // Installed version equals the critical update. |
| EXPECT_FALSE( |
| installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) |
| .IsValid()); |
| // Installed version equals the critical update. |
| EXPECT_FALSE( |
| installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) |
| .IsValid()); |
| } |
| |
| // Test the case where the critical version is between the currently-running |
| // Chrome and the to-be-installed Chrome. |
| TEST_F(InstallerStateCriticalVersionTest, CriticalBetweenOpvAndPv) { |
| MockInstallerState& installer_state(Initialize(middle_version_)); |
| |
| EXPECT_TRUE(installer_state.critical_update_version().Equals( |
| *middle_version_)); |
| // Unable to determine the installed version, so assume critical update. |
| EXPECT_TRUE( |
| installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); |
| // Installed version before the critical update. |
| EXPECT_TRUE( |
| installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) |
| .IsValid()); |
| // Installed version is past the critical update. |
| EXPECT_FALSE( |
| installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) |
| .IsValid()); |
| } |
| |
| // Test the case where the critical version is the same as the to-be-installed |
| // Chrome. |
| TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsPv) { |
| MockInstallerState& installer_state(Initialize(pv_version_)); |
| |
| EXPECT_TRUE(installer_state.critical_update_version().Equals( |
| *pv_version_)); |
| // Unable to determine the installed version, so assume critical update. |
| EXPECT_TRUE( |
| installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); |
| // Installed version before the critical update. |
| EXPECT_TRUE( |
| installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) |
| .IsValid()); |
| // Installed version equals the critical update. |
| EXPECT_FALSE( |
| installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) |
| .IsValid()); |
| } |
| |
| // Test the case where the critical version is greater than the to-be-installed |
| // Chrome. |
| TEST_F(InstallerStateCriticalVersionTest, CriticalAfterPv) { |
| MockInstallerState& installer_state(Initialize(high_version_)); |
| |
| EXPECT_TRUE(installer_state.critical_update_version().Equals( |
| *high_version_)); |
| // Critical update newer than the new version. |
| EXPECT_FALSE( |
| installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid()); |
| EXPECT_FALSE( |
| installer_state.DetermineCriticalVersion(opv_version_, *pv_version_) |
| .IsValid()); |
| EXPECT_FALSE( |
| installer_state.DetermineCriticalVersion(pv_version_, *pv_version_) |
| .IsValid()); |
| } |