install_worker_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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      bool with_chrome_frame_ready_mode,
224      MockInstallationState* installation_state) {
225    if (multi_install)
226      MaybeAddBinariesToInstallationState(system_level, installation_state);
227    MockProductState product_state;
228    product_state.set_version(new Version(*current_version_));
229    product_state.set_multi_install(multi_install);
230    product_state.set_brand(L"TEST");
231    product_state.set_eula_accepted(1);
232    BrowserDistribution* dist =
233        BrowserDistribution::GetSpecificDistribution(
234            BrowserDistribution::CHROME_BROWSER);
235    base::FilePath install_path =
236        installer::GetChromeInstallPath(system_level, dist);
237    product_state.SetUninstallProgram(
238      install_path.AppendASCII(current_version_->GetString())
239          .Append(installer::kInstallerDir)
240          .Append(installer::kSetupExe));
241    product_state.AddUninstallSwitch(installer::switches::kUninstall);
242    if (system_level)
243      product_state.AddUninstallSwitch(installer::switches::kSystemLevel);
244    if (multi_install) {
245      product_state.AddUninstallSwitch(installer::switches::kMultiInstall);
246      product_state.AddUninstallSwitch(installer::switches::kChrome);
247      if (with_chrome_frame_ready_mode) {
248        product_state.AddUninstallSwitch(installer::switches::kChromeFrame);
249        product_state.AddUninstallSwitch(
250            installer::switches::kChromeFrameReadyMode);
251      }
252    }
253
254    installation_state->SetProductState(system_level,
255                                        BrowserDistribution::CHROME_BROWSER,
256                                        product_state);
257  }
258
259  void AddChromeFrameToInstallationState(
260      bool system_level,
261      bool multi_install,
262      bool ready_mode,
263      MockInstallationState* installation_state) {
264    if (multi_install)
265      MaybeAddBinariesToInstallationState(system_level, installation_state);
266    MockProductState product_state;
267    product_state.set_version(new Version(*current_version_));
268    product_state.set_multi_install(multi_install);
269    BrowserDistribution* dist =
270        BrowserDistribution::GetSpecificDistribution(
271            multi_install ? BrowserDistribution::CHROME_BINARIES :
272                BrowserDistribution::CHROME_FRAME);
273    base::FilePath install_path =
274        installer::GetChromeInstallPath(system_level, dist);
275    product_state.SetUninstallProgram(
276      install_path.AppendASCII(current_version_->GetString())
277          .Append(installer::kInstallerDir)
278          .Append(installer::kSetupExe));
279    product_state.AddUninstallSwitch(installer::switches::kUninstall);
280    product_state.AddUninstallSwitch(installer::switches::kChromeFrame);
281    if (system_level)
282      product_state.AddUninstallSwitch(installer::switches::kSystemLevel);
283    if (multi_install) {
284      product_state.AddUninstallSwitch(installer::switches::kMultiInstall);
285      if (ready_mode) {
286        product_state.AddUninstallSwitch(
287            installer::switches::kChromeFrameReadyMode);
288      }
289    }
290
291    installation_state->SetProductState(system_level,
292                                        BrowserDistribution::CHROME_FRAME,
293                                        product_state);
294  }
295
296  MockInstallationState* BuildChromeInstallationState(bool system_level,
297                                                      bool multi_install) {
298    scoped_ptr<MockInstallationState> installation_state(
299        new MockInstallationState());
300    AddChromeToInstallationState(system_level, multi_install, false,
301                                 installation_state.get());
302    return installation_state.release();
303  }
304
305  static MockInstallerState* BuildBasicInstallerState(
306      bool system_install,
307      bool multi_install,
308      const InstallationState& machine_state,
309      InstallerState::Operation operation) {
310    scoped_ptr<MockInstallerState> installer_state(new MockInstallerState());
311
312    InstallerState::Level level = system_install ?
313        InstallerState::SYSTEM_LEVEL : InstallerState::USER_LEVEL;
314    installer_state->set_level(level);
315    installer_state->set_operation(operation);
316    // Hope this next one isn't checked for now.
317    installer_state->set_state_key(L"PROBABLY_INVALID_REG_PATH");
318    installer_state->set_state_type(BrowserDistribution::CHROME_BROWSER);
319    installer_state->set_package_type(multi_install ?
320                                          InstallerState::MULTI_PACKAGE :
321                                          InstallerState::SINGLE_PACKAGE);
322    return installer_state.release();
323  }
324
325  static void AddChromeBinariesToInstallerState(
326      const InstallationState& machine_state,
327      MockInstallerState* installer_state) {
328    if (!installer_state->is_multi_install()) {
329      NOTREACHED();
330      return;
331    }
332    if (installer_state->FindProduct(BrowserDistribution::CHROME_BINARIES))
333      return;
334
335    // Fresh install or upgrade?
336    const ProductState* chrome_binaries =
337        machine_state.GetProductState(installer_state->system_install(),
338                                      BrowserDistribution::CHROME_BINARIES);
339    if (chrome_binaries != NULL) {
340      installer_state->AddProductFromState(BrowserDistribution::CHROME_BINARIES,
341                                           *chrome_binaries);
342    } else {
343      BrowserDistribution* dist =
344          BrowserDistribution::GetSpecificDistribution(
345              BrowserDistribution::CHROME_BINARIES);
346      scoped_ptr<Product> product(new Product(dist));
347      product->SetOption(installer::kOptionMultiInstall, true);
348      installer_state->AddProduct(&product);
349    }
350  }
351
352  static void AddChromeToInstallerState(
353      const InstallationState& machine_state,
354      MockInstallerState* installer_state) {
355    // Fresh install or upgrade?
356    const ProductState* chrome =
357        machine_state.GetProductState(installer_state->system_install(),
358                                      BrowserDistribution::CHROME_BROWSER);
359    if (chrome != NULL &&
360        chrome->is_multi_install() == installer_state->is_multi_install()) {
361      installer_state->AddProductFromState(BrowserDistribution::CHROME_BROWSER,
362                                           *chrome);
363    } else {
364      BrowserDistribution* dist =
365          BrowserDistribution::GetSpecificDistribution(
366              BrowserDistribution::CHROME_BROWSER);
367      scoped_ptr<Product> product(new Product(dist));
368      if (installer_state->is_multi_install())
369        product->SetOption(installer::kOptionMultiInstall, true);
370      installer_state->AddProduct(&product);
371    }
372  }
373
374  static void AddChromeFrameToInstallerState(
375      const InstallationState& machine_state,
376      bool ready_mode,
377      MockInstallerState* installer_state) {
378    // Fresh install or upgrade?
379    const ProductState* cf =
380        machine_state.GetProductState(installer_state->system_install(),
381                                      BrowserDistribution::CHROME_FRAME);
382    if (cf != NULL) {
383      installer_state->AddProductFromState(BrowserDistribution::CHROME_FRAME,
384                                           *cf);
385    } else {
386      BrowserDistribution* dist =
387          BrowserDistribution::GetSpecificDistribution(
388              BrowserDistribution::CHROME_FRAME);
389      scoped_ptr<Product> product(new Product(dist));
390      if (installer_state->is_multi_install()) {
391        product->SetOption(installer::kOptionMultiInstall, true);
392        if (ready_mode)
393          product->SetOption(installer::kOptionReadyMode, true);
394      }
395      installer_state->AddProduct(&product);
396    }
397  }
398
399  static MockInstallerState* BuildChromeInstallerState(
400      bool system_install,
401      bool multi_install,
402      const InstallationState& machine_state,
403      InstallerState::Operation operation) {
404    scoped_ptr<MockInstallerState> installer_state(
405        BuildBasicInstallerState(system_install, multi_install, machine_state,
406                                 operation));
407    if (multi_install) {
408      // We don't want to include Chrome Binaries for uninstall if the machine
409      // has other products. For simplicity, we check Chrome Frame only.
410      bool machine_has_other_products =
411          machine_state.GetProductState(system_install,
412              BrowserDistribution::CHROME_FRAME) != NULL;
413      if (operation != InstallerState::UNINSTALL || !machine_has_other_products)
414        AddChromeBinariesToInstallerState(machine_state, installer_state.get());
415    }
416    AddChromeToInstallerState(machine_state, installer_state.get());
417    return installer_state.release();
418  }
419
420  static MockInstallerState* BuildChromeFrameInstallerState(
421      bool system_install,
422      bool multi_install,
423      bool ready_mode,
424      const InstallationState& machine_state,
425      InstallerState::Operation operation) {
426    // This method only works for installation/upgrade.
427    DCHECK(operation != InstallerState::UNINSTALL);
428    scoped_ptr<MockInstallerState> installer_state(
429        BuildBasicInstallerState(system_install, multi_install, machine_state,
430                                 operation));
431    if (multi_install)
432      AddChromeBinariesToInstallerState(machine_state, installer_state.get());
433    AddChromeFrameToInstallerState(machine_state, ready_mode,
434                                   installer_state.get());
435    return installer_state.release();
436  }
437
438 protected:
439  scoped_ptr<Version> current_version_;
440  scoped_ptr<Version> new_version_;
441  base::FilePath archive_path_;
442  base::FilePath installation_path_;
443  base::FilePath setup_path_;
444  base::FilePath src_path_;
445  base::FilePath temp_dir_;
446};
447
448// Tests
449//------------------------------------------------------------------------------
450
451TEST_F(InstallWorkerTest, TestInstallChromeSingleSystem) {
452  const bool system_level = true;
453  const bool multi_install = false;
454  MockWorkItemList work_item_list;
455
456  scoped_ptr<InstallationState> installation_state(
457      BuildChromeInstallationState(system_level, multi_install));
458
459  scoped_ptr<InstallerState> installer_state(
460      BuildChromeInstallerState(system_level, multi_install,
461                                *installation_state,
462                                InstallerState::SINGLE_INSTALL_OR_UPDATE));
463
464  // Set up some expectations.
465  // TODO(robertshield): Set up some real expectations.
466  EXPECT_CALL(work_item_list, AddCopyTreeWorkItem(_, _, _, _, _))
467      .Times(AtLeast(1));
468
469  AddInstallWorkItems(*installation_state.get(),
470                      *installer_state.get(),
471                      setup_path_,
472                      archive_path_,
473                      src_path_,
474                      temp_dir_,
475                      current_version_.get(),
476                      *new_version_.get(),
477                      &work_item_list);
478}
479
480namespace {
481
482const wchar_t elevation_key[] =
483    L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"
484    L"{E0A900DF-9611-4446-86BD-4B1D47E7DB2A}";
485const wchar_t old_elevation_key[] =
486    L"SOFTWARE\\Microsoft\\Internet Explorer\\Low Rights\\ElevationPolicy\\"
487    L"{6C288DD7-76FB-4721-B628-56FAC252E199}";
488
489}  // namespace
490
491// A test class for worker functions that manipulate the old IE low rights
492// policies.
493// Parameters:
494// bool : system_level_
495// bool : multi_install_
496class OldIELowRightsTests : public InstallWorkerTest,
497  public ::testing::WithParamInterface<std::tr1::tuple<bool, bool> > {
498 protected:
499  virtual void SetUp() OVERRIDE {
500    InstallWorkerTest::SetUp();
501
502    const ParamType& param = GetParam();
503    system_level_ = std::tr1::get<0>(param);
504    multi_install_ = std::tr1::get<1>(param);
505    root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
506
507    installation_state_.reset(new MockInstallationState());
508    AddChromeFrameToInstallationState(system_level_, multi_install_, false,
509                                      installation_state_.get());
510    installer_state_.reset(BuildBasicInstallerState(
511        system_level_, multi_install_, *installation_state_,
512        multi_install_ ? InstallerState::MULTI_UPDATE :
513            InstallerState::SINGLE_INSTALL_OR_UPDATE));
514    if (multi_install_)
515      AddChromeBinariesToInstallerState(*installation_state_,
516                                        installer_state_.get());
517    AddChromeFrameToInstallerState(*installation_state_, false,
518                                   installer_state_.get());
519  }
520
521  scoped_ptr<MockInstallationState> installation_state_;
522  scoped_ptr<MockInstallerState> installer_state_;
523  bool system_level_;
524  bool multi_install_;
525  HKEY root_key_;
526};
527
528TEST_P(OldIELowRightsTests, AddDeleteOldIELowRightsPolicyWorkItems) {
529  StrictMock<MockWorkItemList> work_item_list;
530
531  EXPECT_CALL(work_item_list,
532              AddDeleteRegKeyWorkItem(root_key_, StrEq(old_elevation_key)))
533      .Times(1);
534
535  AddDeleteOldIELowRightsPolicyWorkItems(*installer_state_.get(),
536                                         &work_item_list);
537}
538
539TEST_P(OldIELowRightsTests, AddCopyIELowRightsPolicyWorkItems) {
540  StrictMock<MockWorkItemList> work_item_list;
541
542  // The old elevation policy key should only be copied when there's no old
543  // value.
544  EXPECT_CALL(work_item_list,
545              AddCopyRegKeyWorkItem(root_key_, StrEq(elevation_key),
546                                    StrEq(old_elevation_key),
547                                    Eq(WorkItem::IF_NOT_PRESENT))).Times(1);
548
549  AddCopyIELowRightsPolicyWorkItems(*installer_state_.get(), &work_item_list);
550}
551
552INSTANTIATE_TEST_CASE_P(Variations, OldIELowRightsTests,
553                        Combine(Bool(), Bool()));
554
555TEST_F(InstallWorkerTest, GoogleUpdateWorkItemsTest) {
556  const bool system_level = true;
557  const bool multi_install = true;
558  MockWorkItemList work_item_list;
559
560  scoped_ptr<MockInstallationState> installation_state(
561      BuildChromeInstallationState(system_level, false));
562
563  MockProductState cf_state;
564  cf_state.set_version(new Version(*current_version_));
565  cf_state.set_multi_install(false);
566
567  installation_state->SetProductState(system_level,
568      BrowserDistribution::CHROME_FRAME, cf_state);
569
570  scoped_ptr<MockInstallerState> installer_state(
571      BuildChromeInstallerState(system_level, multi_install,
572                                *installation_state,
573                                InstallerState::MULTI_INSTALL));
574
575  // Expect the multi Client State key to be created.
576  BrowserDistribution* multi_dist =
577      BrowserDistribution::GetSpecificDistribution(
578          BrowserDistribution::CHROME_BINARIES);
579  std::wstring multi_app_guid(multi_dist->GetAppGuid());
580  std::wstring multi_client_state_suffix(L"ClientState\\" + multi_app_guid);
581  EXPECT_CALL(work_item_list,
582              AddCreateRegKeyWorkItem(_, HasSubstr(multi_client_state_suffix)))
583      .Times(testing::AnyNumber());
584
585  // Expect ClientStateMedium to be created for system-level installs.
586  EXPECT_CALL(work_item_list,
587              AddCreateRegKeyWorkItem(_, HasSubstr(L"ClientStateMedium\\" +
588                                                   multi_app_guid)))
589      .Times(system_level ? 1 : 0);
590
591  // Expect to see a set value for the "TEST" brand code in the multi Client
592  // State key.
593  EXPECT_CALL(work_item_list,
594              AddSetRegStringValueWorkItem(_,
595                                           HasSubstr(multi_client_state_suffix),
596                                           StrEq(google_update::kRegBrandField),
597                                           StrEq(L"TEST"),
598                                           _)).Times(1);
599
600  // There may also be some calls to set 'ap' values.
601  EXPECT_CALL(work_item_list,
602              AddSetRegStringValueWorkItem(_, _,
603                                           StrEq(google_update::kRegApField),
604                                           _, _)).Times(testing::AnyNumber());
605
606  // Expect "oeminstall" to be cleared.
607  EXPECT_CALL(work_item_list,
608              AddDeleteRegValueWorkItem(
609                  _,
610                  HasSubstr(multi_client_state_suffix),
611                  StrEq(google_update::kRegOemInstallField))).Times(1);
612
613  // Expect "eulaaccepted" to set.
614  EXPECT_CALL(work_item_list,
615              AddSetRegDwordValueWorkItem(
616                  _,
617                  HasSubstr(multi_client_state_suffix),
618                  StrEq(google_update::kRegEULAAceptedField),
619                  Eq(static_cast<DWORD>(1)),
620                  _)).Times(1);
621
622  AddGoogleUpdateWorkItems(*installation_state.get(),
623                           *installer_state.get(),
624                           &work_item_list);
625}
626
627// Test that usagestats values are migrated properly.
628TEST_F(InstallWorkerTest, AddUsageStatsWorkItems) {
629  const bool system_level = true;
630  const bool multi_install = true;
631  MockWorkItemList work_item_list;
632
633  scoped_ptr<MockInstallationState> installation_state(
634      BuildChromeInstallationState(system_level, multi_install));
635
636  MockProductState chrome_state;
637  chrome_state.set_version(new Version(*current_version_));
638  chrome_state.set_multi_install(false);
639  chrome_state.set_usagestats(1);
640
641  installation_state->SetProductState(system_level,
642      BrowserDistribution::CHROME_BROWSER, chrome_state);
643
644  scoped_ptr<MockInstallerState> installer_state(
645      BuildChromeInstallerState(system_level, multi_install,
646                                *installation_state,
647                                InstallerState::MULTI_INSTALL));
648
649  // Expect the multi Client State key to be created.
650  BrowserDistribution* multi_dist =
651      BrowserDistribution::GetSpecificDistribution(
652          BrowserDistribution::CHROME_BINARIES);
653  std::wstring multi_app_guid(multi_dist->GetAppGuid());
654  EXPECT_CALL(work_item_list,
655              AddCreateRegKeyWorkItem(_, HasSubstr(multi_app_guid))).Times(1);
656
657  // Expect to see a set value for the usagestats in the multi Client State key.
658  EXPECT_CALL(work_item_list,
659              AddSetRegDwordValueWorkItem(
660                  _,
661                  HasSubstr(multi_app_guid),
662                  StrEq(google_update::kRegUsageStatsField),
663                  Eq(static_cast<DWORD>(1)),
664                  Eq(true))).Times(1);
665
666  // Expect to see some values cleaned up from Chrome's keys.
667  BrowserDistribution* chrome_dist =
668      BrowserDistribution::GetSpecificDistribution(
669          BrowserDistribution::CHROME_BROWSER);
670  if (system_level) {
671    EXPECT_CALL(work_item_list,
672                AddDeleteRegValueWorkItem(
673                    _,
674                    StrEq(chrome_dist->GetStateMediumKey()),
675                    StrEq(google_update::kRegUsageStatsField))).Times(1);
676    EXPECT_CALL(work_item_list,
677                AddDeleteRegValueWorkItem(
678                    Eq(HKEY_CURRENT_USER),
679                    StrEq(chrome_dist->GetStateKey()),
680                    StrEq(google_update::kRegUsageStatsField))).Times(1);
681  }
682  EXPECT_CALL(work_item_list,
683              AddDeleteRegValueWorkItem(
684                  Eq(installer_state->root_key()),
685                  StrEq(chrome_dist->GetStateKey()),
686                  StrEq(google_update::kRegUsageStatsField))).Times(1);
687
688  AddUsageStatsWorkItems(*installation_state.get(),
689                         *installer_state.get(),
690                         &work_item_list);
691}
692
693// The Quick Enable tests only make sense for the Google Chrome build as it
694// interacts with registry values that are specific to Google Update.
695#if defined(GOOGLE_CHROME_BUILD)
696
697// Test scenarios under which the quick-enable-cf command should not exist after
698// the run.  We're permissive in that we allow the DeleteRegKeyWorkItem even if
699// it isn't strictly needed.
700class QuickEnableAbsentTest : public InstallWorkerTest {
701 public:
702  virtual void SetUp() {
703    InstallWorkerTest::SetUp();
704    root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
705    delete_reg_key_item_.reset(
706        WorkItem::CreateDeleteRegKeyWorkItem(root_key_, kRegKeyPath));
707    machine_state_.reset(new MockInstallationState());
708    EXPECT_CALL(work_item_list_,
709                AddDeleteRegKeyWorkItem(Eq(root_key_), StrCaseEq(kRegKeyPath)))
710        .Times(AtMost(1))
711        .WillRepeatedly(Return(delete_reg_key_item_.get()));
712  }
713  virtual void TearDown() {
714    machine_state_.reset();
715    delete_reg_key_item_.reset();
716    root_key_ = NULL;
717    InstallWorkerTest::TearDown();
718  }
719 protected:
720  static const bool system_level_ = false;
721  static const wchar_t kRegKeyPath[];
722  HKEY root_key_;
723  scoped_ptr<DeleteRegKeyWorkItem> delete_reg_key_item_;
724  scoped_ptr<MockInstallationState> machine_state_;
725  StrictMock<MockWorkItemList> work_item_list_;
726};
727
728const wchar_t QuickEnableAbsentTest::kRegKeyPath[] =
729    L"Software\\Google\\Update\\Clients\\"
730    L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}\\Commands\\quick-enable-cf";
731
732TEST_F(QuickEnableAbsentTest, CleanInstallSingleChrome) {
733  // Install single Chrome on a clean system.
734  scoped_ptr<MockInstallerState> installer_state(
735      BuildChromeInstallerState(system_level_, false, *machine_state_,
736                                InstallerState::SINGLE_INSTALL_OR_UPDATE));
737  AddQuickEnableChromeFrameWorkItems(*installer_state,
738                                     *machine_state_,
739                                     setup_path_,
740                                     *new_version_.get(),
741                                     &work_item_list_);
742}
743
744TEST_F(QuickEnableAbsentTest, CleanInstallSingleChromeFrame) {
745  // Install single Chrome Frame on a clean system.
746  scoped_ptr<MockInstallerState> installer_state(
747      BuildChromeFrameInstallerState(system_level_, false, false,
748                                     *machine_state_,
749                                     InstallerState::SINGLE_INSTALL_OR_UPDATE));
750  AddQuickEnableChromeFrameWorkItems(*installer_state,
751                                     *machine_state_,
752                                     setup_path_,
753                                     *new_version_.get(),
754                                     &work_item_list_);
755}
756
757TEST_F(QuickEnableAbsentTest, CleanInstallMultiChromeFrame) {
758  // Install multi Chrome Frame on a clean system.
759  scoped_ptr<MockInstallerState> installer_state(
760      BuildChromeFrameInstallerState(system_level_, true, false,
761                                     *machine_state_,
762                                     InstallerState::MULTI_INSTALL));
763  AddQuickEnableChromeFrameWorkItems(*installer_state,
764                                     *machine_state_,
765                                     setup_path_,
766                                     *new_version_.get(),
767                                     &work_item_list_);
768}
769
770TEST_F(QuickEnableAbsentTest, CleanInstallMultiChromeChromeFrame) {
771  // Install multi Chrome and Chrome Frame on a clean system.
772  scoped_ptr<MockInstallerState> installer_state(
773      BuildBasicInstallerState(system_level_, true, *machine_state_,
774                               InstallerState::MULTI_INSTALL));
775  AddChromeBinariesToInstallerState(*machine_state_, installer_state.get());
776  AddChromeToInstallerState(*machine_state_, installer_state.get());
777  AddChromeFrameToInstallerState(*machine_state_, false,
778                                 installer_state.get());
779  AddQuickEnableChromeFrameWorkItems(*installer_state,
780                                     *machine_state_,
781                                     setup_path_,
782                                     *new_version_.get(),
783                                     &work_item_list_);
784}
785
786TEST_F(QuickEnableAbsentTest, UninstallMultiChromeLeaveMultiChromeFrame) {
787  // Uninstall multi Chrome on a machine with multi Chrome Frame.
788  AddChromeToInstallationState(system_level_, true, false,
789                               machine_state_.get());
790  AddChromeFrameToInstallationState(system_level_, true, false,
791                                    machine_state_.get());
792  scoped_ptr<MockInstallerState> installer_state(
793      BuildBasicInstallerState(system_level_, true, *machine_state_,
794                               InstallerState::UNINSTALL));
795  AddChromeToInstallerState(*machine_state_, installer_state.get());
796  AddQuickEnableChromeFrameWorkItems(*installer_state,
797                                     *machine_state_,
798                                     setup_path_,
799                                     *new_version_.get(),
800                                     &work_item_list_);
801}
802
803TEST_F(QuickEnableAbsentTest, UninstallMultiChromeLeaveSingleChromeFrame) {
804  // Uninstall multi Chrome on a machine with single Chrome Frame.
805  AddChromeToInstallationState(system_level_, true, false,
806                               machine_state_.get());
807  AddChromeFrameToInstallationState(system_level_, false, false,
808                                    machine_state_.get());
809  scoped_ptr<MockInstallerState> installer_state(
810      BuildBasicInstallerState(system_level_, true, *machine_state_,
811                               InstallerState::UNINSTALL));
812  AddChromeToInstallerState(*machine_state_, installer_state.get());
813  AddChromeBinariesToInstallerState(*machine_state_, installer_state.get());
814  AddQuickEnableChromeFrameWorkItems(*installer_state,
815                                     *machine_state_,
816                                     setup_path_,
817                                     *new_version_.get(),
818                                     &work_item_list_);
819}
820
821TEST_F(QuickEnableAbsentTest, AcceptReadyMode) {
822  // Accept ready-mode.
823  AddChromeToInstallationState(system_level_, true, true,
824                               machine_state_.get());
825  AddChromeFrameToInstallationState(system_level_, true, true,
826                                    machine_state_.get());
827  scoped_ptr<MockInstallerState> installer_state(
828      BuildBasicInstallerState(system_level_, true, *machine_state_,
829                               InstallerState::UNINSTALL));
830  AddChromeToInstallerState(*machine_state_, installer_state.get());
831  AddChromeFrameToInstallerState(*machine_state_, false, installer_state.get());
832  AddChromeBinariesToInstallerState(*machine_state_, installer_state.get());
833  AddQuickEnableChromeFrameWorkItems(*installer_state,
834                                     *machine_state_,
835                                     setup_path_,
836                                     *new_version_.get(),
837                                     &work_item_list_);
838}
839
840// Test scenarios under which the quick-enable-cf command should exist after the
841// run.
842class QuickEnablePresentTest : public InstallWorkerTest {
843 public:
844  virtual void SetUp() {
845    InstallWorkerTest::SetUp();
846    root_key_ = system_level_ ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
847    create_reg_key_work_item_.reset(
848        WorkItem::CreateCreateRegKeyWorkItem(root_key_, kRegKeyPath));
849    set_reg_value_work_item_.reset(
850        WorkItem::CreateSetRegValueWorkItem(root_key_, kRegKeyPath, L"", L"",
851                                            false));
852    machine_state_.reset(new MockInstallationState());
853    EXPECT_CALL(work_item_list_,
854                AddCreateRegKeyWorkItem(Eq(root_key_), StrCaseEq(kRegKeyPath)))
855        .Times(1)
856        .WillOnce(Return(create_reg_key_work_item_.get()));
857    EXPECT_CALL(work_item_list_,
858                AddSetRegStringValueWorkItem(Eq(root_key_),
859                                             StrCaseEq(kRegKeyPath),
860                                             StrEq(L"CommandLine"), _,
861                                             Eq(true)))
862        .Times(1)
863        .WillOnce(Return(set_reg_value_work_item_.get()));
864    EXPECT_CALL(work_item_list_,
865                AddSetRegDwordValueWorkItem(Eq(root_key_),
866                                            StrCaseEq(kRegKeyPath), _,
867                                            Eq(static_cast<DWORD>(1)),
868                                            Eq(true)))
869        .Times(2)
870        .WillRepeatedly(Return(set_reg_value_work_item_.get()));
871  }
872  virtual void TearDown() {
873    machine_state_.reset();
874    set_reg_value_work_item_.reset();
875    create_reg_key_work_item_.reset();
876    root_key_ = NULL;
877    InstallWorkerTest::TearDown();
878  }
879 protected:
880  static const bool system_level_ = false;
881  static const wchar_t kRegKeyPath[];
882  HKEY root_key_;
883  scoped_ptr<CreateRegKeyWorkItem> create_reg_key_work_item_;
884  scoped_ptr<SetRegValueWorkItem> set_reg_value_work_item_;
885  scoped_ptr<MockInstallationState> machine_state_;
886  StrictMock<MockWorkItemList> work_item_list_;
887};
888
889const wchar_t QuickEnablePresentTest::kRegKeyPath[] =
890    L"Software\\Google\\Update\\Clients\\"
891    L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}\\Commands\\quick-enable-cf";
892
893TEST_F(QuickEnablePresentTest, CleanInstallMultiChrome) {
894  // Install multi Chrome on a clean system.
895  scoped_ptr<MockInstallerState> installer_state(
896      BuildChromeInstallerState(system_level_, true, *machine_state_,
897                                InstallerState::MULTI_INSTALL));
898  AddQuickEnableChromeFrameWorkItems(*installer_state,
899                                     *machine_state_,
900                                     setup_path_,
901                                     *new_version_.get(),
902                                     &work_item_list_);
903}
904
905TEST_F(QuickEnablePresentTest, CleanInstallMultiChromeReadyMode) {
906  // Install multi Chrome with Chrome Frame ready-mode on a clean system.
907  scoped_ptr<MockInstallerState> installer_state(
908      BuildBasicInstallerState(system_level_, true, *machine_state_,
909                               InstallerState::MULTI_INSTALL));
910  AddChromeBinariesToInstallerState(*machine_state_, installer_state.get());
911  AddChromeToInstallerState(*machine_state_, installer_state.get());
912  AddChromeFrameToInstallerState(*machine_state_, true,
913                                 installer_state.get());
914  AddQuickEnableChromeFrameWorkItems(*installer_state,
915                                     *machine_state_,
916                                     setup_path_,
917                                     *new_version_.get(),
918                                     &work_item_list_);
919}
920
921TEST_F(QuickEnablePresentTest, UninstallSingleChromeFrame) {
922  // Uninstall single Chrome Frame on a machine with multi Chrome.
923  AddChromeToInstallationState(system_level_, true, false,
924                               machine_state_.get());
925  AddChromeFrameToInstallationState(system_level_, false, false,
926                                    machine_state_.get());
927  scoped_ptr<MockInstallerState> installer_state(
928      BuildBasicInstallerState(system_level_, false, *machine_state_,
929                               InstallerState::UNINSTALL));
930  AddChromeFrameToInstallerState(*machine_state_, false, installer_state.get());
931  AddQuickEnableChromeFrameWorkItems(*installer_state,
932                                     *machine_state_,
933                                     setup_path_,
934                                     *new_version_.get(),
935                                     &work_item_list_);
936}
937
938TEST_F(QuickEnablePresentTest, UninstallMultiChromeFrame) {
939  // Uninstall multi Chrome Frame on a machine with multi Chrome.
940  AddChromeToInstallationState(system_level_, true, false,
941                               machine_state_.get());
942  AddChromeFrameToInstallationState(system_level_, true, false,
943                                    machine_state_.get());
944  scoped_ptr<MockInstallerState> installer_state(
945      BuildBasicInstallerState(system_level_, true, *machine_state_,
946                               InstallerState::UNINSTALL));
947  AddChromeFrameToInstallerState(*machine_state_, false, installer_state.get());
948  AddQuickEnableChromeFrameWorkItems(*installer_state,
949                                     *machine_state_,
950                                     setup_path_,
951                                     *new_version_.get(),
952                                     &work_item_list_);
953}
954
955TEST_F(InstallWorkerTest, WillProductBePresentAfterSetup) {
956  BrowserDistribution::Type prod_type_list[] = {
957    BrowserDistribution::CHROME_BROWSER,
958    BrowserDistribution::CHROME_FRAME,
959    // Excluding BrowserDistribution::CHROME_BINARIES, since it is installed
960    // along with other products.
961  };
962  enum {  // Index into prod_type_list[].
963    TYPE_BROWSER = 0,
964    TYPE_CF,
965    NUM_TYPE  // This must appear last.
966  };
967  DCHECK(arraysize(prod_type_list) == NUM_TYPE);
968  InstallerState::Operation op_list[] = {
969    InstallerState::UNINSTALL,
970    InstallerState::SINGLE_INSTALL_OR_UPDATE
971  };
972
973  const bool system_level = false;
974  const bool multi_install = true;
975
976  // Loop over machine states: {No product, Chrome, CF, Chrome + CF}.
977  for (int i_mach = 0; i_mach < (1 << NUM_TYPE); ++i_mach) {
978    // i_mach is the machine state before operation, as bit mask.
979    scoped_ptr<MockInstallationState> machine_state(
980        new MockInstallationState());
981    if ((i_mach & (1 << TYPE_BROWSER)) != 0) {  // Add Chrome.
982      AddChromeToInstallationState(system_level, multi_install, false,
983                                   machine_state.get());
984    }
985    if ((i_mach & (1 << TYPE_CF)) != 0) {  // Add Chrome Frame.
986      AddChromeFrameToInstallationState(system_level, multi_install, false,
987                                        machine_state.get());
988    }
989
990    // Loop over operations: {uninstall, install/update}.
991    for (int i_op = 0; i_op < arraysize(op_list); ++i_op) {
992
993      // Loop over product types to operate on: {TYPE_BROWSER, TYPE_CF}.
994      for (int i_type_op = 0; i_type_op < NUM_TYPE; ++i_type_op) {
995        scoped_ptr<InstallerState> installer_state;
996        if (i_type_op == TYPE_BROWSER) {
997          installer_state.reset(BuildChromeInstallerState(
998              system_level, multi_install, *machine_state, op_list[i_op]));
999        } else if (i_type_op == TYPE_CF) {
1000          // Skip the CF uninstall case due to limitations in
1001          // BuildChromeFrameInstallerState().
1002          if (op_list[i_op] == InstallerState::UNINSTALL)
1003            continue;
1004
1005          installer_state.reset(BuildChromeFrameInstallerState(
1006              system_level, multi_install, false, *machine_state,
1007              op_list[i_op]));
1008        } else {
1009          NOTREACHED();
1010        }
1011
1012        // Calculate the machine state after operation, as bit mask.
1013        // If uninstall, remove product with bitwise AND; else add with OR.
1014        int mach_after = (op_list[i_op] == InstallerState::UNINSTALL) ?
1015            i_mach & ~(1 << i_type_op) : i_mach | (1 << i_type_op);
1016
1017        // Verify predicted presence of Chrome Binaries.
1018        bool bin_res = installer::WillProductBePresentAfterSetup(
1019            *installer_state,
1020            *machine_state,
1021            BrowserDistribution::CHROME_BINARIES);
1022        // Binaries are expected to be present iff any product is installed.
1023        bool bin_expect = mach_after != 0;
1024        EXPECT_EQ(bin_expect, bin_res);
1025
1026        // Loop over product types to check: {TYPE_BROWSER, TYPE_CF}.
1027        for (int i_type_check = 0; i_type_check < NUM_TYPE; ++i_type_check) {
1028          // Verify predicted presence of product.
1029          bool prod_res = installer::WillProductBePresentAfterSetup(
1030              *installer_state,
1031              *machine_state,
1032              prod_type_list[i_type_check]);
1033          bool prod_expect = (mach_after & (1 << i_type_check)) != 0;
1034          EXPECT_EQ(prod_expect, prod_res);
1035        }
1036      }
1037    }
1038  }
1039}
1040
1041#endif  // defined(GOOGLE_CHROME_BUILD)
1042