Chromium Code Reviews| Index: chrome/browser/extensions/extension_service_sync_unittest.cc |
| diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc |
| index 1b810fa91a142b85b2d532312fa24bc3fa3cfcb9..23a2bc14374c945febc6c60bd3099d0545e53ef2 100644 |
| --- a/chrome/browser/extensions/extension_service_sync_unittest.cc |
| +++ b/chrome/browser/extensions/extension_service_sync_unittest.cc |
| @@ -19,6 +19,7 @@ |
| #include "base/test/mock_entropy_provider.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" |
| +#include "chrome/browser/extensions/chrome_test_extension_loader.h" |
| #include "chrome/browser/extensions/component_loader.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_service_test_with_install.h" |
| @@ -337,6 +338,163 @@ TEST_F(ExtensionServiceSyncTest, DisableExtensionFromSync) { |
| ASSERT_FALSE(service()->IsExtensionEnabled(good0)); |
| } |
| +// Test that sync can enable and disable installed extensions. |
| +TEST_F(ExtensionServiceSyncTest, ReenableDisabledExtensionFromSync) { |
| + InitializeEmptyExtensionService(); |
| + |
| + // Enable sync. |
| + browser_sync::ProfileSyncService* sync_service = |
| + ProfileSyncServiceFactory::GetForProfile(profile()); |
| + sync_service->SetFirstSetupComplete(); |
| + |
| + service()->Init(); |
| + |
| + // Load up a simple extension. |
| + extensions::ChromeTestExtensionLoader extension_loader(profile()); |
| + extension_loader.set_pack_extension(true); |
| + scoped_refptr<const Extension> extension = extension_loader.LoadExtension( |
| + data_dir().AppendASCII("simple_with_file")); |
| + ASSERT_TRUE(extension); |
| + const std::string kExtensionId = extension->id(); |
| + ASSERT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| + |
| + syncer::FakeSyncChangeProcessor* processor_raw = nullptr; |
| + { |
| + auto processor = base::MakeUnique<syncer::FakeSyncChangeProcessor>(); |
| + processor_raw = processor.get(); |
| + extension_sync_service()->MergeDataAndStartSyncing( |
| + syncer::EXTENSIONS, syncer::SyncDataList(), std::move(processor), |
| + base::MakeUnique<syncer::SyncErrorFactoryMock>()); |
| + } |
| + processor_raw->changes().clear(); |
| + |
| + // Sync says to disable the extension. |
| + ExtensionSyncData disable_extension( |
|
lazyboy
2017/06/12 20:59:55
This pattern:
ExtensionSyncData ...
SyncChangeList
Devlin
2017/06/13 16:14:45
Good idea! Done.
|
| + *extension, false, Extension::DISABLE_USER_ACTION, false, false, |
| + ExtensionSyncData::BOOLEAN_UNSET, false); |
| + 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. :)
|
| + 1, disable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); |
| + extension_sync_service()->ProcessSyncChanges(FROM_HERE, enable_list); |
| + |
| + // The extension should be disabled. |
| + EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); |
| + EXPECT_EQ(Extension::DISABLE_USER_ACTION, |
| + ExtensionPrefs::Get(profile())->GetDisableReasons(kExtensionId)); |
| + EXPECT_TRUE(processor_raw->changes().empty()); |
| + |
| + // Enable the extension. Sync should push the new state. |
| + service()->EnableExtension(kExtensionId); |
| + { |
| + ASSERT_EQ(1u, processor_raw->changes().size()); |
| + const SyncChange& change = processor_raw->changes()[0]; |
| + EXPECT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); |
| + std::unique_ptr<ExtensionSyncData> data = |
| + ExtensionSyncData::CreateFromSyncData(change.sync_data()); |
| + EXPECT_EQ(kExtensionId, data->id()); |
| + EXPECT_EQ(0, data->disable_reasons()); |
| + EXPECT_TRUE(data->enabled()); |
| + } |
| + |
| + // Disable the extension again. Sync should push the new state. |
| + processor_raw->changes().clear(); |
| + service()->DisableExtension(kExtensionId, Extension::DISABLE_USER_ACTION); |
| + EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); |
| + { |
| + ASSERT_EQ(1u, processor_raw->changes().size()); |
| + const SyncChange& change = processor_raw->changes()[0]; |
| + EXPECT_EQ(SyncChange::ACTION_UPDATE, change.change_type()); |
| + std::unique_ptr<ExtensionSyncData> data = |
| + ExtensionSyncData::CreateFromSyncData(change.sync_data()); |
| + EXPECT_EQ(kExtensionId, data->id()); |
| + EXPECT_EQ(Extension::DISABLE_USER_ACTION, data->disable_reasons()); |
| + EXPECT_FALSE(data->enabled()); |
| + } |
| + processor_raw->changes().clear(); |
| + |
| + // Enable the extension via sync. |
| + 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)
|
| + ExtensionSyncData::BOOLEAN_UNSET, false); |
| + SyncChangeList disable_list( |
| + 1, enable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); |
| + extension_sync_service()->ProcessSyncChanges(FROM_HERE, disable_list); |
| + |
| + // The extension should be enabled. |
| + EXPECT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| + EXPECT_TRUE(processor_raw->changes().empty()); |
| +} |
| + |
| +// Tests that default-installed extensions won't be affected by incoming sync |
| +// data. (It's feasible to have a sync entry for an extension that could be |
| +// default installed, since one installation may be default-installed while |
| +// another may not be). |
| +TEST_F(ExtensionServiceSyncTest, |
| + DefaultInstalledExtensionsAreNotReenabledOrDisabledBySync) { |
| + InitializeEmptyExtensionService(); |
| + |
| + // Enable sync. |
| + browser_sync::ProfileSyncService* sync_service = |
| + ProfileSyncServiceFactory::GetForProfile(profile()); |
| + sync_service->SetFirstSetupComplete(); |
| + |
| + service()->Init(); |
| + |
| + // Load up an extension that's considered default installed. |
| + extensions::ChromeTestExtensionLoader extension_loader(profile()); |
| + extension_loader.set_pack_extension(true); |
| + extension_loader.add_creation_flag(Extension::WAS_INSTALLED_BY_DEFAULT); |
| + scoped_refptr<const Extension> extension = extension_loader.LoadExtension( |
| + data_dir().AppendASCII("simple_with_file")); |
| + ASSERT_TRUE(extension); |
| + |
| + // The extension shouldn't sync. |
| + EXPECT_FALSE(extensions::util::ShouldSync(extension.get(), profile())); |
| + const std::string kExtensionId = extension->id(); |
| + ASSERT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| + |
| + syncer::FakeSyncChangeProcessor* processor_raw = nullptr; |
| + { |
| + auto processor = base::MakeUnique<syncer::FakeSyncChangeProcessor>(); |
| + processor_raw = processor.get(); |
| + extension_sync_service()->MergeDataAndStartSyncing( |
| + syncer::EXTENSIONS, syncer::SyncDataList(), std::move(processor), |
| + base::MakeUnique<syncer::SyncErrorFactoryMock>()); |
| + } |
| + processor_raw->changes().clear(); |
| + |
| + // Sync state says the extension is disabled (e.g. on another machine). |
| + ExtensionSyncData disable_extension( |
| + *extension, false, Extension::DISABLE_USER_ACTION, false, false, |
| + ExtensionSyncData::BOOLEAN_UNSET, false); |
| + SyncChangeList disable_list( |
| + 1, disable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); |
| + extension_sync_service()->ProcessSyncChanges(FROM_HERE, disable_list); |
| + |
| + // The extension should still be enabled, since it's default-installed. |
| + EXPECT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| + EXPECT_TRUE(processor_raw->changes().empty()); |
| + |
| + // Now disable the extension locally. Sync should *not* push new state. |
| + service()->DisableExtension(kExtensionId, Extension::DISABLE_USER_ACTION); |
| + EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); |
| + EXPECT_TRUE(processor_raw->changes().empty()); |
| + |
| + // Sync state says the extension is enabled. |
| + ExtensionSyncData enable_extension(*extension, true, 0, false, false, |
| + ExtensionSyncData::BOOLEAN_UNSET, false); |
| + SyncChangeList enable_list( |
| + 1, enable_extension.GetSyncChange(SyncChange::ACTION_UPDATE)); |
| + extension_sync_service()->ProcessSyncChanges(FROM_HERE, enable_list); |
| + |
| + // As above, the extension should not have been affected by sync. |
| + EXPECT_TRUE(registry()->disabled_extensions().GetByID(kExtensionId)); |
| + EXPECT_TRUE(processor_raw->changes().empty()); |
| + |
| + // And re-enabling the extension should not push new state to sync. |
| + service()->EnableExtension(kExtensionId); |
| + EXPECT_TRUE(registry()->enabled_extensions().GetByID(kExtensionId)); |
| + EXPECT_TRUE(processor_raw->changes().empty()); |
| +} |
| + |
| TEST_F(ExtensionServiceSyncTest, IgnoreSyncChangesWhenLocalStateIsMoreRecent) { |
| // Start the extension service with three extensions already installed. |
| base::FilePath source_install_dir = |
| @@ -1359,6 +1517,13 @@ TEST_F(ExtensionServiceSyncTest, ProcessSyncDataEnableDisable) { |
| } |
| TEST_F(ExtensionServiceSyncTest, ProcessSyncDataDeferredEnable) { |
| + // The permissions_increase test extension has a different update URL. |
| + // In order to make it syncable, we have to pretend it syncs from the |
| + // webstore. |
| + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( |
| + switches::kAppsGalleryUpdateURL, |
| + "http://localhost/autoupdate/updates.xml"); |
| + |
| InitializeEmptyExtensionService(); |
| extension_sync_service()->MergeDataAndStartSyncing( |
| syncer::EXTENSIONS, syncer::SyncDataList(), |