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