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   const HKEY kRegRoot = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
    439   static const wchar_t kRegKeyPath[] = L"Software\\Chromium\\test";
    440   scoped_ptr<CreateRegKeyWorkItem> create_reg_key_work_item(
    441       WorkItem::CreateCreateRegKeyWorkItem(
    442           kRegRoot, kRegKeyPath, WorkItem::kWow64Default));
    443   scoped_ptr<SetRegValueWorkItem> set_reg_value_work_item(
    444       WorkItem::CreateSetRegValueWorkItem(
    445           kRegRoot, kRegKeyPath, WorkItem::kWow64Default, L"", L"", false));
    446 
    447   scoped_ptr<InstallationState> installation_state(
    448       BuildChromeInstallationState(system_level, multi_install));
    449 
    450   scoped_ptr<InstallerState> installer_state(
    451       BuildChromeInstallerState(system_level, multi_install,
    452                                 *installation_state,
    453                                 InstallerState::SINGLE_INSTALL_OR_UPDATE));
    454 
    455   // Set up some expectations.
    456   // TODO(robertshield): Set up some real expectations.
    457   EXPECT_CALL(work_item_list, AddCopyTreeWorkItem(_, _, _, _, _))
    458       .Times(AtLeast(1));
    459   EXPECT_CALL(work_item_list, AddCreateRegKeyWorkItem(_, _))
    460       .WillRepeatedly(Return(create_reg_key_work_item.get()));
    461   EXPECT_CALL(work_item_list, AddSetRegStringValueWorkItem(_, _, _, _, _))
    462       .WillRepeatedly(Return(set_reg_value_work_item.get()));
    463 
    464   AddInstallWorkItems(*installation_state.get(),
    465                       *installer_state.get(),
    466                       setup_path_,
    467                       archive_path_,
    468                       src_path_,
    469                       temp_dir_,
    470                       current_version_.get(),
    471                       *new_version_.get(),
    472                       &work_item_list);
    473 }
    474 
    475 namespace {
    476 
    477 const wchar_t elevation_key[] =
    478     L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"
    479     L"{E0A900DF-9611-4446-86BD-4B1D47E7DB2A}";
    480 const wchar_t old_elevation_key[] =
    481     L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"
    482     L"{6C288DD7-76FB-4721-B628-56FAC252E199}";
    483 
    484 }  // namespace
    485 
    486 // A test class for worker functions that manipulate the old IE low rights
    487 // policies.
    488 // Parameters:
    489 // bool : system_level_
    490 // bool : multi_install_
    491 class OldIELowRightsTests : public InstallWorkerTest,
    492   public ::testing::WithParamInterface<std::tr1::tuple<bool, bool> > {
    493  protected:
    494   virtual void SetUp() OVERRIDE {
    495     InstallWorkerTest::SetUp();
    496 
    497     const ParamType& param = GetParam();
    498     system_level_ = std::tr1::get<0>(param);
    499     multi_install_ = std::tr1::get<1>(param);
    500     root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
    501 
    502     installation_state_.reset(new MockInstallationState());
    503     AddChromeFrameToInstallationState(system_level_, multi_install_,
    504                                       installation_state_.get());
    505     installer_state_.reset(BuildBasicInstallerState(
    506         system_level_, multi_install_, *installation_state_,
    507         multi_install_ ? InstallerState::MULTI_UPDATE :
    508             InstallerState::SINGLE_INSTALL_OR_UPDATE));
    509     if (multi_install_)
    510       AddChromeBinariesToInstallerState(*installation_state_,
    511                                         installer_state_.get());
    512     AddChromeFrameToInstallerState(*installation_state_,
    513                                    installer_state_.get());
    514   }
    515 
    516   scoped_ptr<MockInstallationState> installation_state_;
    517   scoped_ptr<MockInstallerState> installer_state_;
    518   bool system_level_;
    519   bool multi_install_;
    520   HKEY root_key_;
    521 };
    522 
    523 TEST_P(OldIELowRightsTests, AddDeleteOldIELowRightsPolicyWorkItems) {
    524   StrictMock<MockWorkItemList> work_item_list;
    525 
    526   EXPECT_CALL(work_item_list,
    527               AddDeleteRegKeyWorkItem(root_key_, StrEq(old_elevation_key)))
    528       .Times(1);
    529 
    530   AddDeleteOldIELowRightsPolicyWorkItems(*installer_state_.get(),
    531                                          &work_item_list);
    532 }
    533 
    534 INSTANTIATE_TEST_CASE_P(Variations, OldIELowRightsTests,
    535                         Combine(Bool(), Bool()));
    536 
    537 TEST_F(InstallWorkerTest, GoogleUpdateWorkItemsTest) {
    538   const bool system_level = true;
    539   const bool multi_install = true;
    540   MockWorkItemList work_item_list;
    541 
    542   scoped_ptr<MockInstallationState> installation_state(
    543       BuildChromeInstallationState(system_level, false));
    544 
    545   MockProductState cf_state;
    546   cf_state.set_version(new Version(*current_version_));
    547   cf_state.set_multi_install(false);
    548 
    549   installation_state->SetProductState(system_level,
    550       BrowserDistribution::CHROME_FRAME, cf_state);
    551 
    552   scoped_ptr<MockInstallerState> installer_state(
    553       BuildChromeInstallerState(system_level, multi_install,
    554                                 *installation_state,
    555                                 InstallerState::MULTI_INSTALL));
    556 
    557   // Expect the multi Client State key to be created.
    558   BrowserDistribution* multi_dist =
    559       BrowserDistribution::GetSpecificDistribution(
    560           BrowserDistribution::CHROME_BINARIES);
    561   std::wstring multi_app_guid(multi_dist->GetAppGuid());
    562   std::wstring multi_client_state_suffix(L"ClientState\\" + multi_app_guid);
    563   EXPECT_CALL(work_item_list,
    564               AddCreateRegKeyWorkItem(_, HasSubstr(multi_client_state_suffix)))
    565       .Times(testing::AnyNumber());
    566 
    567   // Expect ClientStateMedium to be created for system-level installs.
    568   EXPECT_CALL(work_item_list,
    569               AddCreateRegKeyWorkItem(_, HasSubstr(L"ClientStateMedium\\" +
    570                                                    multi_app_guid)))
    571       .Times(system_level ? 1 : 0);
    572 
    573   // Expect to see a set value for the "TEST" brand code in the multi Client
    574   // State key.
    575   EXPECT_CALL(work_item_list,
    576               AddSetRegStringValueWorkItem(_,
    577                                            HasSubstr(multi_client_state_suffix),
    578                                            StrEq(google_update::kRegBrandField),
    579                                            StrEq(L"TEST"),
    580                                            _)).Times(1);
    581 
    582   // There may also be some calls to set 'ap' values.
    583   EXPECT_CALL(work_item_list,
    584               AddSetRegStringValueWorkItem(_, _,
    585                                            StrEq(google_update::kRegApField),
    586                                            _, _)).Times(testing::AnyNumber());
    587 
    588   // Expect "oeminstall" to be cleared.
    589   EXPECT_CALL(work_item_list,
    590               AddDeleteRegValueWorkItem(
    591                   _,
    592                   HasSubstr(multi_client_state_suffix),
    593                   StrEq(google_update::kRegOemInstallField))).Times(1);
    594 
    595   // Expect "eulaaccepted" to set.
    596   EXPECT_CALL(work_item_list,
    597               AddSetRegDwordValueWorkItem(
    598                   _,
    599                   HasSubstr(multi_client_state_suffix),
    600                   StrEq(google_update::kRegEULAAceptedField),
    601                   Eq(static_cast<DWORD>(1)),
    602                   _)).Times(1);
    603 
    604   AddGoogleUpdateWorkItems(*installation_state.get(),
    605                            *installer_state.get(),
    606                            &work_item_list);
    607 }
    608 
    609 // Test that usagestats values are migrated properly.
    610 TEST_F(InstallWorkerTest, AddUsageStatsWorkItems) {
    611   const bool system_level = true;
    612   const bool multi_install = true;
    613   MockWorkItemList work_item_list;
    614 
    615   scoped_ptr<MockInstallationState> installation_state(
    616       BuildChromeInstallationState(system_level, multi_install));
    617 
    618   MockProductState chrome_state;
    619   chrome_state.set_version(new Version(*current_version_));
    620   chrome_state.set_multi_install(false);
    621   chrome_state.set_usagestats(1);
    622 
    623   installation_state->SetProductState(system_level,
    624       BrowserDistribution::CHROME_BROWSER, chrome_state);
    625 
    626   scoped_ptr<MockInstallerState> installer_state(
    627       BuildChromeInstallerState(system_level, multi_install,
    628                                 *installation_state,
    629                                 InstallerState::MULTI_INSTALL));
    630 
    631   // Expect the multi Client State key to be created.
    632   BrowserDistribution* multi_dist =
    633       BrowserDistribution::GetSpecificDistribution(
    634           BrowserDistribution::CHROME_BINARIES);
    635   std::wstring multi_app_guid(multi_dist->GetAppGuid());
    636   EXPECT_CALL(work_item_list,
    637               AddCreateRegKeyWorkItem(_, HasSubstr(multi_app_guid))).Times(1);
    638 
    639   // Expect to see a set value for the usagestats in the multi Client State key.
    640   EXPECT_CALL(work_item_list,
    641               AddSetRegDwordValueWorkItem(
    642                   _,
    643                   HasSubstr(multi_app_guid),
    644                   StrEq(google_update::kRegUsageStatsField),
    645                   Eq(static_cast<DWORD>(1)),
    646                   Eq(true))).Times(1);
    647 
    648   // Expect to see some values cleaned up from Chrome's keys.
    649   BrowserDistribution* chrome_dist =
    650       BrowserDistribution::GetSpecificDistribution(
    651           BrowserDistribution::CHROME_BROWSER);
    652   if (system_level) {
    653     EXPECT_CALL(work_item_list,
    654                 AddDeleteRegValueWorkItem(
    655                     _,
    656                     StrEq(chrome_dist->GetStateMediumKey()),
    657                     StrEq(google_update::kRegUsageStatsField))).Times(1);
    658     EXPECT_CALL(work_item_list,
    659                 AddDeleteRegValueWorkItem(
    660                     Eq(HKEY_CURRENT_USER),
    661                     StrEq(chrome_dist->GetStateKey()),
    662                     StrEq(google_update::kRegUsageStatsField))).Times(1);
    663   }
    664   EXPECT_CALL(work_item_list,
    665               AddDeleteRegValueWorkItem(
    666                   Eq(installer_state->root_key()),
    667                   StrEq(chrome_dist->GetStateKey()),
    668                   StrEq(google_update::kRegUsageStatsField))).Times(1);
    669 
    670   AddUsageStatsWorkItems(*installation_state.get(),
    671                          *installer_state.get(),
    672                          &work_item_list);
    673 }
    674 
    675 // The Quick Enable tests only make sense for the Google Chrome build as it
    676 // interacts with registry values that are specific to Google Update.
    677 #if defined(GOOGLE_CHROME_BUILD)
    678 
    679 // Test scenarios under which the quick-enable-cf command should not exist after
    680 // the run.  We're permissive in that we allow the DeleteRegKeyWorkItem even if
    681 // it isn't strictly needed.
    682 class QuickEnableAbsentTest : public InstallWorkerTest {
    683  public:
    684   virtual void SetUp() {
    685     InstallWorkerTest::SetUp();
    686     root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
    687     delete_reg_key_item_.reset(WorkItem::CreateDeleteRegKeyWorkItem(
    688         root_key_, kRegKeyPath, WorkItem::kWow64Default));
    689     machine_state_.reset(new MockInstallationState());
    690     EXPECT_CALL(work_item_list_,
    691                 AddDeleteRegKeyWorkItem(Eq(root_key_), StrCaseEq(kRegKeyPath)))
    692         .Times(AtMost(1))
    693         .WillRepeatedly(Return(delete_reg_key_item_.get()));
    694   }
    695   virtual void TearDown() {
    696     machine_state_.reset();
    697     delete_reg_key_item_.reset();
    698     root_key_ = NULL;
    699     InstallWorkerTest::TearDown();
    700   }
    701  protected:
    702   static const bool system_level_ = false;
    703   static const wchar_t kRegKeyPath[];
    704   HKEY root_key_;
    705   scoped_ptr<DeleteRegKeyWorkItem> delete_reg_key_item_;
    706   scoped_ptr<MockInstallationState> machine_state_;
    707   StrictMock<MockWorkItemList> work_item_list_;
    708 };
    709 
    710 const wchar_t QuickEnableAbsentTest::kRegKeyPath[] =
    711     L"Software\\Google\\Update\\Clients\\"
    712     L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}\\Commands\\quick-enable-cf";
    713 
    714 TEST_F(QuickEnableAbsentTest, CleanInstallSingleChrome) {
    715   // Install single Chrome on a clean system.
    716   scoped_ptr<MockInstallerState> installer_state(
    717       BuildBasicInstallerState(system_level_, true, *machine_state_,
    718                                 InstallerState::MULTI_UPDATE));
    719   AddQuickEnableChromeFrameWorkItems(*installer_state, &work_item_list_);
    720 }
    721 
    722 TEST_F(InstallWorkerTest, WillProductBePresentAfterSetup) {
    723   BrowserDistribution::Type prod_type_list[] = {
    724     BrowserDistribution::CHROME_BROWSER,
    725     BrowserDistribution::CHROME_FRAME,
    726     // Excluding BrowserDistribution::CHROME_BINARIES, since it is installed
    727     // along with other products.
    728   };
    729   enum {  // Index into prod_type_list[].
    730     TYPE_BROWSER = 0,
    731     TYPE_CF,
    732     NUM_TYPE  // This must appear last.
    733   };
    734   DCHECK(arraysize(prod_type_list) == NUM_TYPE);
    735   InstallerState::Operation op_list[] = {
    736     InstallerState::UNINSTALL,
    737     InstallerState::SINGLE_INSTALL_OR_UPDATE
    738   };
    739 
    740   const bool system_level = false;
    741   const bool multi_install = true;
    742 
    743   // Loop over machine states: {No product, Chrome, CF, Chrome + CF}.
    744   for (int i_mach = 0; i_mach < (1 << NUM_TYPE); ++i_mach) {
    745     // i_mach is the machine state before operation, as bit mask.
    746     scoped_ptr<MockInstallationState> machine_state(
    747         new MockInstallationState());
    748     if ((i_mach & (1 << TYPE_BROWSER)) != 0) {  // Add Chrome.
    749       AddChromeToInstallationState(system_level, multi_install,
    750                                    machine_state.get());
    751     }
    752     if ((i_mach & (1 << TYPE_CF)) != 0) {  // Add Chrome Frame.
    753       AddChromeFrameToInstallationState(system_level, multi_install,
    754                                         machine_state.get());
    755     }
    756 
    757     // Loop over operations: {uninstall, install/update}.
    758     for (int i_op = 0; i_op < arraysize(op_list); ++i_op) {
    759 
    760       // Loop over product types to operate on: {TYPE_BROWSER, TYPE_CF}.
    761       for (int i_type_op = 0; i_type_op < NUM_TYPE; ++i_type_op) {
    762         scoped_ptr<InstallerState> installer_state;
    763         if (i_type_op == TYPE_BROWSER) {
    764           installer_state.reset(BuildChromeInstallerState(
    765               system_level, multi_install, *machine_state, op_list[i_op]));
    766         } else if (i_type_op == TYPE_CF) {
    767           // Skip the CF uninstall case due to limitations in
    768           // BuildChromeFrameInstallerState().
    769           if (op_list[i_op] == InstallerState::UNINSTALL)
    770             continue;
    771 
    772           installer_state.reset(BuildChromeFrameInstallerState(
    773               system_level, multi_install, *machine_state, op_list[i_op]));
    774         } else {
    775           NOTREACHED();
    776         }
    777 
    778         // Calculate the machine state after operation, as bit mask.
    779         // If uninstall, remove product with bitwise AND; else add with OR.
    780         int mach_after = (op_list[i_op] == InstallerState::UNINSTALL) ?
    781             i_mach & ~(1 << i_type_op) : i_mach | (1 << i_type_op);
    782 
    783         // Verify predicted presence of Chrome Binaries.
    784         bool bin_res = installer::WillProductBePresentAfterSetup(
    785             *installer_state,
    786             *machine_state,
    787             BrowserDistribution::CHROME_BINARIES);
    788         // Binaries are expected to be present iff any product is installed.
    789         bool bin_expect = mach_after != 0;
    790         EXPECT_EQ(bin_expect, bin_res);
    791 
    792         // Loop over product types to check: {TYPE_BROWSER, TYPE_CF}.
    793         for (int i_type_check = 0; i_type_check < NUM_TYPE; ++i_type_check) {
    794           // Verify predicted presence of product.
    795           bool prod_res = installer::WillProductBePresentAfterSetup(
    796               *installer_state,
    797               *machine_state,
    798               prod_type_list[i_type_check]);
    799           bool prod_expect = (mach_after & (1 << i_type_check)) != 0;
    800           EXPECT_EQ(prod_expect, prod_res);
    801         }
    802       }
    803     }
    804   }
    805 }
    806 
    807 #endif  // defined(GOOGLE_CHROME_BUILD)
    808