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