Home | History | Annotate | Download | only in setup
      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 "chrome/installer/setup/install_worker.h"
      6 
      7 #include "base/win/registry.h"
      8 #include "base/version.h"
      9 #include "chrome/common/chrome_constants.h"
     10 #include "chrome/installer/setup/setup_util.h"
     11 #include "chrome/installer/util/delete_reg_key_work_item.h"
     12 #include "chrome/installer/util/create_reg_key_work_item.h"
     13 #include "chrome/installer/util/helper.h"
     14 #include "chrome/installer/util/google_update_constants.h"
     15 #include "chrome/installer/util/installation_state.h"
     16 #include "chrome/installer/util/installer_state.h"
     17 #include "chrome/installer/util/set_reg_value_work_item.h"
     18 #include "chrome/installer/util/util_constants.h"
     19 #include "chrome/installer/util/work_item_list.h"
     20 
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 #include "testing/gmock/include/gmock/gmock.h"
     23 
     24 using base::win::RegKey;
     25 using installer::InstallationState;
     26 using installer::InstallerState;
     27 using installer::Product;
     28 using installer::ProductState;
     29 
     30 using ::testing::_;
     31 using ::testing::AtLeast;
     32 using ::testing::AtMost;
     33 using ::testing::Bool;
     34 using ::testing::Combine;
     35 using ::testing::HasSubstr;
     36 using ::testing::Eq;
     37 using ::testing::Return;
     38 using ::testing::StrCaseEq;
     39 using ::testing::StrEq;
     40 using ::testing::StrictMock;
     41 using ::testing::Values;
     42 
     43 // Mock classes to help with testing
     44 //------------------------------------------------------------------------------
     45 
     46 class MockWorkItemList : public WorkItemList {
     47  public:
     48   MockWorkItemList() {}
     49 
     50   MOCK_METHOD4(AddCopyRegKeyWorkItem, WorkItem* (HKEY,
     51                                                  const std::wstring&,
     52                                                  const std::wstring&,
     53                                                  CopyOverWriteOption));
     54   MOCK_METHOD5(AddCopyTreeWorkItem, WorkItem*(const std::wstring&,
     55                                               const std::wstring&,
     56                                               const std::wstring&,
     57                                               CopyOverWriteOption,
     58                                               const std::wstring&));
     59   MOCK_METHOD1(AddCreateDirWorkItem, WorkItem* (const base::FilePath&));
     60   MOCK_METHOD2(AddCreateRegKeyWorkItem, WorkItem* (HKEY, const std::wstring&));
     61   MOCK_METHOD2(AddDeleteRegKeyWorkItem, WorkItem* (HKEY, const std::wstring&));
     62   MOCK_METHOD3(AddDeleteRegValueWorkItem, WorkItem* (HKEY,
     63                                                      const std::wstring&,
     64                                                      const std::wstring&));
     65   MOCK_METHOD2(AddDeleteTreeWorkItem, WorkItem* (
     66       const base::FilePath&,
     67       const std::vector<base::FilePath>&));
     68   MOCK_METHOD1(AddDeleteTreeWorkItem, WorkItem* (const base::FilePath&));
     69   MOCK_METHOD3(AddMoveTreeWorkItem, WorkItem* (const std::wstring&,
     70                                                const std::wstring&,
     71                                                const std::wstring&));
     72   // Workaround for gmock problems with disambiguating between string pointers
     73   // and DWORD.
     74   virtual WorkItem* AddSetRegValueWorkItem(HKEY a1, const std::wstring& a2,
     75       const std::wstring& a3, const std::wstring& a4, bool a5) {
     76     return AddSetRegStringValueWorkItem(a1, a2, a3, a4, a5);
     77   }
     78 
     79   virtual WorkItem* AddSetRegValueWorkItem(HKEY a1, const std::wstring& a2,
     80                                            const std::wstring& a3,
     81                                            DWORD a4, bool a5) {
     82     return AddSetRegDwordValueWorkItem(a1, a2, a3, a4, a5);
     83   }
     84 
     85   MOCK_METHOD5(AddSetRegStringValueWorkItem, WorkItem*(HKEY,
     86                                                  const std::wstring&,
     87                                                  const std::wstring&,
     88                                                  const std::wstring&,
     89                                                  bool));
     90   MOCK_METHOD5(AddSetRegDwordValueWorkItem, WorkItem* (HKEY,
     91                                                   const std::wstring&,
     92                                                   const std::wstring&,
     93                                                   DWORD,
     94                                                   bool));
     95   MOCK_METHOD3(AddSelfRegWorkItem, WorkItem* (const std::wstring&,
     96                                               bool,
     97                                               bool));
     98 };
     99 
    100 class MockProductState : public ProductState {
    101  public:
    102   // Takes ownership of |version|.
    103   void set_version(Version* version) { version_.reset(version); }
    104   void set_multi_install(bool multi) { multi_install_ = multi; }
    105   void set_brand(const std::wstring& brand) { brand_ = brand; }
    106   void set_eula_accepted(DWORD eula_accepted) {
    107     has_eula_accepted_ = true;
    108     eula_accepted_ = eula_accepted;
    109   }
    110   void clear_eula_accepted() { has_eula_accepted_ = false; }
    111   void set_usagestats(DWORD usagestats) {
    112     has_usagestats_ = true;
    113     usagestats_ = usagestats;
    114   }
    115   void clear_usagestats() { has_usagestats_ = false; }
    116   void set_oem_install(const std::wstring& oem_install) {
    117     has_oem_install_ = true;
    118     oem_install_ = oem_install;
    119   }
    120   void clear_oem_install() { has_oem_install_ = false; }
    121   void SetUninstallProgram(const base::FilePath& setup_exe) {
    122     uninstall_command_ = CommandLine(setup_exe);
    123   }
    124   void AddUninstallSwitch(const std::string& option) {
    125     uninstall_command_.AppendSwitch(option);
    126   }
    127 };
    128 
    129 // Okay, so this isn't really a mock as such, but it does add setter methods
    130 // to make it easier to build custom InstallationStates.
    131 class MockInstallationState : public InstallationState {
    132  public:
    133   // Included for testing.
    134   void SetProductState(bool system_install,
    135                        BrowserDistribution::Type type,
    136                        const ProductState& product_state) {
    137     ProductState& target = (system_install ? system_products_ :
    138         user_products_)[IndexFromDistType(type)];
    139     target.CopyFrom(product_state);
    140   }
    141 };
    142 
    143 class MockInstallerState : public InstallerState {
    144  public:
    145   void set_level(Level level) {
    146     InstallerState::set_level(level);
    147   }
    148 
    149   void set_operation(Operation operation) { operation_ = operation; }
    150 
    151   void set_state_key(const std::wstring& state_key) {
    152     state_key_ = state_key;
    153   }
    154 
    155   void set_state_type(BrowserDistribution::Type state_type) {
    156     state_type_ = state_type;
    157   }
    158 
    159   void set_package_type(PackageType type) {
    160     InstallerState::set_package_type(type);
    161   }
    162 };
    163 
    164 // The test fixture
    165 //------------------------------------------------------------------------------
    166 
    167 class InstallWorkerTest : public testing::Test {
    168  public:
    169   virtual void SetUp() {
    170     current_version_.reset(new Version("1.0.0.0"));
    171     new_version_.reset(new Version("42.0.0.0"));
    172 
    173     // Don't bother ensuring that these paths exist. Since we're just
    174     // building the work item lists and not running them, they shouldn't
    175     // actually be touched.
    176     archive_path_ =
    177         base::FilePath(L"C:\\UnlikelyPath\\Temp\\chrome_123\\chrome.7z");
    178     // TODO(robertshield): Take this from the BrowserDistribution once that
    179     // no longer depends on MasterPreferences.
    180     installation_path_ =
    181         base::FilePath(L"C:\\Program Files\\Google\\Chrome\\");
    182     src_path_ = base::FilePath(
    183         L"C:\\UnlikelyPath\\Temp\\chrome_123\\source\\Chrome-bin");
    184     setup_path_ = base::FilePath(
    185         L"C:\\UnlikelyPath\\Temp\\CR_123.tmp\\setup.exe");
    186     temp_dir_ = base::FilePath(L"C:\\UnlikelyPath\\Temp\\chrome_123");
    187   }
    188 
    189   virtual void TearDown() {
    190   }
    191 
    192   void MaybeAddBinariesToInstallationState(
    193       bool system_level,
    194       MockInstallationState* installation_state) {
    195     if (installation_state->GetProductState(
    196             system_level, BrowserDistribution::CHROME_BINARIES) == NULL) {
    197       MockProductState product_state;
    198       product_state.set_version(new Version(*current_version_));
    199       product_state.set_brand(L"TEST");
    200       product_state.set_multi_install(true);
    201       BrowserDistribution* dist =
    202           BrowserDistribution::GetSpecificDistribution(
    203               BrowserDistribution::CHROME_BINARIES);
    204       base::FilePath install_path =
    205           installer::GetChromeInstallPath(system_level, dist);
    206       product_state.SetUninstallProgram(
    207           install_path.AppendASCII(current_version_->GetString())
    208           .Append(installer::kInstallerDir)
    209           .Append(installer::kSetupExe));
    210       product_state.AddUninstallSwitch(installer::switches::kUninstall);
    211       product_state.AddUninstallSwitch(installer::switches::kMultiInstall);
    212       if (system_level)
    213         product_state.AddUninstallSwitch(installer::switches::kSystemLevel);
    214       installation_state->SetProductState(system_level,
    215                                           BrowserDistribution::CHROME_BINARIES,
    216                                           product_state);
    217     }
    218   }
    219 
    220   void AddChromeToInstallationState(
    221       bool system_level,
    222       bool multi_install,
    223       bool with_chrome_frame_ready_mode,
    224       MockInstallationState* installation_state) {
    225     if (multi_install)
    226       MaybeAddBinariesToInstallationState(system_level, installation_state);
    227     MockProductState product_state;
    228     product_state.set_version(new Version(*current_version_));
    229     product_state.set_multi_install(multi_install);
    230     product_state.set_brand(L"TEST");
    231     product_state.set_eula_accepted(1);
    232     BrowserDistribution* dist =
    233         BrowserDistribution::GetSpecificDistribution(
    234             BrowserDistribution::CHROME_BROWSER);
    235     base::FilePath install_path =
    236         installer::GetChromeInstallPath(system_level, dist);
    237     product_state.SetUninstallProgram(
    238       install_path.AppendASCII(current_version_->GetString())
    239           .Append(installer::kInstallerDir)
    240           .Append(installer::kSetupExe));
    241     product_state.AddUninstallSwitch(installer::switches::kUninstall);
    242     if (system_level)
    243       product_state.AddUninstallSwitch(installer::switches::kSystemLevel);
    244     if (multi_install) {
    245       product_state.AddUninstallSwitch(installer::switches::kMultiInstall);
    246       product_state.AddUninstallSwitch(installer::switches::kChrome);
    247       if (with_chrome_frame_ready_mode) {
    248         product_state.AddUninstallSwitch(installer::switches::kChromeFrame);
    249         product_state.AddUninstallSwitch(
    250             installer::switches::kChromeFrameReadyMode);
    251       }
    252     }
    253 
    254     installation_state->SetProductState(system_level,
    255                                         BrowserDistribution::CHROME_BROWSER,
    256                                         product_state);
    257   }
    258 
    259   void AddChromeFrameToInstallationState(
    260       bool system_level,
    261       bool multi_install,
    262       bool ready_mode,
    263       MockInstallationState* installation_state) {
    264     if (multi_install)
    265       MaybeAddBinariesToInstallationState(system_level, installation_state);
    266     MockProductState product_state;
    267     product_state.set_version(new Version(*current_version_));
    268     product_state.set_multi_install(multi_install);
    269     BrowserDistribution* dist =
    270         BrowserDistribution::GetSpecificDistribution(
    271             multi_install ? BrowserDistribution::CHROME_BINARIES :
    272                 BrowserDistribution::CHROME_FRAME);
    273     base::FilePath install_path =
    274         installer::GetChromeInstallPath(system_level, dist);
    275     product_state.SetUninstallProgram(
    276       install_path.AppendASCII(current_version_->GetString())
    277           .Append(installer::kInstallerDir)
    278           .Append(installer::kSetupExe));
    279     product_state.AddUninstallSwitch(installer::switches::kUninstall);
    280     product_state.AddUninstallSwitch(installer::switches::kChromeFrame);
    281     if (system_level)
    282       product_state.AddUninstallSwitch(installer::switches::kSystemLevel);
    283     if (multi_install) {
    284       product_state.AddUninstallSwitch(installer::switches::kMultiInstall);
    285       if (ready_mode) {
    286         product_state.AddUninstallSwitch(
    287             installer::switches::kChromeFrameReadyMode);
    288       }
    289     }
    290 
    291     installation_state->SetProductState(system_level,
    292                                         BrowserDistribution::CHROME_FRAME,
    293                                         product_state);
    294   }
    295 
    296   MockInstallationState* BuildChromeInstallationState(bool system_level,
    297                                                       bool multi_install) {
    298     scoped_ptr<MockInstallationState> installation_state(
    299         new MockInstallationState());
    300     AddChromeToInstallationState(system_level, multi_install, false,
    301                                  installation_state.get());
    302     return installation_state.release();
    303   }
    304 
    305   static MockInstallerState* BuildBasicInstallerState(
    306       bool system_install,
    307       bool multi_install,
    308       const InstallationState& machine_state,
    309       InstallerState::Operation operation) {
    310     scoped_ptr<MockInstallerState> installer_state(new MockInstallerState());
    311 
    312     InstallerState::Level level = system_install ?
    313         InstallerState::SYSTEM_LEVEL : InstallerState::USER_LEVEL;
    314     installer_state->set_level(level);
    315     installer_state->set_operation(operation);
    316     // Hope this next one isn't checked for now.
    317     installer_state->set_state_key(L"PROBABLY_INVALID_REG_PATH");
    318     installer_state->set_state_type(BrowserDistribution::CHROME_BROWSER);
    319     installer_state->set_package_type(multi_install ?
    320                                           InstallerState::MULTI_PACKAGE :
    321                                           InstallerState::SINGLE_PACKAGE);
    322     return installer_state.release();
    323   }
    324 
    325   static void AddChromeBinariesToInstallerState(
    326       const InstallationState& machine_state,
    327       MockInstallerState* installer_state) {
    328     if (!installer_state->is_multi_install()) {
    329       NOTREACHED();
    330       return;
    331     }
    332     if (installer_state->FindProduct(BrowserDistribution::CHROME_BINARIES))
    333       return;
    334 
    335     // Fresh install or upgrade?
    336     const ProductState* chrome_binaries =
    337         machine_state.GetProductState(installer_state->system_install(),
    338                                       BrowserDistribution::CHROME_BINARIES);
    339     if (chrome_binaries != NULL) {
    340       installer_state->AddProductFromState(BrowserDistribution::CHROME_BINARIES,
    341                                            *chrome_binaries);
    342     } else {
    343       BrowserDistribution* dist =
    344           BrowserDistribution::GetSpecificDistribution(
    345               BrowserDistribution::CHROME_BINARIES);
    346       scoped_ptr<Product> product(new Product(dist));
    347       product->SetOption(installer::kOptionMultiInstall, true);
    348       installer_state->AddProduct(&product);
    349     }
    350   }
    351 
    352   static void AddChromeToInstallerState(
    353       const InstallationState& machine_state,
    354       MockInstallerState* installer_state) {
    355     // Fresh install or upgrade?
    356     const ProductState* chrome =
    357         machine_state.GetProductState(installer_state->system_install(),
    358                                       BrowserDistribution::CHROME_BROWSER);
    359     if (chrome != NULL &&
    360         chrome->is_multi_install() == installer_state->is_multi_install()) {
    361       installer_state->AddProductFromState(BrowserDistribution::CHROME_BROWSER,
    362                                            *chrome);
    363     } else {
    364       BrowserDistribution* dist =
    365           BrowserDistribution::GetSpecificDistribution(
    366               BrowserDistribution::CHROME_BROWSER);
    367       scoped_ptr<Product> product(new Product(dist));
    368       if (installer_state->is_multi_install())
    369         product->SetOption(installer::kOptionMultiInstall, true);
    370       installer_state->AddProduct(&product);
    371     }
    372   }
    373 
    374   static void AddChromeFrameToInstallerState(
    375       const InstallationState& machine_state,
    376       bool ready_mode,
    377       MockInstallerState* installer_state) {
    378     // Fresh install or upgrade?
    379     const ProductState* cf =
    380         machine_state.GetProductState(installer_state->system_install(),
    381                                       BrowserDistribution::CHROME_FRAME);
    382     if (cf != NULL) {
    383       installer_state->AddProductFromState(BrowserDistribution::CHROME_FRAME,
    384                                            *cf);
    385     } else {
    386       BrowserDistribution* dist =
    387           BrowserDistribution::GetSpecificDistribution(
    388               BrowserDistribution::CHROME_FRAME);
    389       scoped_ptr<Product> product(new Product(dist));
    390       if (installer_state->is_multi_install()) {
    391         product->SetOption(installer::kOptionMultiInstall, true);
    392         if (ready_mode)
    393           product->SetOption(installer::kOptionReadyMode, true);
    394       }
    395       installer_state->AddProduct(&product);
    396     }
    397   }
    398 
    399   static MockInstallerState* BuildChromeInstallerState(
    400       bool system_install,
    401       bool multi_install,
    402       const InstallationState& machine_state,
    403       InstallerState::Operation operation) {
    404     scoped_ptr<MockInstallerState> installer_state(
    405         BuildBasicInstallerState(system_install, multi_install, machine_state,
    406                                  operation));
    407     if (multi_install) {
    408       // We don't want to include Chrome Binaries for uninstall if the machine
    409       // has other products. For simplicity, we check Chrome Frame only.
    410       bool machine_has_other_products =
    411           machine_state.GetProductState(system_install,
    412               BrowserDistribution::CHROME_FRAME) != NULL;
    413       if (operation != InstallerState::UNINSTALL || !machine_has_other_products)
    414         AddChromeBinariesToInstallerState(machine_state, installer_state.get());
    415     }
    416     AddChromeToInstallerState(machine_state, installer_state.get());
    417     return installer_state.release();
    418   }
    419 
    420   static MockInstallerState* BuildChromeFrameInstallerState(
    421       bool system_install,
    422       bool multi_install,
    423       bool ready_mode,
    424       const InstallationState& machine_state,
    425       InstallerState::Operation operation) {
    426     // This method only works for installation/upgrade.
    427     DCHECK(operation != InstallerState::UNINSTALL);
    428     scoped_ptr<MockInstallerState> installer_state(
    429         BuildBasicInstallerState(system_install, multi_install, machine_state,
    430                                  operation));
    431     if (multi_install)
    432       AddChromeBinariesToInstallerState(machine_state, installer_state.get());
    433     AddChromeFrameToInstallerState(machine_state, ready_mode,
    434                                    installer_state.get());
    435     return installer_state.release();
    436   }
    437 
    438  protected:
    439   scoped_ptr<Version> current_version_;
    440   scoped_ptr<Version> new_version_;
    441   base::FilePath archive_path_;
    442   base::FilePath installation_path_;
    443   base::FilePath setup_path_;
    444   base::FilePath src_path_;
    445   base::FilePath temp_dir_;
    446 };
    447 
    448 // Tests
    449 //------------------------------------------------------------------------------
    450 
    451 TEST_F(InstallWorkerTest, TestInstallChromeSingleSystem) {
    452   const bool system_level = true;
    453   const bool multi_install = false;
    454   MockWorkItemList work_item_list;
    455 
    456   scoped_ptr<InstallationState> installation_state(
    457       BuildChromeInstallationState(system_level, multi_install));
    458 
    459   scoped_ptr<InstallerState> installer_state(
    460       BuildChromeInstallerState(system_level, multi_install,
    461                                 *installation_state,
    462                                 InstallerState::SINGLE_INSTALL_OR_UPDATE));
    463 
    464   // Set up some expectations.
    465   // TODO(robertshield): Set up some real expectations.
    466   EXPECT_CALL(work_item_list, AddCopyTreeWorkItem(_, _, _, _, _))
    467       .Times(AtLeast(1));
    468 
    469   AddInstallWorkItems(*installation_state.get(),
    470                       *installer_state.get(),
    471                       setup_path_,
    472                       archive_path_,
    473                       src_path_,
    474                       temp_dir_,
    475                       current_version_.get(),
    476                       *new_version_.get(),
    477                       &work_item_list);
    478 }
    479 
    480 namespace {
    481 
    482 const wchar_t elevation_key[] =
    483     L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"
    484     L"{E0A900DF-9611-4446-86BD-4B1D47E7DB2A}";
    485 const wchar_t old_elevation_key[] =
    486     L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"
    487     L"{6C288DD7-76FB-4721-B628-56FAC252E199}";
    488 
    489 }  // namespace
    490 
    491 // A test class for worker functions that manipulate the old IE low rights
    492 // policies.
    493 // Parameters:
    494 // bool : system_level_
    495 // bool : multi_install_
    496 class OldIELowRightsTests : public InstallWorkerTest,
    497   public ::testing::WithParamInterface<std::tr1::tuple<bool, bool> > {
    498  protected:
    499   virtual void SetUp() OVERRIDE {
    500     InstallWorkerTest::SetUp();
    501 
    502     const ParamType& param = GetParam();
    503     system_level_ = std::tr1::get<0>(param);
    504     multi_install_ = std::tr1::get<1>(param);
    505     root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
    506 
    507     installation_state_.reset(new MockInstallationState());
    508     AddChromeFrameToInstallationState(system_level_, multi_install_, false,
    509                                       installation_state_.get());
    510     installer_state_.reset(BuildBasicInstallerState(
    511         system_level_, multi_install_, *installation_state_,
    512         multi_install_ ? InstallerState::MULTI_UPDATE :
    513             InstallerState::SINGLE_INSTALL_OR_UPDATE));
    514     if (multi_install_)
    515       AddChromeBinariesToInstallerState(*installation_state_,
    516                                         installer_state_.get());
    517     AddChromeFrameToInstallerState(*installation_state_, false,
    518                                    installer_state_.get());
    519   }
    520 
    521   scoped_ptr<MockInstallationState> installation_state_;
    522   scoped_ptr<MockInstallerState> installer_state_;
    523   bool system_level_;
    524   bool multi_install_;
    525   HKEY root_key_;
    526 };
    527 
    528 TEST_P(OldIELowRightsTests, AddDeleteOldIELowRightsPolicyWorkItems) {
    529   StrictMock<MockWorkItemList> work_item_list;
    530 
    531   EXPECT_CALL(work_item_list,
    532               AddDeleteRegKeyWorkItem(root_key_, StrEq(old_elevation_key)))
    533       .Times(1);
    534 
    535   AddDeleteOldIELowRightsPolicyWorkItems(*installer_state_.get(),
    536                                          &work_item_list);
    537 }
    538 
    539 TEST_P(OldIELowRightsTests, AddCopyIELowRightsPolicyWorkItems) {
    540   StrictMock<MockWorkItemList> work_item_list;
    541 
    542   // The old elevation policy key should only be copied when there's no old
    543   // value.
    544   EXPECT_CALL(work_item_list,
    545               AddCopyRegKeyWorkItem(root_key_, StrEq(elevation_key),
    546                                     StrEq(old_elevation_key),
    547                                     Eq(WorkItem::IF_NOT_PRESENT))).Times(1);
    548 
    549   AddCopyIELowRightsPolicyWorkItems(*installer_state_.get(), &work_item_list);
    550 }
    551 
    552 INSTANTIATE_TEST_CASE_P(Variations, OldIELowRightsTests,
    553                         Combine(Bool(), Bool()));
    554 
    555 TEST_F(InstallWorkerTest, GoogleUpdateWorkItemsTest) {
    556   const bool system_level = true;
    557   const bool multi_install = true;
    558   MockWorkItemList work_item_list;
    559 
    560   scoped_ptr<MockInstallationState> installation_state(
    561       BuildChromeInstallationState(system_level, false));
    562 
    563   MockProductState cf_state;
    564   cf_state.set_version(new Version(*current_version_));
    565   cf_state.set_multi_install(false);
    566 
    567   installation_state->SetProductState(system_level,
    568       BrowserDistribution::CHROME_FRAME, cf_state);
    569 
    570   scoped_ptr<MockInstallerState> installer_state(
    571       BuildChromeInstallerState(system_level, multi_install,
    572                                 *installation_state,
    573                                 InstallerState::MULTI_INSTALL));
    574 
    575   // Expect the multi Client State key to be created.
    576   BrowserDistribution* multi_dist =
    577       BrowserDistribution::GetSpecificDistribution(
    578           BrowserDistribution::CHROME_BINARIES);
    579   std::wstring multi_app_guid(multi_dist->GetAppGuid());
    580   std::wstring multi_client_state_suffix(L"ClientState\\" + multi_app_guid);
    581   EXPECT_CALL(work_item_list,
    582               AddCreateRegKeyWorkItem(_, HasSubstr(multi_client_state_suffix)))
    583       .Times(testing::AnyNumber());
    584 
    585   // Expect ClientStateMedium to be created for system-level installs.
    586   EXPECT_CALL(work_item_list,
    587               AddCreateRegKeyWorkItem(_, HasSubstr(L"ClientStateMedium\\" +
    588                                                    multi_app_guid)))
    589       .Times(system_level ? 1 : 0);
    590 
    591   // Expect to see a set value for the "TEST" brand code in the multi Client
    592   // State key.
    593   EXPECT_CALL(work_item_list,
    594               AddSetRegStringValueWorkItem(_,
    595                                            HasSubstr(multi_client_state_suffix),
    596                                            StrEq(google_update::kRegBrandField),
    597                                            StrEq(L"TEST"),
    598                                            _)).Times(1);
    599 
    600   // There may also be some calls to set 'ap' values.
    601   EXPECT_CALL(work_item_list,
    602               AddSetRegStringValueWorkItem(_, _,
    603                                            StrEq(google_update::kRegApField),
    604                                            _, _)).Times(testing::AnyNumber());
    605 
    606   // Expect "oeminstall" to be cleared.
    607   EXPECT_CALL(work_item_list,
    608               AddDeleteRegValueWorkItem(
    609                   _,
    610                   HasSubstr(multi_client_state_suffix),
    611                   StrEq(google_update::kRegOemInstallField))).Times(1);
    612 
    613   // Expect "eulaaccepted" to set.
    614   EXPECT_CALL(work_item_list,
    615               AddSetRegDwordValueWorkItem(
    616                   _,
    617                   HasSubstr(multi_client_state_suffix),
    618                   StrEq(google_update::kRegEULAAceptedField),
    619                   Eq(static_cast<DWORD>(1)),
    620                   _)).Times(1);
    621 
    622   AddGoogleUpdateWorkItems(*installation_state.get(),
    623                            *installer_state.get(),
    624                            &work_item_list);
    625 }
    626 
    627 // Test that usagestats values are migrated properly.
    628 TEST_F(InstallWorkerTest, AddUsageStatsWorkItems) {
    629   const bool system_level = true;
    630   const bool multi_install = true;
    631   MockWorkItemList work_item_list;
    632 
    633   scoped_ptr<MockInstallationState> installation_state(
    634       BuildChromeInstallationState(system_level, multi_install));
    635 
    636   MockProductState chrome_state;
    637   chrome_state.set_version(new Version(*current_version_));
    638   chrome_state.set_multi_install(false);
    639   chrome_state.set_usagestats(1);
    640 
    641   installation_state->SetProductState(system_level,
    642       BrowserDistribution::CHROME_BROWSER, chrome_state);
    643 
    644   scoped_ptr<MockInstallerState> installer_state(
    645       BuildChromeInstallerState(system_level, multi_install,
    646                                 *installation_state,
    647                                 InstallerState::MULTI_INSTALL));
    648 
    649   // Expect the multi Client State key to be created.
    650   BrowserDistribution* multi_dist =
    651       BrowserDistribution::GetSpecificDistribution(
    652           BrowserDistribution::CHROME_BINARIES);
    653   std::wstring multi_app_guid(multi_dist->GetAppGuid());
    654   EXPECT_CALL(work_item_list,
    655               AddCreateRegKeyWorkItem(_, HasSubstr(multi_app_guid))).Times(1);
    656 
    657   // Expect to see a set value for the usagestats in the multi Client State key.
    658   EXPECT_CALL(work_item_list,
    659               AddSetRegDwordValueWorkItem(
    660                   _,
    661                   HasSubstr(multi_app_guid),
    662                   StrEq(google_update::kRegUsageStatsField),
    663                   Eq(static_cast<DWORD>(1)),
    664                   Eq(true))).Times(1);
    665 
    666   // Expect to see some values cleaned up from Chrome's keys.
    667   BrowserDistribution* chrome_dist =
    668       BrowserDistribution::GetSpecificDistribution(
    669           BrowserDistribution::CHROME_BROWSER);
    670   if (system_level) {
    671     EXPECT_CALL(work_item_list,
    672                 AddDeleteRegValueWorkItem(
    673                     _,
    674                     StrEq(chrome_dist->GetStateMediumKey()),
    675                     StrEq(google_update::kRegUsageStatsField))).Times(1);
    676     EXPECT_CALL(work_item_list,
    677                 AddDeleteRegValueWorkItem(
    678                     Eq(HKEY_CURRENT_USER),
    679                     StrEq(chrome_dist->GetStateKey()),
    680                     StrEq(google_update::kRegUsageStatsField))).Times(1);
    681   }
    682   EXPECT_CALL(work_item_list,
    683               AddDeleteRegValueWorkItem(
    684                   Eq(installer_state->root_key()),
    685                   StrEq(chrome_dist->GetStateKey()),
    686                   StrEq(google_update::kRegUsageStatsField))).Times(1);
    687 
    688   AddUsageStatsWorkItems(*installation_state.get(),
    689                          *installer_state.get(),
    690                          &work_item_list);
    691 }
    692 
    693 // The Quick Enable tests only make sense for the Google Chrome build as it
    694 // interacts with registry values that are specific to Google Update.
    695 #if defined(GOOGLE_CHROME_BUILD)
    696 
    697 // Test scenarios under which the quick-enable-cf command should not exist after
    698 // the run.  We're permissive in that we allow the DeleteRegKeyWorkItem even if
    699 // it isn't strictly needed.
    700 class QuickEnableAbsentTest : public InstallWorkerTest {
    701  public:
    702   virtual void SetUp() {
    703     InstallWorkerTest::SetUp();
    704     root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
    705     delete_reg_key_item_.reset(
    706         WorkItem::CreateDeleteRegKeyWorkItem(root_key_, kRegKeyPath));
    707     machine_state_.reset(new MockInstallationState());
    708     EXPECT_CALL(work_item_list_,
    709                 AddDeleteRegKeyWorkItem(Eq(root_key_), StrCaseEq(kRegKeyPath)))
    710         .Times(AtMost(1))
    711         .WillRepeatedly(Return(delete_reg_key_item_.get()));
    712   }
    713   virtual void TearDown() {
    714     machine_state_.reset();
    715     delete_reg_key_item_.reset();
    716     root_key_ = NULL;
    717     InstallWorkerTest::TearDown();
    718   }
    719  protected:
    720   static const bool system_level_ = false;
    721   static const wchar_t kRegKeyPath[];
    722   HKEY root_key_;
    723   scoped_ptr<DeleteRegKeyWorkItem> delete_reg_key_item_;
    724   scoped_ptr<MockInstallationState> machine_state_;
    725   StrictMock<MockWorkItemList> work_item_list_;
    726 };
    727 
    728 const wchar_t QuickEnableAbsentTest::kRegKeyPath[] =
    729     L"Software\\Google\\Update\\Clients\\"
    730     L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}\\Commands\\quick-enable-cf";
    731 
    732 TEST_F(QuickEnableAbsentTest, CleanInstallSingleChrome) {
    733   // Install single Chrome on a clean system.
    734   scoped_ptr<MockInstallerState> installer_state(
    735       BuildChromeInstallerState(system_level_, false, *machine_state_,
    736                                 InstallerState::SINGLE_INSTALL_OR_UPDATE));
    737   AddQuickEnableChromeFrameWorkItems(*installer_state,
    738                                      *machine_state_,
    739                                      setup_path_,
    740                                      *new_version_.get(),
    741                                      &work_item_list_);
    742 }
    743 
    744 TEST_F(QuickEnableAbsentTest, CleanInstallSingleChromeFrame) {
    745   // Install single Chrome Frame on a clean system.
    746   scoped_ptr<MockInstallerState> installer_state(
    747       BuildChromeFrameInstallerState(system_level_, false, false,
    748                                      *machine_state_,
    749                                      InstallerState::SINGLE_INSTALL_OR_UPDATE));
    750   AddQuickEnableChromeFrameWorkItems(*installer_state,
    751                                      *machine_state_,
    752                                      setup_path_,
    753                                      *new_version_.get(),
    754                                      &work_item_list_);
    755 }
    756 
    757 TEST_F(QuickEnableAbsentTest, CleanInstallMultiChromeFrame) {
    758   // Install multi Chrome Frame on a clean system.
    759   scoped_ptr<MockInstallerState> installer_state(
    760       BuildChromeFrameInstallerState(system_level_, true, false,
    761                                      *machine_state_,
    762                                      InstallerState::MULTI_INSTALL));
    763   AddQuickEnableChromeFrameWorkItems(*installer_state,
    764                                      *machine_state_,
    765                                      setup_path_,
    766                                      *new_version_.get(),
    767                                      &work_item_list_);
    768 }
    769 
    770 TEST_F(QuickEnableAbsentTest, CleanInstallMultiChromeChromeFrame) {
    771   // Install multi Chrome and Chrome Frame on a clean system.
    772   scoped_ptr<MockInstallerState> installer_state(
    773       BuildBasicInstallerState(system_level_, true, *machine_state_,
    774                                InstallerState::MULTI_INSTALL));
    775   AddChromeBinariesToInstallerState(*machine_state_, installer_state.get());
    776   AddChromeToInstallerState(*machine_state_, installer_state.get());
    777   AddChromeFrameToInstallerState(*machine_state_, false,
    778                                  installer_state.get());
    779   AddQuickEnableChromeFrameWorkItems(*installer_state,
    780                                      *machine_state_,
    781                                      setup_path_,
    782                                      *new_version_.get(),
    783                                      &work_item_list_);
    784 }
    785 
    786 TEST_F(QuickEnableAbsentTest, UninstallMultiChromeLeaveMultiChromeFrame) {
    787   // Uninstall multi Chrome on a machine with multi Chrome Frame.
    788   AddChromeToInstallationState(system_level_, true, false,
    789                                machine_state_.get());
    790   AddChromeFrameToInstallationState(system_level_, true, false,
    791                                     machine_state_.get());
    792   scoped_ptr<MockInstallerState> installer_state(
    793       BuildBasicInstallerState(system_level_, true, *machine_state_,
    794                                InstallerState::UNINSTALL));
    795   AddChromeToInstallerState(*machine_state_, installer_state.get());
    796   AddQuickEnableChromeFrameWorkItems(*installer_state,
    797                                      *machine_state_,
    798                                      setup_path_,
    799                                      *new_version_.get(),
    800                                      &work_item_list_);
    801 }
    802 
    803 TEST_F(QuickEnableAbsentTest, UninstallMultiChromeLeaveSingleChromeFrame) {
    804   // Uninstall multi Chrome on a machine with single Chrome Frame.
    805   AddChromeToInstallationState(system_level_, true, false,
    806                                machine_state_.get());
    807   AddChromeFrameToInstallationState(system_level_, false, false,
    808                                     machine_state_.get());
    809   scoped_ptr<MockInstallerState> installer_state(
    810       BuildBasicInstallerState(system_level_, true, *machine_state_,
    811                                InstallerState::UNINSTALL));
    812   AddChromeToInstallerState(*machine_state_, installer_state.get());
    813   AddChromeBinariesToInstallerState(*machine_state_, installer_state.get());
    814   AddQuickEnableChromeFrameWorkItems(*installer_state,
    815                                      *machine_state_,
    816                                      setup_path_,
    817                                      *new_version_.get(),
    818                                      &work_item_list_);
    819 }
    820 
    821 TEST_F(QuickEnableAbsentTest, AcceptReadyMode) {
    822   // Accept ready-mode.
    823   AddChromeToInstallationState(system_level_, true, true,
    824                                machine_state_.get());
    825   AddChromeFrameToInstallationState(system_level_, true, true,
    826                                     machine_state_.get());
    827   scoped_ptr<MockInstallerState> installer_state(
    828       BuildBasicInstallerState(system_level_, true, *machine_state_,
    829                                InstallerState::UNINSTALL));
    830   AddChromeToInstallerState(*machine_state_, installer_state.get());
    831   AddChromeFrameToInstallerState(*machine_state_, false, installer_state.get());
    832   AddChromeBinariesToInstallerState(*machine_state_, installer_state.get());
    833   AddQuickEnableChromeFrameWorkItems(*installer_state,
    834                                      *machine_state_,
    835                                      setup_path_,
    836                                      *new_version_.get(),
    837                                      &work_item_list_);
    838 }
    839 
    840 // Test scenarios under which the quick-enable-cf command should exist after the
    841 // run.
    842 class QuickEnablePresentTest : public InstallWorkerTest {
    843  public:
    844   virtual void SetUp() {
    845     InstallWorkerTest::SetUp();
    846     root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
    847     create_reg_key_work_item_.reset(
    848         WorkItem::CreateCreateRegKeyWorkItem(root_key_, kRegKeyPath));
    849     set_reg_value_work_item_.reset(
    850         WorkItem::CreateSetRegValueWorkItem(root_key_, kRegKeyPath, L"", L"",
    851                                             false));
    852     machine_state_.reset(new MockInstallationState());
    853     EXPECT_CALL(work_item_list_,
    854                 AddCreateRegKeyWorkItem(Eq(root_key_), StrCaseEq(kRegKeyPath)))
    855         .Times(1)
    856         .WillOnce(Return(create_reg_key_work_item_.get()));
    857     EXPECT_CALL(work_item_list_,
    858                 AddSetRegStringValueWorkItem(Eq(root_key_),
    859                                              StrCaseEq(kRegKeyPath),
    860                                              StrEq(L"CommandLine"), _,
    861                                              Eq(true)))
    862         .Times(1)
    863         .WillOnce(Return(set_reg_value_work_item_.get()));
    864     EXPECT_CALL(work_item_list_,
    865                 AddSetRegDwordValueWorkItem(Eq(root_key_),
    866                                             StrCaseEq(kRegKeyPath), _,
    867                                             Eq(static_cast<DWORD>(1)),
    868                                             Eq(true)))
    869         .Times(2)
    870         .WillRepeatedly(Return(set_reg_value_work_item_.get()));
    871   }
    872   virtual void TearDown() {
    873     machine_state_.reset();
    874     set_reg_value_work_item_.reset();
    875     create_reg_key_work_item_.reset();
    876     root_key_ = NULL;
    877     InstallWorkerTest::TearDown();
    878   }
    879  protected:
    880   static const bool system_level_ = false;
    881   static const wchar_t kRegKeyPath[];
    882   HKEY root_key_;
    883   scoped_ptr<CreateRegKeyWorkItem> create_reg_key_work_item_;
    884   scoped_ptr<SetRegValueWorkItem> set_reg_value_work_item_;
    885   scoped_ptr<MockInstallationState> machine_state_;
    886   StrictMock<MockWorkItemList> work_item_list_;
    887 };
    888 
    889 const wchar_t QuickEnablePresentTest::kRegKeyPath[] =
    890     L"Software\\Google\\Update\\Clients\\"
    891     L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}\\Commands\\quick-enable-cf";
    892 
    893 TEST_F(QuickEnablePresentTest, CleanInstallMultiChrome) {
    894   // Install multi Chrome on a clean system.
    895   scoped_ptr<MockInstallerState> installer_state(
    896       BuildChromeInstallerState(system_level_, true, *machine_state_,
    897                                 InstallerState::MULTI_INSTALL));
    898   AddQuickEnableChromeFrameWorkItems(*installer_state,
    899                                      *machine_state_,
    900                                      setup_path_,
    901                                      *new_version_.get(),
    902                                      &work_item_list_);
    903 }
    904 
    905 TEST_F(QuickEnablePresentTest, CleanInstallMultiChromeReadyMode) {
    906   // Install multi Chrome with Chrome Frame ready-mode on a clean system.
    907   scoped_ptr<MockInstallerState> installer_state(
    908       BuildBasicInstallerState(system_level_, true, *machine_state_,
    909                                InstallerState::MULTI_INSTALL));
    910   AddChromeBinariesToInstallerState(*machine_state_, installer_state.get());
    911   AddChromeToInstallerState(*machine_state_, installer_state.get());
    912   AddChromeFrameToInstallerState(*machine_state_, true,
    913                                  installer_state.get());
    914   AddQuickEnableChromeFrameWorkItems(*installer_state,
    915                                      *machine_state_,
    916                                      setup_path_,
    917                                      *new_version_.get(),
    918                                      &work_item_list_);
    919 }
    920 
    921 TEST_F(QuickEnablePresentTest, UninstallSingleChromeFrame) {
    922   // Uninstall single Chrome Frame on a machine with multi Chrome.
    923   AddChromeToInstallationState(system_level_, true, false,
    924                                machine_state_.get());
    925   AddChromeFrameToInstallationState(system_level_, false, false,
    926                                     machine_state_.get());
    927   scoped_ptr<MockInstallerState> installer_state(
    928       BuildBasicInstallerState(system_level_, false, *machine_state_,
    929                                InstallerState::UNINSTALL));
    930   AddChromeFrameToInstallerState(*machine_state_, false, installer_state.get());
    931   AddQuickEnableChromeFrameWorkItems(*installer_state,
    932                                      *machine_state_,
    933                                      setup_path_,
    934                                      *new_version_.get(),
    935                                      &work_item_list_);
    936 }
    937 
    938 TEST_F(QuickEnablePresentTest, UninstallMultiChromeFrame) {
    939   // Uninstall multi Chrome Frame on a machine with multi Chrome.
    940   AddChromeToInstallationState(system_level_, true, false,
    941                                machine_state_.get());
    942   AddChromeFrameToInstallationState(system_level_, true, false,
    943                                     machine_state_.get());
    944   scoped_ptr<MockInstallerState> installer_state(
    945       BuildBasicInstallerState(system_level_, true, *machine_state_,
    946                                InstallerState::UNINSTALL));
    947   AddChromeFrameToInstallerState(*machine_state_, false, installer_state.get());
    948   AddQuickEnableChromeFrameWorkItems(*installer_state,
    949                                      *machine_state_,
    950                                      setup_path_,
    951                                      *new_version_.get(),
    952                                      &work_item_list_);
    953 }
    954 
    955 TEST_F(InstallWorkerTest, WillProductBePresentAfterSetup) {
    956   BrowserDistribution::Type prod_type_list[] = {
    957     BrowserDistribution::CHROME_BROWSER,
    958     BrowserDistribution::CHROME_FRAME,
    959     // Excluding BrowserDistribution::CHROME_BINARIES, since it is installed
    960     // along with other products.
    961   };
    962   enum {  // Index into prod_type_list[].
    963     TYPE_BROWSER = 0,
    964     TYPE_CF,
    965     NUM_TYPE  // This must appear last.
    966   };
    967   DCHECK(arraysize(prod_type_list) == NUM_TYPE);
    968   InstallerState::Operation op_list[] = {
    969     InstallerState::UNINSTALL,
    970     InstallerState::SINGLE_INSTALL_OR_UPDATE
    971   };
    972 
    973   const bool system_level = false;
    974   const bool multi_install = true;
    975 
    976   // Loop over machine states: {No product, Chrome, CF, Chrome + CF}.
    977   for (int i_mach = 0; i_mach < (1 << NUM_TYPE); ++i_mach) {
    978     // i_mach is the machine state before operation, as bit mask.
    979     scoped_ptr<MockInstallationState> machine_state(
    980         new MockInstallationState());
    981     if ((i_mach & (1 << TYPE_BROWSER)) != 0) {  // Add Chrome.
    982       AddChromeToInstallationState(system_level, multi_install, false,
    983                                    machine_state.get());
    984     }
    985     if ((i_mach & (1 << TYPE_CF)) != 0) {  // Add Chrome Frame.
    986       AddChromeFrameToInstallationState(system_level, multi_install, false,
    987                                         machine_state.get());
    988     }
    989 
    990     // Loop over operations: {uninstall, install/update}.
    991     for (int i_op = 0; i_op < arraysize(op_list); ++i_op) {
    992 
    993       // Loop over product types to operate on: {TYPE_BROWSER, TYPE_CF}.
    994       for (int i_type_op = 0; i_type_op < NUM_TYPE; ++i_type_op) {
    995         scoped_ptr<InstallerState> installer_state;
    996         if (i_type_op == TYPE_BROWSER) {
    997           installer_state.reset(BuildChromeInstallerState(
    998               system_level, multi_install, *machine_state, op_list[i_op]));
    999         } else if (i_type_op == TYPE_CF) {
   1000           // Skip the CF uninstall case due to limitations in
   1001           // BuildChromeFrameInstallerState().
   1002           if (op_list[i_op] == InstallerState::UNINSTALL)
   1003             continue;
   1004 
   1005           installer_state.reset(BuildChromeFrameInstallerState(
   1006               system_level, multi_install, false, *machine_state,
   1007               op_list[i_op]));
   1008         } else {
   1009           NOTREACHED();
   1010         }
   1011 
   1012         // Calculate the machine state after operation, as bit mask.
   1013         // If uninstall, remove product with bitwise AND; else add with OR.
   1014         int mach_after = (op_list[i_op] == InstallerState::UNINSTALL) ?
   1015             i_mach & ~(1 << i_type_op) : i_mach | (1 << i_type_op);
   1016 
   1017         // Verify predicted presence of Chrome Binaries.
   1018         bool bin_res = installer::WillProductBePresentAfterSetup(
   1019             *installer_state,
   1020             *machine_state,
   1021             BrowserDistribution::CHROME_BINARIES);
   1022         // Binaries are expected to be present iff any product is installed.
   1023         bool bin_expect = mach_after != 0;
   1024         EXPECT_EQ(bin_expect, bin_res);
   1025 
   1026         // Loop over product types to check: {TYPE_BROWSER, TYPE_CF}.
   1027         for (int i_type_check = 0; i_type_check < NUM_TYPE; ++i_type_check) {
   1028           // Verify predicted presence of product.
   1029           bool prod_res = installer::WillProductBePresentAfterSetup(
   1030               *installer_state,
   1031               *machine_state,
   1032               prod_type_list[i_type_check]);
   1033           bool prod_expect = (mach_after & (1 << i_type_check)) != 0;
   1034           EXPECT_EQ(prod_expect, prod_res);
   1035         }
   1036       }
   1037     }
   1038   }
   1039 }
   1040 
   1041 #endif  // defined(GOOGLE_CHROME_BUILD)
   1042