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