Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(158)

Side by Side Diff: chrome/browser/extensions/extension_service_sync_unittest.cc

Issue 1778923003: Fix extensions sync in cases where items change type (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 25 matching lines...) Expand all
36 #include "extensions/browser/extension_registry.h" 36 #include "extensions/browser/extension_registry.h"
37 #include "extensions/browser/extension_system.h" 37 #include "extensions/browser/extension_system.h"
38 #include "extensions/browser/management_policy.h" 38 #include "extensions/browser/management_policy.h"
39 #include "extensions/browser/test_management_policy.h" 39 #include "extensions/browser/test_management_policy.h"
40 #include "extensions/common/constants.h" 40 #include "extensions/common/constants.h"
41 #include "extensions/common/extension_builder.h" 41 #include "extensions/common/extension_builder.h"
42 #include "extensions/common/manifest_url_handlers.h" 42 #include "extensions/common/manifest_url_handlers.h"
43 #include "extensions/common/permissions/permission_set.h" 43 #include "extensions/common/permissions/permission_set.h"
44 #include "extensions/common/value_builder.h" 44 #include "extensions/common/value_builder.h"
45 #include "sync/api/fake_sync_change_processor.h" 45 #include "sync/api/fake_sync_change_processor.h"
46 #include "sync/api/sync_change_processor_wrapper_for_test.h"
46 #include "sync/api/sync_data.h" 47 #include "sync/api/sync_data.h"
47 #include "sync/api/sync_error_factory_mock.h" 48 #include "sync/api/sync_error_factory_mock.h"
48 #include "testing/gtest/include/gtest/gtest.h" 49 #include "testing/gtest/include/gtest/gtest.h"
49 50
50 #if defined(ENABLE_SUPERVISED_USERS) 51 #if defined(ENABLE_SUPERVISED_USERS)
51 #include "chrome/browser/supervised_user/permission_request_creator.h" 52 #include "chrome/browser/supervised_user/permission_request_creator.h"
52 #include "chrome/browser/supervised_user/supervised_user_constants.h" 53 #include "chrome/browser/supervised_user/supervised_user_constants.h"
53 #include "chrome/browser/supervised_user/supervised_user_service.h" 54 #include "chrome/browser/supervised_user/supervised_user_service.h"
54 #include "chrome/browser/supervised_user/supervised_user_service_factory.h" 55 #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
55 #endif 56 #endif
(...skipping 17 matching lines...) Expand all
73 const char theme2_crx[] = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf"; 74 const char theme2_crx[] = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf";
74 75
75 SyncChangeList MakeSyncChangeList(const std::string& id, 76 SyncChangeList MakeSyncChangeList(const std::string& id,
76 const sync_pb::EntitySpecifics& specifics, 77 const sync_pb::EntitySpecifics& specifics,
77 SyncChange::SyncChangeType change_type) { 78 SyncChange::SyncChangeType change_type) {
78 syncer::SyncData sync_data = 79 syncer::SyncData sync_data =
79 syncer::SyncData::CreateLocalData(id, "Name", specifics); 80 syncer::SyncData::CreateLocalData(id, "Name", specifics);
80 return SyncChangeList(1, SyncChange(FROM_HERE, change_type, sync_data)); 81 return SyncChangeList(1, SyncChange(FROM_HERE, change_type, sync_data));
81 } 82 }
82 83
84 // This is a FakeSyncChangeProcessor specialization that maintains a store of
85 // SyncData items in the superclass' data_ member variable, treating it like a
86 // map keyed by the extension id from the SyncData. Each instance of this class
87 // should only be used for one model type (which should be either extensions or
88 // apps) to match how the real sync system handles things.
89 class StatefulChangeProcessor : public syncer::FakeSyncChangeProcessor {
90 public:
91 explicit StatefulChangeProcessor(syncer::ModelType expected_type)
92 : expected_type_(expected_type) {
93 EXPECT_TRUE(expected_type == syncer::ModelType::EXTENSIONS ||
94 expected_type == syncer::ModelType::APPS);
95 }
96
97 ~StatefulChangeProcessor() override {}
98
99 // We let our parent class, FakeSyncChangeProcessor, handle saving the
100 // changes for us, but in addition we "apply" these changes by treating
101 // the FakeSyncChangeProcessor's SyncDataList as a map keyed by extension
102 // id.
103 syncer::SyncError ProcessSyncChanges(
104 const tracked_objects::Location& from_here,
105 const syncer::SyncChangeList& change_list) override {
106 syncer::FakeSyncChangeProcessor::ProcessSyncChanges(from_here, change_list);
107 for (const auto& change : change_list) {
108 syncer::SyncData sync_data = change.sync_data();
Marc Treib 2016/03/10 10:36:34 const syncer::SyncData& ?
asargent_no_longer_on_chrome 2016/03/11 23:40:59 The sync_data() method actually returns a SyncData
109 EXPECT_EQ(expected_type_, sync_data.GetDataType());
110
111 scoped_ptr<ExtensionSyncData> modified =
112 ExtensionSyncData::CreateFromSyncData(sync_data);
113
114 // Start by removing any existing entry for this extension id.
115 syncer::SyncDataList& data_list = data();
116 for (auto iter = data_list.begin(); iter != data_list.end(); ++iter) {
117 scoped_ptr<ExtensionSyncData> existing =
118 ExtensionSyncData::CreateFromSyncData(*iter);
119 if (existing->id() == modified->id()) {
120 data_list.erase(iter);
121 break;
122 }
123 }
124
125 // Now add in the new data for this id, if appropriate.
126 if (change.change_type() == SyncChange::ACTION_ADD ||
127 change.change_type() == SyncChange::ACTION_UPDATE) {
128 data_list.push_back(sync_data);
129 } else if (change.change_type() != SyncChange::ACTION_DELETE) {
130 ADD_FAILURE() << "Unexpected change type " << change.change_type();
131 }
132 }
133 return syncer::SyncError();
134 }
135
136 // We override this to help catch the error of trying to use a single
137 // StatefulChangeProcessor to process changes for both extensions and apps
138 // sync data.
139 syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override {
140 EXPECT_EQ(expected_type_, type);
141 return FakeSyncChangeProcessor::GetAllSyncData(type);
142 }
143
144 // This is a helper to vend a wrapped version of this object suitable for
145 // passing in to MergeDataAndStartSyncing, which takes a
146 // scoped_ptr<SyncChangeProcessor>, since in tests we typically don't want to
147 // give up ownership of a local change processor.
148 scoped_ptr<syncer::SyncChangeProcessor> GetWrapped() {
149 return make_scoped_ptr(
150 new syncer::SyncChangeProcessorWrapperForTest(this));
151 }
152
153 protected:
154 // The expected ModelType of changes that this processor will see.
155 syncer::ModelType expected_type_;
156 };
Devlin 2016/03/10 18:08:29 nit: DISALLOW_COPY_AND_ASSIGN
asargent_no_longer_on_chrome 2016/03/11 23:40:59 Done.
157
83 } // namespace 158 } // namespace
84 159
85 class ExtensionServiceSyncTest 160 class ExtensionServiceSyncTest
86 : public extensions::ExtensionServiceTestWithInstall { 161 : public extensions::ExtensionServiceTestWithInstall {
87 public: 162 public:
88 void MockSyncStartFlare(bool* was_called, 163 void MockSyncStartFlare(bool* was_called,
89 syncer::ModelType* model_type_passed_in, 164 syncer::ModelType* model_type_passed_in,
90 syncer::ModelType model_type) { 165 syncer::ModelType model_type) {
91 *was_called = true; 166 *was_called = true;
92 *model_type_passed_in = model_type; 167 *model_type_passed_in = model_type;
93 } 168 }
94 169
170 // Helper to call MergeDataAndStartSyncing with no server data and dummy
171 // change processor / error factory.
172 void StartSyncing(syncer::ModelType type) {
173 ASSERT_TRUE(type == syncer::EXTENSIONS || type == syncer::APPS);
174 extension_sync_service()->MergeDataAndStartSyncing(
175 type, syncer::SyncDataList(),
Devlin 2016/03/10 18:08:29 nit: indentation
asargent_no_longer_on_chrome 2016/03/11 23:40:59 Done. (Not sure why git cl upload didn't warn me,
176 make_scoped_ptr(new syncer::FakeSyncChangeProcessor()),
177 make_scoped_ptr(new syncer::SyncErrorFactoryMock()));
178 }
179
95 protected: 180 protected:
96 // Paths to some of the fake extensions. 181 // Paths to some of the fake extensions.
97 base::FilePath good0_path() { 182 base::FilePath good0_path() {
98 return data_dir() 183 return data_dir()
99 .AppendASCII("good") 184 .AppendASCII("good")
100 .AppendASCII("Extensions") 185 .AppendASCII("Extensions")
101 .AppendASCII(good0) 186 .AppendASCII(good0)
102 .AppendASCII("1.0.0.0"); 187 .AppendASCII("1.0.0.0");
103 } 188 }
104 189
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after
601 InitializeEmptyExtensionService(); 686 InitializeEmptyExtensionService();
602 InstallCRXWithLocation( 687 InstallCRXWithLocation(
603 data_dir().AppendASCII("good.crx"), Manifest::EXTERNAL_PREF, INSTALL_NEW); 688 data_dir().AppendASCII("good.crx"), Manifest::EXTERNAL_PREF, INSTALL_NEW);
604 const Extension* extension = service()->GetInstalledExtension(good_crx); 689 const Extension* extension = service()->GetInstalledExtension(good_crx);
605 ASSERT_TRUE(extension); 690 ASSERT_TRUE(extension);
606 691
607 extension_sync_service()->MergeDataAndStartSyncing( 692 extension_sync_service()->MergeDataAndStartSyncing(
608 syncer::EXTENSIONS, syncer::SyncDataList(), 693 syncer::EXTENSIONS, syncer::SyncDataList(),
609 make_scoped_ptr(new syncer::FakeSyncChangeProcessor()), 694 make_scoped_ptr(new syncer::FakeSyncChangeProcessor()),
610 make_scoped_ptr(new syncer::SyncErrorFactoryMock())); 695 make_scoped_ptr(new syncer::SyncErrorFactoryMock()));
696 StartSyncing(syncer::APPS);
611 697
612 UninstallExtension(good_crx, false); 698 UninstallExtension(good_crx, false);
613 EXPECT_TRUE( 699 EXPECT_TRUE(
614 ExtensionPrefs::Get(profile())->IsExternalExtensionUninstalled(good_crx)); 700 ExtensionPrefs::Get(profile())->IsExternalExtensionUninstalled(good_crx));
615 701
616 sync_pb::EntitySpecifics specifics; 702 sync_pb::EntitySpecifics specifics;
617 sync_pb::AppSpecifics* app_specifics = specifics.mutable_app(); 703 sync_pb::AppSpecifics* app_specifics = specifics.mutable_app();
618 sync_pb::ExtensionSpecifics* extension_specifics = 704 sync_pb::ExtensionSpecifics* extension_specifics =
619 app_specifics->mutable_extension(); 705 app_specifics->mutable_extension();
620 extension_specifics->set_id(good_crx); 706 extension_specifics->set_id(good_crx);
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list); 871 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
786 EXPECT_FALSE(service()->GetExtensionById(good_crx, true)); 872 EXPECT_FALSE(service()->GetExtensionById(good_crx, true));
787 873
788 // Should again do nothing. 874 // Should again do nothing.
789 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list); 875 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
790 EXPECT_FALSE(service()->GetExtensionById(good_crx, true)); 876 EXPECT_FALSE(service()->GetExtensionById(good_crx, true));
791 } 877 }
792 878
793 TEST_F(ExtensionServiceSyncTest, ProcessSyncDataWrongType) { 879 TEST_F(ExtensionServiceSyncTest, ProcessSyncDataWrongType) {
794 InitializeEmptyExtensionService(); 880 InitializeEmptyExtensionService();
881 StartSyncing(syncer::EXTENSIONS);
882 StartSyncing(syncer::APPS);
795 883
796 // Install the extension. 884 // Install the extension.
797 base::FilePath extension_path = data_dir().AppendASCII("good.crx"); 885 base::FilePath extension_path = data_dir().AppendASCII("good.crx");
798 InstallCRX(extension_path, INSTALL_NEW); 886 InstallCRX(extension_path, INSTALL_NEW);
799 EXPECT_TRUE(service()->GetExtensionById(good_crx, true)); 887 EXPECT_TRUE(service()->GetExtensionById(good_crx, true));
800 888
801 sync_pb::EntitySpecifics specifics; 889 sync_pb::EntitySpecifics specifics;
802 sync_pb::AppSpecifics* app_specifics = specifics.mutable_app(); 890 sync_pb::AppSpecifics* app_specifics = specifics.mutable_app();
803 sync_pb::ExtensionSpecifics* extension_specifics = 891 sync_pb::ExtensionSpecifics* extension_specifics =
804 app_specifics->mutable_extension(); 892 app_specifics->mutable_extension();
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after
1479 params["legacy_supervised_user"] = enabled ? "true" : "false"; 1567 params["legacy_supervised_user"] = enabled ? "true" : "false";
1480 params["child_account"] = enabled ? "true" : "false"; 1568 params["child_account"] = enabled ? "true" : "false";
1481 variations::AssociateVariationParams( 1569 variations::AssociateVariationParams(
1482 "SupervisedUserExtensionPermissionIncrease", "group", params); 1570 "SupervisedUserExtensionPermissionIncrease", "group", params);
1483 } 1571 }
1484 1572
1485 void InitServices(bool profile_is_supervised) { 1573 void InitServices(bool profile_is_supervised) {
1486 ExtensionServiceInitParams params = CreateDefaultInitParams(); 1574 ExtensionServiceInitParams params = CreateDefaultInitParams();
1487 params.profile_is_supervised = profile_is_supervised; 1575 params.profile_is_supervised = profile_is_supervised;
1488 InitializeExtensionService(params); 1576 InitializeExtensionService(params);
1577 StartSyncing(syncer::EXTENSIONS);
1489 1578
1490 supervised_user_service()->SetDelegate(this); 1579 supervised_user_service()->SetDelegate(this);
1491 supervised_user_service()->Init(); 1580 supervised_user_service()->Init();
1492 } 1581 }
1493 1582
1494 std::string InstallPermissionsTestExtension() { 1583 std::string InstallPermissionsTestExtension() {
1495 const std::string version("1"); 1584 const std::string version("1");
1496 1585
1497 const Extension* extension = 1586 const Extension* extension =
1498 PackAndInstallCRX(dir_path(version), pem_path(), INSTALL_NEW, 1587 PackAndInstallCRX(dir_path(version), pem_path(), INSTALL_NEW,
(...skipping 327 matching lines...) Expand 10 before | Expand all | Expand 10 after
1826 // blocked by policy, so it should still be there. 1915 // blocked by policy, so it should still be there.
1827 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_ids[0])); 1916 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_ids[0]));
1828 1917
1829 // But installed_by_custodian should result in bypassing the policy check. 1918 // But installed_by_custodian should result in bypassing the policy check.
1830 EXPECT_FALSE( 1919 EXPECT_FALSE(
1831 registry()->GenerateInstalledExtensionsSet()->Contains(extension_ids[1])); 1920 registry()->GenerateInstalledExtensionsSet()->Contains(extension_ids[1]));
1832 } 1921 }
1833 1922
1834 TEST_F(ExtensionServiceSyncTest, SyncExtensionHasAllhostsWithheld) { 1923 TEST_F(ExtensionServiceSyncTest, SyncExtensionHasAllhostsWithheld) {
1835 InitializeEmptyExtensionService(); 1924 InitializeEmptyExtensionService();
1925 StartSyncing(syncer::EXTENSIONS);
1836 1926
1837 // Create an extension that needs all-hosts. 1927 // Create an extension that needs all-hosts.
1838 const std::string kName("extension"); 1928 const std::string kName("extension");
1839 scoped_refptr<const Extension> extension = 1929 scoped_refptr<const Extension> extension =
1840 extensions::ExtensionBuilder() 1930 extensions::ExtensionBuilder()
1841 .SetLocation(Manifest::INTERNAL) 1931 .SetLocation(Manifest::INTERNAL)
1842 .SetManifest( 1932 .SetManifest(
1843 extensions::DictionaryBuilder() 1933 extensions::DictionaryBuilder()
1844 .Set("name", kName) 1934 .Set("name", kName)
1845 .Set("description", "foo") 1935 .Set("description", "foo")
(...skipping 26 matching lines...) Expand all
1872 1962
1873 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list); 1963 extension_sync_service()->ProcessSyncChanges(FROM_HERE, list);
1874 1964
1875 EXPECT_TRUE(registry()->enabled_extensions().GetByID(id)); 1965 EXPECT_TRUE(registry()->enabled_extensions().GetByID(id));
1876 EXPECT_FALSE(extensions::util::AllowedScriptingOnAllUrls(id, profile())); 1966 EXPECT_FALSE(extensions::util::AllowedScriptingOnAllUrls(id, profile()));
1877 EXPECT_TRUE(extensions::util::HasSetAllowedScriptingOnAllUrls(id, profile())); 1967 EXPECT_TRUE(extensions::util::HasSetAllowedScriptingOnAllUrls(id, profile()));
1878 EXPECT_FALSE(extensions::util::AllowedScriptingOnAllUrls(id, profile())); 1968 EXPECT_FALSE(extensions::util::AllowedScriptingOnAllUrls(id, profile()));
1879 } 1969 }
1880 1970
1881 #endif // defined(ENABLE_SUPERVISED_USERS) 1971 #endif // defined(ENABLE_SUPERVISED_USERS)
1972
1973 // Tests sync behavior in the case of an item that starts out as an app and
1974 // gets updated to become an extension.
1975 TEST_F(ExtensionServiceSyncTest, AppToExtension) {
1976 InitializeEmptyExtensionService();
1977 service()->Init();
1978 ASSERT_TRUE(service()->is_ready());
1979
1980 // Install v1, which is an app.
1981 const Extension* v1 =
1982 InstallCRX(data_dir().AppendASCII("sync_datatypes").AppendASCII("v1.crx"),
1983 INSTALL_NEW);
1984 EXPECT_TRUE(v1->is_app());
1985 EXPECT_FALSE(v1->is_extension());
1986 std::string id = v1->id();
1987
1988 StatefulChangeProcessor extensions_processor(syncer::ModelType::EXTENSIONS);
1989 StatefulChangeProcessor apps_processor(syncer::ModelType::APPS);
1990 extension_sync_service()->MergeDataAndStartSyncing(
1991 syncer::EXTENSIONS, syncer::SyncDataList(),
1992 extensions_processor.GetWrapped(),
1993 make_scoped_ptr(new syncer::SyncErrorFactoryMock()));
1994 extension_sync_service()->MergeDataAndStartSyncing(
1995 syncer::APPS, syncer::SyncDataList(),
1996 apps_processor.GetWrapped(),
1997 make_scoped_ptr(new syncer::SyncErrorFactoryMock()));
1998
1999 // Check the app/extension change processors to be sure the right data was
2000 // added.
2001 EXPECT_TRUE(extensions_processor.changes().empty());
2002 EXPECT_TRUE(extensions_processor.data().empty());
2003 EXPECT_EQ(1u, apps_processor.data().size());
2004 ASSERT_EQ(1u, apps_processor.changes().size());
2005 const SyncChange& app_change = apps_processor.changes()[0];
2006 EXPECT_EQ(SyncChange::ACTION_ADD, app_change.change_type());
2007 scoped_ptr<ExtensionSyncData> app_data =
2008 ExtensionSyncData::CreateFromSyncData(app_change.sync_data());
2009 EXPECT_TRUE(app_data->is_app());
2010 EXPECT_EQ(id, app_data->id());
2011 EXPECT_EQ(*v1->version(), app_data->version());
2012
2013 // Update the app to v2, which is an extension.
2014 const Extension* v2 =
2015 InstallCRX(data_dir().AppendASCII("sync_datatypes").AppendASCII("v2.crx"),
Devlin 2016/03/10 18:08:29 Is v3.crx used?
asargent_no_longer_on_chrome 2016/03/11 23:40:59 Good catch - early on I had been thinking of addin
2016 INSTALL_UPDATED);
2017 EXPECT_FALSE(v2->is_app());
2018 EXPECT_TRUE(v2->is_extension());
2019 EXPECT_EQ(id, v2->id());
2020
2021 // Make sure we saw an extension item added.
2022 ASSERT_EQ(1u, extensions_processor.changes().size());
2023 const SyncChange& extension_change = extensions_processor.changes()[0];
2024 EXPECT_EQ(SyncChange::ACTION_ADD, extension_change.change_type());
2025 scoped_ptr<ExtensionSyncData> extension_data =
2026 ExtensionSyncData::CreateFromSyncData(extension_change.sync_data());
2027 EXPECT_FALSE(extension_data->is_app());
2028 EXPECT_EQ(id, extension_data->id());
2029 EXPECT_EQ(*v2->version(), extension_data->version());
2030
2031 // Get the current data from the change processors to use as the input to
2032 // the following call to MergeDataAndStartSyncing. This simulates what should
2033 // happen with sync.
2034 syncer::SyncDataList extensions_data =
2035 extensions_processor.GetAllSyncData(syncer::EXTENSIONS);
2036 syncer::SyncDataList apps_data =
2037 apps_processor.GetAllSyncData(syncer::APPS);
2038
2039 // Stop syncing, then start again.
2040 extension_sync_service()->StopSyncing(syncer::EXTENSIONS);
2041 extension_sync_service()->StopSyncing(syncer::APPS);
2042 extension_sync_service()->MergeDataAndStartSyncing(
2043 syncer::EXTENSIONS, extensions_data,
2044 extensions_processor.GetWrapped(),
2045 make_scoped_ptr(new syncer::SyncErrorFactoryMock()));
2046 extension_sync_service()->MergeDataAndStartSyncing(
2047 syncer::APPS, apps_data,
2048 apps_processor.GetWrapped(),
2049 make_scoped_ptr(new syncer::SyncErrorFactoryMock()));
2050
2051 // Make sure we saw an app item deleted.
Marc Treib 2016/03/10 10:36:34 Hm, it's a bit unfortunate that we have to wait fo
2052 bool found_delete = false;
2053 for (const auto& change : apps_processor.changes()) {
2054 if (change.change_type() == SyncChange::ACTION_DELETE) {
2055 scoped_ptr<ExtensionSyncData> data =
2056 ExtensionSyncData::CreateFromSyncChange(change);
2057 if (data->id() == id) {
2058 found_delete = true;
2059 break;
2060 }
2061 }
2062 }
2063 EXPECT_TRUE(found_delete);
2064
2065 // Make sure there is one extension, and there are no more apps.
2066 EXPECT_EQ(1u, extensions_processor.data().size());
2067 EXPECT_TRUE(apps_processor.data().empty());
2068 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698