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