Home | History | Annotate | Download | only in util
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <windows.h>
      6 
      7 #include <fstream>
      8 
      9 #include "base/base_paths.h"
     10 #include "base/command_line.h"
     11 #include "base/file_util.h"
     12 #include "base/files/file_enumerator.h"
     13 #include "base/files/file_path.h"
     14 #include "base/files/scoped_temp_dir.h"
     15 #include "base/path_service.h"
     16 #include "base/strings/string_util.h"
     17 #include "base/strings/utf_string_conversions.h"
     18 #include "base/test/test_reg_util_win.h"
     19 #include "base/version.h"
     20 #include "base/win/registry.h"
     21 #include "base/win/scoped_handle.h"
     22 #include "chrome/common/chrome_constants.h"
     23 #include "chrome/installer/test/alternate_version_generator.h"
     24 #include "chrome/installer/util/fake_installation_state.h"
     25 #include "chrome/installer/util/fake_product_state.h"
     26 #include "chrome/installer/util/google_update_constants.h"
     27 #include "chrome/installer/util/helper.h"
     28 #include "chrome/installer/util/installation_state.h"
     29 #include "chrome/installer/util/installer_state.h"
     30 #include "chrome/installer/util/master_preferences.h"
     31 #include "chrome/installer/util/product_unittest.h"
     32 #include "chrome/installer/util/util_constants.h"
     33 #include "chrome/installer/util/work_item.h"
     34 #include "testing/gtest/include/gtest/gtest.h"
     35 
     36 #include "installer_util_strings.h"  // NOLINT
     37 
     38 using base::win::RegKey;
     39 using installer::InstallationState;
     40 using installer::InstallerState;
     41 using installer::MasterPreferences;
     42 using registry_util::RegistryOverrideManager;
     43 
     44 class InstallerStateTest : public TestWithTempDirAndDeleteTempOverrideKeys {
     45  protected:
     46 };
     47 
     48 // An installer state on which we can access otherwise protected members.
     49 class MockInstallerState : public InstallerState {
     50  public:
     51   MockInstallerState() : InstallerState() { }
     52   void set_target_path(const base::FilePath& target_path) {
     53     target_path_ = target_path;
     54   }
     55   static bool IsFileInUse(const base::FilePath& file) {
     56     return InstallerState::IsFileInUse(file);
     57   }
     58   const Version& critical_update_version() const {
     59     return critical_update_version_;
     60   }
     61   void GetExistingExeVersions(std::set<std::string>* existing_version_strings) {
     62     return InstallerState::GetExistingExeVersions(existing_version_strings);
     63   }
     64 };
     65 
     66 // Simple function to dump some text into a new file.
     67 void CreateTextFile(const std::wstring& filename,
     68                     const std::wstring& contents) {
     69   std::ofstream file;
     70   file.open(filename.c_str());
     71   ASSERT_TRUE(file.is_open());
     72   file << contents;
     73   file.close();
     74 }
     75 
     76 void BuildSingleChromeState(const base::FilePath& target_dir,
     77                             MockInstallerState* installer_state) {
     78   CommandLine cmd_line = CommandLine::FromString(L"setup.exe");
     79   MasterPreferences prefs(cmd_line);
     80   InstallationState machine_state;
     81   machine_state.Initialize();
     82   installer_state->Initialize(cmd_line, prefs, machine_state);
     83   installer_state->set_target_path(target_dir);
     84   EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER)
     85       != NULL);
     86   EXPECT_TRUE(installer_state->FindProduct(BrowserDistribution::CHROME_FRAME)
     87       == NULL);
     88 }
     89 
     90 wchar_t text_content_1[] = L"delete me";
     91 wchar_t text_content_2[] = L"delete me as well";
     92 
     93 // Delete version directories. Everything lower than the given version
     94 // should be deleted.
     95 TEST_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   file_util::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   file_util::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   file_util::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   file_util::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   file_util::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.
    162 TEST_F(InstallerStateTest, DeleteInUsed) {
    163   // Create a Chrome dir
    164   base::FilePath chrome_dir(test_dir_.path());
    165   chrome_dir = chrome_dir.AppendASCII("chrome");
    166   file_util::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   file_util::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   file_util::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   file_util::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   file_util::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
    250 TEST_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   file_util::CreateDirectory(installer_dir);
    288   EXPECT_TRUE(base::PathExists(new_version_dir));
    289 
    290   file_util::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 
    333 TEST_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 
    375 TEST_F(InstallerStateTest, InstallerResult) {
    376   const bool system_level = true;
    377   bool multi_install = false;
    378   HKEY root = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
    379 
    380   RegKey key;
    381   std::wstring launch_cmd = L"hey diddle diddle";
    382   std::wstring value;
    383   DWORD dw_value;
    384 
    385   // check results for a fresh install of single Chrome
    386   {
    387     RegistryOverrideManager override_manager;
    388     override_manager.OverrideRegistry(root, 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
    450 TEST_F(InstallerStateTest, GetCurrentVersionMigrateChrome) {
    451   using installer::FakeInstallationState;
    452 
    453   const bool system_install = false;
    454   FakeInstallationState machine_state;
    455 
    456   // Pretend that this version of single-install Chrome is already installed.
    457   machine_state.AddChrome(system_install, false,
    458                           new Version(chrome::kChromeVersion));
    459 
    460   // Now we're invoked to install multi Chrome.
    461   CommandLine cmd_line(
    462       CommandLine::FromString(L"setup.exe --multi-install --chrome"));
    463   MasterPreferences prefs(cmd_line);
    464   InstallerState installer_state;
    465   installer_state.Initialize(cmd_line, prefs, machine_state);
    466 
    467   // Is the Chrome version picked up?
    468   scoped_ptr<Version> version(installer_state.GetCurrentVersion(machine_state));
    469   EXPECT_TRUE(version.get() != NULL);
    470 }
    471 
    472 TEST_F(InstallerStateTest, IsFileInUse) {
    473   base::ScopedTempDir temp_dir;
    474   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    475 
    476   base::FilePath temp_file;
    477   ASSERT_TRUE(file_util::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 
    499 TEST_F(InstallerStateTest, RemoveOldVersionDirs) {
    500   MockInstallerState installer_state;
    501   installer_state.set_target_path(test_dir_.path());
    502   EXPECT_EQ(test_dir_.path().value(), installer_state.target_path().value());
    503 
    504   const char kOldVersion[] = "2.0.0.0";
    505   const char kNewVersion[] = "3.0.0.0";
    506   const char kOldChromeExeVersion[] = "2.1.0.0";
    507   const char kChromeExeVersion[] = "2.1.1.1";
    508   const char kNewChromeExeVersion[] = "3.0.0.0";
    509 
    510   Version new_version(kNewVersion);
    511   Version old_version(kOldVersion);
    512   Version old_chrome_exe_version(kOldChromeExeVersion);
    513   Version chrome_exe_version(kChromeExeVersion);
    514   Version new_chrome_exe_version(kNewChromeExeVersion);
    515 
    516   ASSERT_TRUE(new_version.IsValid());
    517   ASSERT_TRUE(old_version.IsValid());
    518   ASSERT_TRUE(old_chrome_exe_version.IsValid());
    519   ASSERT_TRUE(chrome_exe_version.IsValid());
    520   ASSERT_TRUE(new_chrome_exe_version.IsValid());
    521 
    522   // Set up a bunch of version dir paths.
    523   base::FilePath version_dirs[] = {
    524     installer_state.target_path().Append(L"1.2.3.4"),
    525     installer_state.target_path().Append(L"1.2.3.5"),
    526     installer_state.target_path().Append(L"1.2.3.6"),
    527     installer_state.target_path().Append(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     file_util::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 
    605 
    606 // A fixture for testing InstallerState::DetermineCriticalVersion.  Individual
    607 // tests must invoke Initialize() with a critical version.
    608 class InstallerStateCriticalVersionTest : public ::testing::Test {
    609  protected:
    610   InstallerStateCriticalVersionTest() : cmd_line_(CommandLine::NO_PROGRAM) {}
    611 
    612   // Creates a set of versions for use by all test runs.
    613   static void SetUpTestCase() {
    614     low_version_    = new Version("15.0.874.106");
    615     opv_version_    = new Version("15.0.874.255");
    616     middle_version_ = new Version("16.0.912.32");
    617     pv_version_     = new Version("16.0.912.255");
    618     high_version_   = new Version("17.0.932.0");
    619   }
    620 
    621   // Cleans up versions used by all test runs.
    622   static void TearDownTestCase() {
    623     delete low_version_;
    624     delete opv_version_;
    625     delete middle_version_;
    626     delete pv_version_;
    627     delete high_version_;
    628   }
    629 
    630   // Initializes the InstallerState to use for a test run.  The returned
    631   // instance's critical update version is set to |version|.  |version| may be
    632   // NULL, in which case the critical update version is unset.
    633   MockInstallerState& Initialize(const Version* version) {
    634     cmd_line_ = version == NULL ?
    635         CommandLine::FromString(L"setup.exe") :
    636         CommandLine::FromString(
    637             L"setup.exe --critical-update-version=" +
    638             ASCIIToWide(version->GetString()));
    639     prefs_.reset(new MasterPreferences(cmd_line_));
    640     machine_state_.Initialize();
    641     installer_state_.Initialize(cmd_line_, *prefs_, machine_state_);
    642     return installer_state_;
    643   }
    644 
    645   static Version* low_version_;
    646   static Version* opv_version_;
    647   static Version* middle_version_;
    648   static Version* pv_version_;
    649   static Version* high_version_;
    650 
    651   CommandLine cmd_line_;
    652   scoped_ptr<MasterPreferences> prefs_;
    653   InstallationState machine_state_;
    654   MockInstallerState installer_state_;
    655 };
    656 
    657 Version* InstallerStateCriticalVersionTest::low_version_ = NULL;
    658 Version* InstallerStateCriticalVersionTest::opv_version_ = NULL;
    659 Version* InstallerStateCriticalVersionTest::middle_version_ = NULL;
    660 Version* InstallerStateCriticalVersionTest::pv_version_ = NULL;
    661 Version* InstallerStateCriticalVersionTest::high_version_ = NULL;
    662 
    663 // Test the case where the critical version is less than the currently-running
    664 // Chrome.  The critical version is ignored since it doesn't apply.
    665 TEST_F(InstallerStateCriticalVersionTest, CriticalBeforeOpv) {
    666   MockInstallerState& installer_state(Initialize(low_version_));
    667 
    668   EXPECT_TRUE(installer_state.critical_update_version().Equals(*low_version_));
    669   // Unable to determine the installed version, so assume critical update.
    670   EXPECT_TRUE(
    671       installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
    672   // Installed version is past the critical update.
    673   EXPECT_FALSE(
    674       installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
    675           .IsValid());
    676   // Installed version is past the critical update.
    677   EXPECT_FALSE(
    678       installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
    679           .IsValid());
    680 }
    681 
    682 // Test the case where the critical version is equal to the currently-running
    683 // Chrome.  The critical version is ignored since it doesn't apply.
    684 TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsOpv) {
    685   MockInstallerState& installer_state(Initialize(opv_version_));
    686 
    687   EXPECT_TRUE(installer_state.critical_update_version().Equals(*opv_version_));
    688   // Unable to determine the installed version, so assume critical update.
    689   EXPECT_TRUE(
    690       installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
    691   // Installed version equals the critical update.
    692   EXPECT_FALSE(
    693       installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
    694           .IsValid());
    695   // Installed version equals the critical update.
    696   EXPECT_FALSE(
    697       installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
    698           .IsValid());
    699 }
    700 
    701 // Test the case where the critical version is between the currently-running
    702 // Chrome and the to-be-installed Chrome.
    703 TEST_F(InstallerStateCriticalVersionTest, CriticalBetweenOpvAndPv) {
    704   MockInstallerState& installer_state(Initialize(middle_version_));
    705 
    706   EXPECT_TRUE(installer_state.critical_update_version().Equals(
    707       *middle_version_));
    708   // Unable to determine the installed version, so assume critical update.
    709   EXPECT_TRUE(
    710       installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
    711   // Installed version before the critical update.
    712   EXPECT_TRUE(
    713       installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
    714           .IsValid());
    715   // Installed version is past the critical update.
    716   EXPECT_FALSE(
    717       installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
    718           .IsValid());
    719 }
    720 
    721 // Test the case where the critical version is the same as the to-be-installed
    722 // Chrome.
    723 TEST_F(InstallerStateCriticalVersionTest, CriticalEqualsPv) {
    724   MockInstallerState& installer_state(Initialize(pv_version_));
    725 
    726   EXPECT_TRUE(installer_state.critical_update_version().Equals(
    727       *pv_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 before the critical update.
    732   EXPECT_TRUE(
    733       installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
    734           .IsValid());
    735   // Installed version equals 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 greater than the to-be-installed
    742 // Chrome.
    743 TEST_F(InstallerStateCriticalVersionTest, CriticalAfterPv) {
    744   MockInstallerState& installer_state(Initialize(high_version_));
    745 
    746   EXPECT_TRUE(installer_state.critical_update_version().Equals(
    747       *high_version_));
    748   // Critical update newer than the new version.
    749   EXPECT_FALSE(
    750       installer_state.DetermineCriticalVersion(NULL, *pv_version_).IsValid());
    751   EXPECT_FALSE(
    752       installer_state.DetermineCriticalVersion(opv_version_, *pv_version_)
    753           .IsValid());
    754   EXPECT_FALSE(
    755       installer_state.DetermineCriticalVersion(pv_version_, *pv_version_)
    756           .IsValid());
    757 }
    758