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