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