Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <stddef.h> | 5 #include <stddef.h> |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <utility> | 10 #include <utility> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/files/file_util.h" | 14 #include "base/files/file_util.h" |
| 15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/memory/weak_ptr.h" | 17 #include "base/memory/weak_ptr.h" |
| 18 #include "base/metrics/field_trial.h" | 18 #include "base/metrics/field_trial.h" |
| 19 #include "base/test/mock_entropy_provider.h" | 19 #include "base/test/mock_entropy_provider.h" |
| 20 #include "base/test/scoped_feature_list.h" | 20 #include "base/test/scoped_feature_list.h" |
| 21 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" | 21 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" |
| 22 #include "chrome/browser/extensions/chrome_test_extension_loader.h" | |
| 22 #include "chrome/browser/extensions/component_loader.h" | 23 #include "chrome/browser/extensions/component_loader.h" |
| 23 #include "chrome/browser/extensions/extension_service.h" | 24 #include "chrome/browser/extensions/extension_service.h" |
| 24 #include "chrome/browser/extensions/extension_service_test_with_install.h" | 25 #include "chrome/browser/extensions/extension_service_test_with_install.h" |
| 25 #include "chrome/browser/extensions/extension_sync_data.h" | 26 #include "chrome/browser/extensions/extension_sync_data.h" |
| 26 #include "chrome/browser/extensions/extension_sync_service.h" | 27 #include "chrome/browser/extensions/extension_sync_service.h" |
| 27 #include "chrome/browser/extensions/extension_util.h" | 28 #include "chrome/browser/extensions/extension_util.h" |
| 28 #include "chrome/browser/extensions/scripting_permissions_modifier.h" | 29 #include "chrome/browser/extensions/scripting_permissions_modifier.h" |
| 29 #include "chrome/browser/extensions/updater/extension_updater.h" | 30 #include "chrome/browser/extensions/updater/extension_updater.h" |
| 30 #include "chrome/browser/sync/profile_sync_service_factory.h" | 31 #include "chrome/browser/sync/profile_sync_service_factory.h" |
| 31 #include "chrome/common/chrome_constants.h" | 32 #include "chrome/common/chrome_constants.h" |
| (...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 330 Extension::DISABLE_USER_ACTION, false, | 331 Extension::DISABLE_USER_ACTION, false, |
| 331 false, ExtensionSyncData::BOOLEAN_UNSET, | 332 false, ExtensionSyncData::BOOLEAN_UNSET, |
| 332 false); | 333 false); |
| 333 SyncChangeList list( | 334 SyncChangeList list( |
| 334 1, disable_good_crx.GetSyncChange(SyncChange::ACTION_UPDATE)); | 335 1, disable_good_crx.GetSyncChange(SyncChange::ACTION_UPDATE)); |
| 335 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list); | 336 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list); |
| 336 | 337 |
| 337 ASSERT_FALSE(service()->IsExtensionEnabled(good0)); | 338 ASSERT_FALSE(service()->IsExtensionEnabled(good0)); |
| 338 } | 339 } |
| 339 | 340 |
| 341 // Test that sync can enable and disable installed extensions. | |
| 342 TEST_F(ExtensionServiceSyncTest, ReenableDisabledExtensionFromSync) { | |
| 343 InitializeEmptyExtensionService(); | |
| 344 | |
| 345 // Enable sync. | |
| 346 browser_sync::ProfileSyncService* sync_service = | |
| 347 ProfileSyncServiceFactory::GetForProfile(profile()); | |
| 348 sync_service->SetFirstSetupComplete(); | |
| 349 | |
| 350 service()->Init(); | |
| 351 | |
| 352 // Load up a simple extension. | |
| 353 extensions::ChromeTestExtensionLoader extension_loader(profile()); | |
| 354 extension_loader.set_pack_extension(true); | |
| 355 scoped_refptr<const Extension> extension = extension_loader.LoadExtension( | |
| 356 data_dir().AppendASCII("simple_with_file")); | |
| 357 ASSERT_TRUE(extension); | |
| 358 const std::string kExtensionId = extension->id(); | |
| 359 ASSERT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); | |
| 360 | |
| 361 syncer::FakeSyncChangeProcessor* processor_raw = nullptr; | |
| 362 { | |
| 363 auto processor = base::MakeUnique<syncer::FakeSyncChangeProcessor>(); | |
| 364 processor_raw = processor.get(); | |
| 365 extension_sync_service()->MergeDataAndStartSyncing( | |
| 366 syncer::EXTENSIONS, syncer::SyncDataList(), std::move(processor), | |
| 367 base::MakeUnique<syncer::SyncErrorFactoryMock>()); | |
| 368 } | |
| 369 processor_raw->changes().clear(); | |
| 370 | |
| 371 // Sync says to disable the extension. | |
| 372 ExtensionSyncData disable_extension( | |
|
lazyboy
2017/06/12 20:59:55
This pattern:
ExtensionSyncData ...
SyncChangeList
Devlin
2017/06/13 16:14:45
Good idea! Done.
| |
| 373 *extension, false, Extension::DISABLE_USER_ACTION, false, false, | |
| 374 ExtensionSyncData::BOOLEAN_UNSET, false); | |
| 375 SyncChangeList enable_list( | |
|
lazyboy
2017/06/12 20:59:55
nit: should this be called disable_list (and the o
Devlin
2017/06/13 16:14:45
Yes, but moot with your suggestion above. :)
| |
| 376 1, disable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); | |
| 377 extension_sync_service()->ProcessSyncChanges(FROM_HERE, enable_list); | |
| 378 | |
| 379 // The extension should be disabled. | |
| 380 EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); | |
| 381 EXPECT_EQ(Extension::DISABLE_USER_ACTION, | |
| 382 ExtensionPrefs::Get(profile())->GetDisableReasons(kExtensionId)); | |
| 383 EXPECT_TRUE(processor_raw->changes().empty()); | |
| 384 | |
| 385 // Enable the extension. Sync should push the new state. | |
| 386 service()->EnableExtension(kExtensionId); | |
| 387 { | |
| 388 ASSERT_EQ(1u, processor_raw->changes().size()); | |
| 389 const SyncChange& change = processor_raw->changes()[0]; | |
| 390 EXPECT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | |
| 391 std::unique_ptr<ExtensionSyncData> data = | |
| 392 ExtensionSyncData::CreateFromSyncData(change.sync_data()); | |
| 393 EXPECT_EQ(kExtensionId, data->id()); | |
| 394 EXPECT_EQ(0, data->disable_reasons()); | |
| 395 EXPECT_TRUE(data->enabled()); | |
| 396 } | |
| 397 | |
| 398 // Disable the extension again. Sync should push the new state. | |
| 399 processor_raw->changes().clear(); | |
| 400 service()->DisableExtension(kExtensionId, Extension::DISABLE_USER_ACTION); | |
| 401 EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); | |
| 402 { | |
| 403 ASSERT_EQ(1u, processor_raw->changes().size()); | |
| 404 const SyncChange& change = processor_raw->changes()[0]; | |
| 405 EXPECT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); | |
| 406 std::unique_ptr<ExtensionSyncData> data = | |
| 407 ExtensionSyncData::CreateFromSyncData(change.sync_data()); | |
| 408 EXPECT_EQ(kExtensionId, data->id()); | |
| 409 EXPECT_EQ(Extension::DISABLE_USER_ACTION, data->disable_reasons()); | |
| 410 EXPECT_FALSE(data->enabled()); | |
| 411 } | |
| 412 processor_raw->changes().clear(); | |
| 413 | |
| 414 // Enable the extension via sync. | |
| 415 ExtensionSyncData enable_extension(*extension, true, 0, false, false, | |
|
lazyboy
2017/06/12 20:59:55
0->DISABLE_NONE?
Devlin
2017/06/13 16:14:45
Done (in the EnableExtensionFromSync method)
| |
| 416 ExtensionSyncData::BOOLEAN_UNSET, false); | |
| 417 SyncChangeList disable_list( | |
| 418 1, enable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); | |
| 419 extension_sync_service()->ProcessSyncChanges(FROM_HERE, disable_list); | |
| 420 | |
| 421 // The extension should be enabled. | |
| 422 EXPECT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); | |
| 423 EXPECT_TRUE(processor_raw->changes().empty()); | |
| 424 } | |
| 425 | |
| 426 // Tests that default-installed extensions won't be affected by incoming sync | |
| 427 // data. (It's feasible to have a sync entry for an extension that could be | |
| 428 // default installed, since one installation may be default-installed while | |
| 429 // another may not be). | |
| 430 TEST_F(ExtensionServiceSyncTest, | |
| 431 DefaultInstalledExtensionsAreNotReenabledOrDisabledBySync) { | |
| 432 InitializeEmptyExtensionService(); | |
| 433 | |
| 434 // Enable sync. | |
| 435 browser_sync::ProfileSyncService* sync_service = | |
| 436 ProfileSyncServiceFactory::GetForProfile(profile()); | |
| 437 sync_service->SetFirstSetupComplete(); | |
| 438 | |
| 439 service()->Init(); | |
| 440 | |
| 441 // Load up an extension that's considered default installed. | |
| 442 extensions::ChromeTestExtensionLoader extension_loader(profile()); | |
| 443 extension_loader.set_pack_extension(true); | |
| 444 extension_loader.add_creation_flag(Extension::WAS_INSTALLED_BY_DEFAULT); | |
| 445 scoped_refptr<const Extension> extension = extension_loader.LoadExtension( | |
| 446 data_dir().AppendASCII("simple_with_file")); | |
| 447 ASSERT_TRUE(extension); | |
| 448 | |
| 449 // The extension shouldn't sync. | |
| 450 EXPECT_FALSE(extensions::util::ShouldSync(extension.get(), profile())); | |
| 451 const std::string kExtensionId = extension->id(); | |
| 452 ASSERT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); | |
| 453 | |
| 454 syncer::FakeSyncChangeProcessor* processor_raw = nullptr; | |
| 455 { | |
| 456 auto processor = base::MakeUnique<syncer::FakeSyncChangeProcessor>(); | |
| 457 processor_raw = processor.get(); | |
| 458 extension_sync_service()->MergeDataAndStartSyncing( | |
| 459 syncer::EXTENSIONS, syncer::SyncDataList(), std::move(processor), | |
| 460 base::MakeUnique<syncer::SyncErrorFactoryMock>()); | |
| 461 } | |
| 462 processor_raw->changes().clear(); | |
| 463 | |
| 464 // Sync state says the extension is disabled (e.g. on another machine). | |
| 465 ExtensionSyncData disable_extension( | |
| 466 *extension, false, Extension::DISABLE_USER_ACTION, false, false, | |
| 467 ExtensionSyncData::BOOLEAN_UNSET, false); | |
| 468 SyncChangeList disable_list( | |
| 469 1, disable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); | |
| 470 extension_sync_service()->ProcessSyncChanges(FROM_HERE, disable_list); | |
| 471 | |
| 472 // The extension should still be enabled, since it's default-installed. | |
| 473 EXPECT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); | |
| 474 EXPECT_TRUE(processor_raw->changes().empty()); | |
| 475 | |
| 476 // Now disable the extension locally. Sync should *not* push new state. | |
| 477 service()->DisableExtension(kExtensionId, Extension::DISABLE_USER_ACTION); | |
| 478 EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); | |
| 479 EXPECT_TRUE(processor_raw->changes().empty()); | |
| 480 | |
| 481 // Sync state says the extension is enabled. | |
| 482 ExtensionSyncData enable_extension(*extension, true, 0, false, false, | |
| 483 ExtensionSyncData::BOOLEAN_UNSET, false); | |
| 484 SyncChangeList enable_list( | |
| 485 1, enable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); | |
| 486 extension_sync_service()->ProcessSyncChanges(FROM_HERE, enable_list); | |
| 487 | |
| 488 // As above, the extension should not have been affected by sync. | |
| 489 EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); | |
| 490 EXPECT_TRUE(processor_raw->changes().empty()); | |
| 491 | |
| 492 // And re-enabling the extension should not push new state to sync. | |
| 493 service()->EnableExtension(kExtensionId); | |
| 494 EXPECT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); | |
| 495 EXPECT_TRUE(processor_raw->changes().empty()); | |
| 496 } | |
| 497 | |
| 340 TEST_F(ExtensionServiceSyncTest, IgnoreSyncChangesWhenLocalStateIsMoreRecent) { | 498 TEST_F(ExtensionServiceSyncTest, IgnoreSyncChangesWhenLocalStateIsMoreRecent) { |
| 341 // Start the extension service with three extensions already installed. | 499 // Start the extension service with three extensions already installed. |
| 342 base::FilePath source_install_dir = | 500 base::FilePath source_install_dir = |
| 343 data_dir().AppendASCII("good").AppendASCII("Extensions"); | 501 data_dir().AppendASCII("good").AppendASCII("Extensions"); |
| 344 base::FilePath pref_path = | 502 base::FilePath pref_path = |
| 345 source_install_dir.DirName().Append(chrome::kPreferencesFilename); | 503 source_install_dir.DirName().Append(chrome::kPreferencesFilename); |
| 346 | 504 |
| 347 InitializeInstalledExtensionService(pref_path, source_install_dir); | 505 InitializeInstalledExtensionService(pref_path, source_install_dir); |
| 348 | 506 |
| 349 // The user has enabled sync. | 507 // The user has enabled sync. |
| (...skipping 1002 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1352 EXPECT_EQ(expect_enabled, service()->IsExtensionEnabled(id)); | 1510 EXPECT_EQ(expect_enabled, service()->IsExtensionEnabled(id)); |
| 1353 EXPECT_EQ(test_case.expect_disable_reasons, prefs->GetDisableReasons(id)); | 1511 EXPECT_EQ(test_case.expect_disable_reasons, prefs->GetDisableReasons(id)); |
| 1354 | 1512 |
| 1355 // Remove the extension again, so we can install it again for the next case. | 1513 // Remove the extension again, so we can install it again for the next case. |
| 1356 UninstallExtension(id, false, expect_enabled ? Extension::ENABLED | 1514 UninstallExtension(id, false, expect_enabled ? Extension::ENABLED |
| 1357 : Extension::DISABLED); | 1515 : Extension::DISABLED); |
| 1358 } | 1516 } |
| 1359 } | 1517 } |
| 1360 | 1518 |
| 1361 TEST_F(ExtensionServiceSyncTest, ProcessSyncDataDeferredEnable) { | 1519 TEST_F(ExtensionServiceSyncTest, ProcessSyncDataDeferredEnable) { |
| 1520 // The permissions_increase test extension has a different update URL. | |
| 1521 // In order to make it syncable, we have to pretend it syncs from the | |
| 1522 // webstore. | |
| 1523 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( | |
| 1524 switches::kAppsGalleryUpdateURL, | |
| 1525 "http://localhost/autoupdate/updates.xml"); | |
| 1526 | |
| 1362 InitializeEmptyExtensionService(); | 1527 InitializeEmptyExtensionService(); |
| 1363 extension_sync_service()->MergeDataAndStartSyncing( | 1528 extension_sync_service()->MergeDataAndStartSyncing( |
| 1364 syncer::EXTENSIONS, syncer::SyncDataList(), | 1529 syncer::EXTENSIONS, syncer::SyncDataList(), |
| 1365 base::MakeUnique<syncer::FakeSyncChangeProcessor>(), | 1530 base::MakeUnique<syncer::FakeSyncChangeProcessor>(), |
| 1366 base::MakeUnique<syncer::SyncErrorFactoryMock>()); | 1531 base::MakeUnique<syncer::SyncErrorFactoryMock>()); |
| 1367 | 1532 |
| 1368 base::FilePath base_path = data_dir().AppendASCII("permissions_increase"); | 1533 base::FilePath base_path = data_dir().AppendASCII("permissions_increase"); |
| 1369 base::FilePath pem_path = base_path.AppendASCII("permissions.pem"); | 1534 base::FilePath pem_path = base_path.AppendASCII("permissions.pem"); |
| 1370 | 1535 |
| 1371 base::FilePath path = base_path.AppendASCII("v1"); | 1536 base::FilePath path = base_path.AppendASCII("v1"); |
| (...skipping 1094 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2466 break; | 2631 break; |
| 2467 } | 2632 } |
| 2468 } | 2633 } |
| 2469 } | 2634 } |
| 2470 EXPECT_TRUE(found_delete); | 2635 EXPECT_TRUE(found_delete); |
| 2471 | 2636 |
| 2472 // Make sure there is one extension, and there are no more apps. | 2637 // Make sure there is one extension, and there are no more apps. |
| 2473 EXPECT_EQ(1u, extensions_processor.data().size()); | 2638 EXPECT_EQ(1u, extensions_processor.data().size()); |
| 2474 EXPECT_TRUE(apps_processor.data().empty()); | 2639 EXPECT_TRUE(apps_processor.data().empty()); |
| 2475 } | 2640 } |
| OLD | NEW |