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) 1042