Move Webstore URL concepts to //extensions and out
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / sync_extension_helper.cc
bloba04167147f705119e2d9c51fe79d45c1cbbea9dc
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.
5 #include "chrome/browser/sync/test/integration/sync_extension_helper.h"
7 #include "base/files/file_path.h"
8 #include "base/files/file_util.h"
9 #include "base/logging.h"
10 #include "base/values.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/extension_util.h"
13 #include "chrome/browser/extensions/pending_extension_info.h"
14 #include "chrome/browser/extensions/pending_extension_manager.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
17 #include "chrome/browser/sync/test/integration/sync_test.h"
18 #include "components/crx_file/id_util.h"
19 #include "extensions/browser/extension_registry.h"
20 #include "extensions/browser/extension_system.h"
21 #include "extensions/browser/install_flag.h"
22 #include "extensions/browser/uninstall_reason.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_set.h"
25 #include "extensions/common/manifest_constants.h"
26 #include "sync/api/string_ordinal.h"
27 #include "testing/gtest/include/gtest/gtest.h"
29 using extensions::Extension;
30 using extensions::ExtensionRegistry;
31 using extensions::Manifest;
33 SyncExtensionHelper::ExtensionState::ExtensionState()
34 : enabled_state(ENABLED), incognito_enabled(false) {}
36 SyncExtensionHelper::ExtensionState::~ExtensionState() {}
38 bool SyncExtensionHelper::ExtensionState::Equals(
39 const SyncExtensionHelper::ExtensionState &other) const {
40 return ((enabled_state == other.enabled_state) &&
41 (incognito_enabled == other.incognito_enabled));
44 // static
45 SyncExtensionHelper* SyncExtensionHelper::GetInstance() {
46 SyncExtensionHelper* instance = Singleton<SyncExtensionHelper>::get();
47 instance->SetupIfNecessary(sync_datatype_helper::test());
48 return instance;
51 SyncExtensionHelper::SyncExtensionHelper() : setup_completed_(false) {}
53 SyncExtensionHelper::~SyncExtensionHelper() {}
55 void SyncExtensionHelper::SetupIfNecessary(SyncTest* test) {
56 if (setup_completed_)
57 return;
59 for (int i = 0; i < test->num_clients(); ++i) {
60 SetupProfile(test->GetProfile(i));
62 SetupProfile(test->verifier());
64 setup_completed_ = true;
67 std::string SyncExtensionHelper::InstallExtension(
68 Profile* profile, const std::string& name, Manifest::Type type) {
69 scoped_refptr<Extension> extension = GetExtension(profile, name, type);
70 if (!extension.get()) {
71 NOTREACHED() << "Could not install extension " << name;
72 return std::string();
74 extensions::ExtensionSystem::Get(profile)
75 ->extension_service()
76 ->OnExtensionInstalled(extension.get(),
77 syncer::StringOrdinal(),
78 extensions::kInstallFlagInstallImmediately);
79 return extension->id();
82 void SyncExtensionHelper::UninstallExtension(
83 Profile* profile, const std::string& name) {
84 ExtensionService::UninstallExtensionHelper(
85 extensions::ExtensionSystem::Get(profile)->extension_service(),
86 crx_file::id_util::GenerateId(name),
87 extensions::UNINSTALL_REASON_SYNC);
90 std::vector<std::string> SyncExtensionHelper::GetInstalledExtensionNames(
91 Profile* profile) const {
92 std::vector<std::string> names;
94 scoped_ptr<const extensions::ExtensionSet> extensions(
95 extensions::ExtensionRegistry::Get(profile)
96 ->GenerateInstalledExtensionsSet());
97 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
98 it != extensions->end(); ++it) {
99 names.push_back((*it)->name());
102 return names;
105 void SyncExtensionHelper::EnableExtension(Profile* profile,
106 const std::string& name) {
107 extensions::ExtensionSystem::Get(profile)
108 ->extension_service()
109 ->EnableExtension(crx_file::id_util::GenerateId(name));
112 void SyncExtensionHelper::DisableExtension(Profile* profile,
113 const std::string& name) {
114 extensions::ExtensionSystem::Get(profile)
115 ->extension_service()
116 ->DisableExtension(crx_file::id_util::GenerateId(name),
117 Extension::DISABLE_USER_ACTION);
120 bool SyncExtensionHelper::IsExtensionEnabled(
121 Profile* profile, const std::string& name) const {
122 return extensions::ExtensionSystem::Get(profile)
123 ->extension_service()
124 ->IsExtensionEnabled(crx_file::id_util::GenerateId(name));
127 void SyncExtensionHelper::IncognitoEnableExtension(
128 Profile* profile, const std::string& name) {
129 extensions::util::SetIsIncognitoEnabled(
130 crx_file::id_util::GenerateId(name), profile, true);
133 void SyncExtensionHelper::IncognitoDisableExtension(
134 Profile* profile, const std::string& name) {
135 extensions::util::SetIsIncognitoEnabled(
136 crx_file::id_util::GenerateId(name), profile, false);
139 bool SyncExtensionHelper::IsIncognitoEnabled(
140 Profile* profile, const std::string& name) const {
141 return extensions::util::IsIncognitoEnabled(
142 crx_file::id_util::GenerateId(name), profile);
146 bool SyncExtensionHelper::IsExtensionPendingInstallForSync(
147 Profile* profile, const std::string& id) const {
148 const extensions::PendingExtensionManager* pending_extension_manager =
149 extensions::ExtensionSystem::Get(profile)
150 ->extension_service()
151 ->pending_extension_manager();
152 const extensions::PendingExtensionInfo* info =
153 pending_extension_manager->GetById(id);
154 if (!info)
155 return false;
156 return info->is_from_sync();
159 void SyncExtensionHelper::InstallExtensionsPendingForSync(Profile* profile) {
160 // TODO(akalin): Mock out the servers that the extensions auto-update
161 // mechanism talk to so as to more closely match what actually happens.
162 // Background networking will need to be re-enabled for extensions tests.
164 // We make a copy here since InstallExtension() removes the
165 // extension from the extensions service's copy.
166 const extensions::PendingExtensionManager* pending_extension_manager =
167 extensions::ExtensionSystem::Get(profile)
168 ->extension_service()
169 ->pending_extension_manager();
171 std::list<std::string> pending_crx_ids;
172 pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_crx_ids);
174 std::list<std::string>::const_iterator iter;
175 const extensions::PendingExtensionInfo* info = NULL;
176 for (iter = pending_crx_ids.begin(); iter != pending_crx_ids.end(); ++iter) {
177 ASSERT_TRUE((info = pending_extension_manager->GetById(*iter)));
178 if (!info->is_from_sync())
179 continue;
181 StringMap::const_iterator iter2 = id_to_name_.find(*iter);
182 if (iter2 == id_to_name_.end()) {
183 ADD_FAILURE() << "Could not get name for id " << *iter
184 << " (profile = " << profile->GetDebugName() << ")";
185 continue;
187 TypeMap::const_iterator iter3 = id_to_type_.find(*iter);
188 if (iter3 == id_to_type_.end()) {
189 ADD_FAILURE() << "Could not get type for id " << *iter
190 << " (profile = " << profile->GetDebugName() << ")";
192 InstallExtension(profile, iter2->second, iter3->second);
196 SyncExtensionHelper::ExtensionStateMap
197 SyncExtensionHelper::GetExtensionStates(Profile* profile) {
198 const std::string& profile_debug_name = profile->GetDebugName();
200 ExtensionStateMap extension_state_map;
202 scoped_ptr<const extensions::ExtensionSet> extensions(
203 extensions::ExtensionRegistry::Get(profile)
204 ->GenerateInstalledExtensionsSet());
206 ExtensionService* extension_service =
207 extensions::ExtensionSystem::Get(profile)->extension_service();
208 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
209 it != extensions->end(); ++it) {
210 const std::string& id = (*it)->id();
211 extension_state_map[id].enabled_state =
212 extension_service->IsExtensionEnabled(id) ?
213 ExtensionState::ENABLED :
214 ExtensionState::DISABLED;
215 extension_state_map[id].incognito_enabled =
216 extensions::util::IsIncognitoEnabled(id, profile);
218 DVLOG(2) << "Extension " << (*it)->id() << " in profile "
219 << profile_debug_name << " is "
220 << (extension_service->IsExtensionEnabled(id) ?
221 "enabled" : "disabled");
224 const extensions::PendingExtensionManager* pending_extension_manager =
225 extension_service->pending_extension_manager();
227 std::list<std::string> pending_crx_ids;
228 pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_crx_ids);
230 std::list<std::string>::const_iterator id;
231 for (id = pending_crx_ids.begin(); id != pending_crx_ids.end(); ++id) {
232 extension_state_map[*id].enabled_state = ExtensionState::PENDING;
233 extension_state_map[*id].incognito_enabled =
234 extensions::util::IsIncognitoEnabled(*id, profile);
235 DVLOG(2) << "Extension " << *id << " in profile "
236 << profile_debug_name << " is pending";
239 return extension_state_map;
242 bool SyncExtensionHelper::ExtensionStatesMatch(
243 Profile* profile1, Profile* profile2) {
244 const ExtensionStateMap& state_map1 = GetExtensionStates(profile1);
245 const ExtensionStateMap& state_map2 = GetExtensionStates(profile2);
246 if (state_map1.size() != state_map2.size()) {
247 DVLOG(1) << "Number of extensions for profile " << profile1->GetDebugName()
248 << " does not match profile " << profile2->GetDebugName();
249 return false;
252 ExtensionStateMap::const_iterator it1 = state_map1.begin();
253 ExtensionStateMap::const_iterator it2 = state_map2.begin();
254 while (it1 != state_map1.end()) {
255 if (it1->first != it2->first) {
256 DVLOG(1) << "Extensions for profile " << profile1->GetDebugName()
257 << " do not match profile " << profile2->GetDebugName();
258 return false;
259 } else if (!it1->second.Equals(it2->second)) {
260 DVLOG(1) << "Extension states for profile " << profile1->GetDebugName()
261 << " do not match profile " << profile2->GetDebugName();
262 return false;
264 ++it1;
265 ++it2;
267 return true;
270 void SyncExtensionHelper::SetupProfile(Profile* profile) {
271 extensions::ExtensionSystem::Get(profile)->InitForRegularProfile(true);
272 profile_extensions_.insert(make_pair(profile, ExtensionNameMap()));
275 namespace {
277 std::string NameToPublicKey(const std::string& name) {
278 std::string public_key;
279 std::string pem;
280 EXPECT_TRUE(Extension::ProducePEM(name, &pem) &&
281 Extension::FormatPEMForFileOutput(pem, &public_key,
282 true /* is_public */));
283 return public_key;
286 // TODO(akalin): Somehow unify this with MakeExtension() in
287 // extension_util_unittest.cc.
288 scoped_refptr<Extension> CreateExtension(const base::FilePath& base_dir,
289 const std::string& name,
290 Manifest::Type type) {
291 base::DictionaryValue source;
292 source.SetString(extensions::manifest_keys::kName, name);
293 const std::string& public_key = NameToPublicKey(name);
294 source.SetString(extensions::manifest_keys::kPublicKey, public_key);
295 source.SetString(extensions::manifest_keys::kVersion, "0.0.0.0");
296 switch (type) {
297 case Manifest::TYPE_EXTENSION:
298 // Do nothing.
299 break;
300 case Manifest::TYPE_THEME:
301 source.Set(extensions::manifest_keys::kTheme,
302 new base::DictionaryValue());
303 break;
304 case Manifest::TYPE_HOSTED_APP:
305 case Manifest::TYPE_LEGACY_PACKAGED_APP:
306 source.Set(extensions::manifest_keys::kApp, new base::DictionaryValue());
307 source.SetString(extensions::manifest_keys::kLaunchWebURL,
308 "http://www.example.com");
309 break;
310 case Manifest::TYPE_PLATFORM_APP: {
311 source.Set(extensions::manifest_keys::kApp, new base::DictionaryValue());
312 source.Set(extensions::manifest_keys::kPlatformAppBackground,
313 new base::DictionaryValue());
314 base::ListValue* scripts = new base::ListValue();
315 scripts->AppendString("main.js");
316 source.Set(extensions::manifest_keys::kPlatformAppBackgroundScripts,
317 scripts);
318 break;
320 default:
321 ADD_FAILURE();
322 return NULL;
324 const base::FilePath sub_dir = base::FilePath().AppendASCII(name);
325 base::FilePath extension_dir;
326 if (!base::PathExists(base_dir) &&
327 !base::CreateDirectory(base_dir)) {
328 ADD_FAILURE();
329 return NULL;
331 if (!base::CreateTemporaryDirInDir(base_dir, sub_dir.value(),
332 &extension_dir)) {
333 ADD_FAILURE();
334 return NULL;
336 std::string error;
337 scoped_refptr<Extension> extension =
338 Extension::Create(extension_dir, Manifest::INTERNAL, source,
339 Extension::NO_FLAGS, &error);
340 if (!error.empty()) {
341 ADD_FAILURE() << error;
342 return NULL;
344 if (!extension.get()) {
345 ADD_FAILURE();
346 return NULL;
348 if (extension->name() != name) {
349 EXPECT_EQ(name, extension->name());
350 return NULL;
352 if (extension->GetType() != type) {
353 EXPECT_EQ(type, extension->GetType());
354 return NULL;
356 return extension;
359 } // namespace
361 scoped_refptr<Extension> SyncExtensionHelper::GetExtension(
362 Profile* profile, const std::string& name, Manifest::Type type) {
363 if (name.empty()) {
364 ADD_FAILURE();
365 return NULL;
367 ProfileExtensionNameMap::iterator it = profile_extensions_.find(profile);
368 if (it == profile_extensions_.end()) {
369 ADD_FAILURE();
370 return NULL;
372 ExtensionNameMap::const_iterator it2 = it->second.find(name);
373 if (it2 != it->second.end()) {
374 return it2->second;
377 scoped_refptr<Extension> extension =
378 CreateExtension(extensions::ExtensionSystem::Get(profile)
379 ->extension_service()
380 ->install_directory(),
381 name,
382 type);
383 if (!extension.get()) {
384 ADD_FAILURE();
385 return NULL;
387 const std::string& expected_id = crx_file::id_util::GenerateId(name);
388 if (extension->id() != expected_id) {
389 EXPECT_EQ(expected_id, extension->id());
390 return NULL;
392 DVLOG(2) << "created extension with name = "
393 << name << ", id = " << expected_id;
394 (it->second)[name] = extension;
395 id_to_name_[expected_id] = name;
396 id_to_type_[expected_id] = type;
397 return extension;