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       MockInstallationState* installation_state) {
    224     if (multi_install)
    225       MaybeAddBinariesToInstallationState(system_level, installation_state);
    226     MockProductState product_state;
    227     product_state.set_version(new Version(*current_version_));
    228     product_state.set_multi_install(multi_install);
    229     product_state.set_brand(L"TEST");
    230     product_state.set_eula_accepted(1);
    231     BrowserDistribution* dist =
    232         BrowserDistribution::GetSpecificDistribution(
    233             BrowserDistribution::CHROME_BROWSER);
    234     base::FilePath install_path =
    235         installer::GetChromeInstallPath(system_level, dist);
    236     product_state.SetUninstallProgram(
    237       install_path.AppendASCII(current_version_->GetString())
    238           .Append(installer::kInstallerDir)
    239           .Append(installer::kSetupExe));
    240     product_state.AddUninstallSwitch(installer::switches::kUninstall);
    241     if (system_level)
    242       product_state.AddUninstallSwitch(installer::switches::kSystemLevel);
    243     if (multi_install) {
    244       product_state.AddUninstallSwitch(installer::switches::kMultiInstall);
    245       product_state.AddUninstallSwitch(installer::switches::kChrome);
    246     }
    247 
    248     installation_state->SetProductState(system_level,
    249                                         BrowserDistribution::CHROME_BROWSER,
    250                                         product_state);
    251   }
    252 
    253   void AddChromeFrameToInstallationState(
    254       bool system_level,
    255       bool multi_install,
    256       MockInstallationState* installation_state) {
    257     if (multi_install)
    258       MaybeAddBinariesToInstallationState(system_level, installation_state);
    259     MockProductState product_state;
    260     product_state.set_version(new Version(*current_version_));
    261     product_state.set_multi_install(multi_install);
    262     BrowserDistribution* dist =
    263         BrowserDistribution::GetSpecificDistribution(
    264             multi_install ? BrowserDistribution::CHROME_BINARIES :
    265                 BrowserDistribution::CHROME_FRAME);
    266     base::FilePath install_path =
    267         installer::GetChromeInstallPath(system_level, dist);
    268     product_state.SetUninstallProgram(
    269       install_path.AppendASCII(current_version_->GetString())
    270           .Append(installer::kInstallerDir)
    271           .Append(installer::kSetupExe));
    272     product_state.AddUninstallSwitch(installer::switches::kUninstall);
    273     product_state.AddUninstallSwitch(installer::switches::kChromeFrame);
    274     if (system_level)
    275       product_state.AddUninstallSwitch(installer::switches::kSystemLevel);
    276     if (multi_install)
    277       product_state.AddUninstallSwitch(installer::switches::kMultiInstall);
    278 
    279     installation_state->SetProductState(system_level,
    280                                         BrowserDistribution::CHROME_FRAME,
    281                                         product_state);
    282   }
    283 
    284   MockInstallationState* BuildChromeInstallationState(bool system_level,
    285                                                       bool multi_install) {
    286     scoped_ptr<MockInstallationState> installation_state(
    287         new MockInstallationState());
    288     AddChromeToInstallationState(system_level, multi_install,
    289                                  installation_state.get());
    290     return installation_state.release();
    291   }
    292 
    293   static MockInstallerState* BuildBasicInstallerState(
    294       bool system_install,
    295       bool multi_install,
    296       const InstallationState& machine_state,
    297       InstallerState::Operation operation) {
    298     scoped_ptr<MockInstallerState> installer_state(new MockInstallerState());
    299 
    300     InstallerState::Level level = system_install ?
    301         InstallerState::SYSTEM_LEVEL : InstallerState::USER_LEVEL;
    302     installer_state->set_level(level);
    303     installer_state->set_operation(operation);
    304     // Hope this next one isn't checked for now.
    305     installer_state->set_state_key(L"PROBABLY_INVALID_REG_PATH");
    306     installer_state->set_state_type(BrowserDistribution::CHROME_BROWSER);
    307     installer_state->set_package_type(multi_install ?
    308                                           InstallerState::MULTI_PACKAGE :
    309                                           InstallerState::SINGLE_PACKAGE);
    310     return installer_state.release();
    311   }
    312 
    313   static void AddChromeBinariesToInstallerState(
    314       const InstallationState& machine_state,
    315       MockInstallerState* installer_state) {
    316     if (!installer_state->is_multi_install()) {
    317       NOTREACHED();
    318       return;
    319     }
    320     if (installer_state->FindProduct(BrowserDistribution::CHROME_BINARIES))
    321       return;
    322 
    323     // Fresh install or upgrade?
    324     const ProductState* chrome_binaries =
    325         machine_state.GetProductState(installer_state->system_install(),
    326                                       BrowserDistribution::CHROME_BINARIES);
    327     if (chrome_binaries != NULL) {
    328       installer_state->AddProductFromState(BrowserDistribution::CHROME_BINARIES,
    329                                            *chrome_binaries);
    330     } else {
    331       BrowserDistribution* dist =
    332           BrowserDistribution::GetSpecificDistribution(
    333               BrowserDistribution::CHROME_BINARIES);
    334       scoped_ptr<Product> product(new Product(dist));
    335       product->SetOption(installer::kOptionMultiInstall, true);
    336       installer_state->AddProduct(&product);
    337     }
    338   }
    339 
    340   static void AddChromeToInstallerState(
    341       const InstallationState& machine_state,
    342       MockInstallerState* installer_state) {
    343     // Fresh install or upgrade?
    344     const ProductState* chrome =
    345         machine_state.GetProductState(installer_state->system_install(),
    346                                       BrowserDistribution::CHROME_BROWSER);
    347     if (chrome != NULL &&
    348         chrome->is_multi_install() == installer_state->is_multi_install()) {
    349       installer_state->AddProductFromState(BrowserDistribution::CHROME_BROWSER,
    350                                            *chrome);
    351     } else {
    352       BrowserDistribution* dist =
    353           BrowserDistribution::GetSpecificDistribution(
    354               BrowserDistribution::CHROME_BROWSER);
    355       scoped_ptr<Product> product(new Product(dist));
    356       if (installer_state->is_multi_install())
    357         product->SetOption(installer::kOptionMultiInstall, true);
    358       installer_state->AddProduct(&product);
    359     }
    360   }
    361 
    362   static void AddChromeFrameToInstallerState(
    363       const InstallationState& machine_state,
    364       MockInstallerState* installer_state) {
    365     // Fresh install or upgrade?
    366     const ProductState* cf =
    367         machine_state.GetProductState(installer_state->system_install(),
    368                                       BrowserDistribution::CHROME_FRAME);
    369     if (cf != NULL) {
    370       installer_state->AddProductFromState(BrowserDistribution::CHROME_FRAME,
    371                                            *cf);
    372     } else {
    373       BrowserDistribution* dist =
    374           BrowserDistribution::GetSpecificDistribution(
    375               BrowserDistribution::CHROME_FRAME);
    376       scoped_ptr<Product> product(new Product(dist));
    377       if (installer_state->is_multi_install())
    378         product->SetOption(installer::kOptionMultiInstall, true);
    379       installer_state->AddProduct(&product);
    380     }
    381   }
    382 
    383   static MockInstallerState* BuildChromeInstallerState(
    384       bool system_install,
    385       bool multi_install,
    386       const InstallationState& machine_state,
    387       InstallerState::Operation operation) {
    388     scoped_ptr<MockInstallerState> installer_state(
    389         BuildBasicInstallerState(system_install, multi_install, machine_state,
    390                                  operation));
    391     if (multi_install) {
    392       // We don't want to include Chrome Binaries for uninstall if the machine
    393       // has other products. For simplicity, we check Chrome Frame only.
    394       bool machine_has_other_products =
    395           machine_state.GetProductState(system_install,
    396               BrowserDistribution::CHROME_FRAME) != NULL;
    397       if (operation != InstallerState::UNINSTALL || !machine_has_other_products)
    398         AddChromeBinariesToInstallerState(machine_state, installer_state.get());
    399     }
    400     AddChromeToInstallerState(machine_state, installer_state.get());
    401     return installer_state.release();
    402   }
    403 
    404   static MockInstallerState* BuildChromeFrameInstallerState(
    405       bool system_install,
    406       bool multi_install,
    407       const InstallationState& machine_state,
    408       InstallerState::Operation operation) {
    409     // This method only works for installation/upgrade.
    410     DCHECK(operation != InstallerState::UNINSTALL);
    411     scoped_ptr<MockInstallerState> installer_state(
    412         BuildBasicInstallerState(system_install, multi_install, machine_state,
    413                                  operation));
    414     if (multi_install)
    415       AddChromeBinariesToInstallerState(machine_state, installer_state.get());
    416     AddChromeFrameToInstallerState(machine_state, installer_state.get());
    417     return installer_state.release();
    418   }
    419 
    420  protected:
    421   scoped_ptr<Version> current_version_;
    422   scoped_ptr<Version> new_version_;
    423   base::FilePath archive_path_;
    424   base::FilePath installation_path_;
    425   base::FilePath setup_path_;
    426   base::FilePath src_path_;
    427   base::FilePath temp_dir_;
    428 };
    429 
    430 // Tests
    431 //------------------------------------------------------------------------------
    432 
    433 TEST_F(InstallWorkerTest, TestInstallChromeSingleSystem) {
    434   const bool system_level = true;
    435   const bool multi_install = false;
    436   MockWorkItemList work_item_list;
    437 
    438   scoped_ptr<InstallationState> installation_state(
    439       BuildChromeInstallationState(system_level, multi_install));
    440 
    441   scoped_ptr<InstallerState> installer_state(
    442       BuildChromeInstallerState(system_level, multi_install,
    443                                 *installation_state,
    444                                 InstallerState::SINGLE_INSTALL_OR_UPDATE));
    445 
    446   // Set up some expectations.
    447   // TODO(robertshield): Set up some real expectations.
    448   EXPECT_CALL(work_item_list, AddCopyTreeWorkItem(_, _, _, _, _))
    449       .Times(AtLeast(1));
    450 
    451   AddInstallWorkItems(*installation_state.get(),
    452                       *installer_state.get(),
    453                       setup_path_,
    454                       archive_path_,
    455                       src_path_,
    456                       temp_dir_,
    457                       current_version_.get(),
    458                       *new_version_.get(),
    459                       &work_item_list);
    460 }
    461 
    462 namespace {
    463 
    464 const wchar_t elevation_key[] =
    465     L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"
    466     L"{E0A900DF-9611-4446-86BD-4B1D47E7DB2A}";
    467 const wchar_t old_elevation_key[] =
    468     L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"
    469     L"{6C288DD7-76FB-4721-B628-56FAC252E199}";
    470 
    471 }  // namespace
    472 
    473 // A test class for worker functions that manipulate the old IE low rights
    474 // policies.
    475 // Parameters:
    476 // bool : system_level_
    477 // bool : multi_install_
    478 class OldIELowRightsTests : public InstallWorkerTest,
    479   public ::testing::WithParamInterface<std::tr1::tuple<bool, bool> > {
    480  protected:
    481   virtual void SetUp() OVERRIDE {
    482     InstallWorkerTest::SetUp();
    483 
    484     const ParamType& param = GetParam();
    485     system_level_ = std::tr1::get<0>(param);
    486     multi_install_ = std::tr1::get<1>(param);
    487     root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
    488 
    489     installation_state_.reset(new MockInstallationState());
    490     AddChromeFrameToInstallationState(system_level_, multi_install_,
    491                                       installation_state_.get());
    492     installer_state_.reset(BuildBasicInstallerState(
    493         system_level_, multi_install_, *installation_state_,
    494         multi_install_ ? InstallerState::MULTI_UPDATE :
    495             InstallerState::SINGLE_INSTALL_OR_UPDATE));
    496     if (multi_install_)
    497       AddChromeBinariesToInstallerState(*installation_state_,
    498                                         installer_state_.get());
    499     AddChromeFrameToInstallerState(*installation_state_,
    500                                    installer_state_.get());
    501   }
    502 
    503   scoped_ptr<MockInstallationState> installation_state_;
    504   scoped_ptr<MockInstallerState> installer_state_;
    505   bool system_level_;
    506   bool multi_install_;
    507   HKEY root_key_;
    508 };
    509 
    510 TEST_P(OldIELowRightsTests, AddDeleteOldIELowRightsPolicyWorkItems) {
    511   StrictMock<MockWorkItemList> work_item_list;
    512 
    513   EXPECT_CALL(work_item_list,
    514               AddDeleteRegKeyWorkItem(root_key_, StrEq(old_elevation_key)))
    515       .Times(1);
    516 
    517   AddDeleteOldIELowRightsPolicyWorkItems(*installer_state_.get(),
    518                                          &work_item_list);
    519 }
    520 
    521 INSTANTIATE_TEST_CASE_P(Variations, OldIELowRightsTests,
    522                         Combine(Bool(), Bool()));
    523 
    524 TEST_F(InstallWorkerTest, GoogleUpdateWorkItemsTest) {
    525   const bool system_level = true;
    526   const bool multi_install = true;
    527   MockWorkItemList work_item_list;
    528 
    529   scoped_ptr<MockInstallationState> installation_state(
    530       BuildChromeInstallationState(system_level, false));
    531 
    532   MockProductState cf_state;
    533   cf_state.set_version(new Version(*current_version_));
    534   cf_state.set_multi_install(false);
    535 
    536   installation_state->SetProductState(system_level,
    537       BrowserDistribution::CHROME_FRAME, cf_state);
    538 
    539   scoped_ptr<MockInstallerState> installer_state(
    540       BuildChromeInstallerState(system_level, multi_install,
    541                                 *installation_state,
    542                                 InstallerState::MULTI_INSTALL));
    543 
    544   // Expect the multi Client State key to be created.
    545   BrowserDistribution* multi_dist =
    546       BrowserDistribution::GetSpecificDistribution(
    547           BrowserDistribution::CHROME_BINARIES);
    548   std::wstring multi_app_guid(multi_dist->GetAppGuid());
    549   std::wstring multi_client_state_suffix(L"ClientState\\" + multi_app_guid);
    550   EXPECT_CALL(work_item_list,
    551               AddCreateRegKeyWorkItem(_, HasSubstr(multi_client_state_suffix)))
    552       .Times(testing::AnyNumber());
    553 
    554   // Expect ClientStateMedium to be created for system-level installs.
    555   EXPECT_CALL(work_item_list,
    556               AddCreateRegKeyWorkItem(_, HasSubstr(L"ClientStateMedium\\" +
    557                                                    multi_app_guid)))
    558       .Times(system_level ? 1 : 0);
    559 
    560   // Expect to see a set value for the "TEST" brand code in the multi Client
    561   // State key.
    562   EXPECT_CALL(work_item_list,
    563               AddSetRegStringValueWorkItem(_,
    564                                            HasSubstr(multi_client_state_suffix),
    565                                            StrEq(google_update::kRegBrandField),
    566                                            StrEq(L"TEST"),
    567                                            _)).Times(1);
    568 
    569   // There may also be some calls to set 'ap' values.
    570   EXPECT_CALL(work_item_list,
    571               AddSetRegStringValueWorkItem(_, _,
    572                                            StrEq(google_update::kRegApField),
    573                                            _, _)).Times(testing::AnyNumber());
    574 
    575   // Expect "oeminstall" to be cleared.
    576   EXPECT_CALL(work_item_list,
    577               AddDeleteRegValueWorkItem(
    578                   _,
    579                   HasSubstr(multi_client_state_suffix),
    580                   StrEq(google_update::kRegOemInstallField))).Times(1);
    581 
    582   // Expect "eulaaccepted" to set.
    583   EXPECT_CALL(work_item_list,
    584               AddSetRegDwordValueWorkItem(
    585                   _,
    586                   HasSubstr(multi_client_state_suffix),
    587                   StrEq(google_update::kRegEULAAceptedField),
    588                   Eq(static_cast<DWORD>(1)),
    589                   _)).Times(1);
    590 
    591   AddGoogleUpdateWorkItems(*installation_state.get(),
    592                            *installer_state.get(),
    593                            &work_item_list);
    594 }
    595 
    596 // Test that usagestats values are migrated properly.
    597 TEST_F(InstallWorkerTest, AddUsageStatsWorkItems) {
    598   const bool system_level = true;
    599   const bool multi_install = true;
    600   MockWorkItemList work_item_list;
    601 
    602   scoped_ptr<MockInstallationState> installation_state(
    603       BuildChromeInstallationState(system_level, multi_install));
    604 
    605   MockProductState chrome_state;
    606   chrome_state.set_version(new Version(*current_version_));
    607   chrome_state.set_multi_install(false);
    608   chrome_state.set_usagestats(1);
    609 
    610   installation_state->SetProductState(system_level,
    611       BrowserDistribution::CHROME_BROWSER, chrome_state);
    612 
    613   scoped_ptr<MockInstallerState> installer_state(
    614       BuildChromeInstallerState(system_level, multi_install,
    615                                 *installation_state,
    616                                 InstallerState::MULTI_INSTALL));
    617 
    618   // Expect the multi Client State key to be created.
    619   BrowserDistribution* multi_dist =
    620       BrowserDistribution::GetSpecificDistribution(
    621           BrowserDistribution::CHROME_BINARIES);
    622   std::wstring multi_app_guid(multi_dist->GetAppGuid());
    623   EXPECT_CALL(work_item_list,
    624               AddCreateRegKeyWorkItem(_, HasSubstr(multi_app_guid))).Times(1);
    625 
    626   // Expect to see a set value for the usagestats in the multi Client State key.
    627   EXPECT_CALL(work_item_list,
    628               AddSetRegDwordValueWorkItem(
    629                   _,
    630                   HasSubstr(multi_app_guid),
    631                   StrEq(google_update::kRegUsageStatsField),
    632                   Eq(static_cast<DWORD>(1)),
    633                   Eq(true))).Times(1);
    634 
    635   // Expect to see some values cleaned up from Chrome's keys.
    636   BrowserDistribution* chrome_dist =
    637       BrowserDistribution::GetSpecificDistribution(
    638           BrowserDistribution::CHROME_BROWSER);
    639   if (system_level) {
    640     EXPECT_CALL(work_item_list,
    641                 AddDeleteRegValueWorkItem(
    642                     _,
    643                     StrEq(chrome_dist->GetStateMediumKey()),
    644                     StrEq(google_update::kRegUsageStatsField))).Times(1);
    645     EXPECT_CALL(work_item_list,
    646                 AddDeleteRegValueWorkItem(
    647                     Eq(HKEY_CURRENT_USER),
    648                     StrEq(chrome_dist->GetStateKey()),
    649                     StrEq(google_update::kRegUsageStatsField))).Times(1);
    650   }
    651   EXPECT_CALL(work_item_list,
    652               AddDeleteRegValueWorkItem(
    653                   Eq(installer_state->root_key()),
    654                   StrEq(chrome_dist->GetStateKey()),
    655                   StrEq(google_update::kRegUsageStatsField))).Times(1);
    656 
    657   AddUsageStatsWorkItems(*installation_state.get(),
    658                          *installer_state.get(),
    659                          &work_item_list);
    660 }
    661 
    662 // The Quick Enable tests only make sense for the Google Chrome build as it
    663 // interacts with registry values that are specific to Google Update.
    664 #if defined(GOOGLE_CHROME_BUILD)
    665 
    666 // Test scenarios under which the quick-enable-cf command should not exist after
    667 // the run.  We're permissive in that we allow the DeleteRegKeyWorkItem even if
    668 // it isn't strictly needed.
    669 class QuickEnableAbsentTest : public InstallWorkerTest {
    670  public:
    671   virtual void SetUp() {
    672     InstallWorkerTest::SetUp();
    673     root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
    674     delete_reg_key_item_.reset(
    675         WorkItem::CreateDeleteRegKeyWorkItem(root_key_, kRegKeyPath));
    676     machine_state_.reset(new MockInstallationState());
    677     EXPECT_CALL(work_item_list_,
    678                 AddDeleteRegKeyWorkItem(Eq(root_key_), StrCaseEq(kRegKeyPath)))
    679         .Times(AtMost(1))
    680         .WillRepeatedly(Return(delete_reg_key_item_.get()));
    681   }
    682   virtual void TearDown() {
    683     machine_state_.reset();
    684     delete_reg_key_item_.reset();
    685     root_key_ = NULL;
    686     InstallWorkerTest::TearDown();
    687   }
    688  protected:
    689   static const bool system_level_ = false;
    690   static const wchar_t kRegKeyPath[];
    691   HKEY root_key_;
    692   scoped_ptr<DeleteRegKeyWorkItem> delete_reg_key_item_;
    693   scoped_ptr<MockInstallationState> machine_state_;
    694   StrictMock<MockWorkItemList> work_item_list_;
    695 };
    696 
    697 const wchar_t QuickEnableAbsentTest::kRegKeyPath[] =
    698     L"Software\\Google\\Update\\Clients\\"
    699     L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}\\Commands\\quick-enable-cf";
    700 
    701 TEST_F(QuickEnableAbsentTest, CleanInstallSingleChrome) {
    702   // Install single Chrome on a clean system.
    703   scoped_ptr<MockInstallerState> installer_state(
    704       BuildBasicInstallerState(system_level_, true, *machine_state_,
    705                                 InstallerState::MULTI_UPDATE));
    706   AddQuickEnableChromeFrameWorkItems(*installer_state, &work_item_list_);
    707 }
    708 
    709 TEST_F(InstallWorkerTest, WillProductBePresentAfterSetup) {
    710   BrowserDistribution::Type prod_type_list[] = {
    711     BrowserDistribution::CHROME_BROWSER,
    712     BrowserDistribution::CHROME_FRAME,
    713     // Excluding BrowserDistribution::CHROME_BINARIES, since it is installed
    714     // along with other products.
    715   };
    716   enum {  // Index into prod_type_list[].
    717     TYPE_BROWSER = 0,
    718     TYPE_CF,
    719     NUM_TYPE  // This must appear last.
    720   };
    721   DCHECK(arraysize(prod_type_list) == NUM_TYPE);
    722   InstallerState::Operation op_list[] = {
    723     InstallerState::UNINSTALL,
    724     InstallerState::SINGLE_INSTALL_OR_UPDATE
    725   };
    726 
    727   const bool system_level = false;
    728   const bool multi_install = true;
    729 
    730   // Loop over machine states: {No product, Chrome, CF, Chrome + CF}.
    731   for (int i_mach = 0; i_mach < (1 << NUM_TYPE); ++i_mach) {
    732     // i_mach is the machine state before operation, as bit mask.
    733     scoped_ptr<MockInstallationState> machine_state(
    734         new MockInstallationState());
    735     if ((i_mach & (1 << TYPE_BROWSER)) != 0) {  // Add Chrome.
    736       AddChromeToInstallationState(system_level, multi_install,
    737                                    machine_state.get());
    738     }
    739     if ((i_mach & (1 << TYPE_CF)) != 0) {  // Add Chrome Frame.
    740       AddChromeFrameToInstallationState(system_level, multi_install,
    741                                         machine_state.get());
    742     }
    743 
    744     // Loop over operations: {uninstall, install/update}.
    745     for (int i_op = 0; i_op < arraysize(op_list); ++i_op) {
    746 
    747       // Loop over product types to operate on: {TYPE_BROWSER, TYPE_CF}.
    748       for (int i_type_op = 0; i_type_op < NUM_TYPE; ++i_type_op) {
    749         scoped_ptr<InstallerState> installer_state;
    750         if (i_type_op == TYPE_BROWSER) {
    751           installer_state.reset(BuildChromeInstallerState(
    752               system_level, multi_install, *machine_state, op_list[i_op]));
    753         } else if (i_type_op == TYPE_CF) {
    754           // Skip the CF uninstall case due to limitations in
    755           // BuildChromeFrameInstallerState().
    756           if (op_list[i_op] == InstallerState::UNINSTALL)
    757             continue;
    758 
    759           installer_state.reset(BuildChromeFrameInstallerState(
    760               system_level, multi_install, *machine_state, op_list[i_op]));
    761         } else {
    762           NOTREACHED();
    763         }
    764 
    765         // Calculate the machine state after operation, as bit mask.
    766         // If uninstall, remove product with bitwise AND; else add with OR.
    767         int mach_after = (op_list[i_op] == InstallerState::UNINSTALL) ?
    768             i_mach & ~(1 << i_type_op) : i_mach | (1 << i_type_op);
    769 
    770         // Verify predicted presence of Chrome Binaries.
    771         bool bin_res = installer::WillProductBePresentAfterSetup(
    772             *installer_state,
    773             *machine_state,
    774             BrowserDistribution::CHROME_BINARIES);
    775         // Binaries are expected to be present iff any product is installed.
    776         bool bin_expect = mach_after != 0;
    777         EXPECT_EQ(bin_expect, bin_res);
    778 
    779         // Loop over product types to check: {TYPE_BROWSER, TYPE_CF}.
    780         for (int i_type_check = 0; i_type_check < NUM_TYPE; ++i_type_check) {
    781           // Verify predicted presence of product.
    782           bool prod_res = installer::WillProductBePresentAfterSetup(
    783               *installer_state,
    784               *machine_state,
    785               prod_type_list[i_type_check]);
    786           bool prod_expect = (mach_after & (1 << i_type_check)) != 0;
    787           EXPECT_EQ(prod_expect, prod_res);
    788         }
    789       }
    790     }
    791   }
    792 }
    793 
    794 #endif  // defined(GOOGLE_CHROME_BUILD)
    795