Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / sync / test / integration / sync_extension_helper.cc
blobec9efb843adefda97bac2b360d6f929aebc728ab
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/file_util.h"
8 #include "base/files/file_path.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_system.h"
13 #include "chrome/browser/extensions/extension_util.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/sync/test/integration/sync_datatype_helper.h"
16 #include "chrome/browser/sync/test/integration/sync_test.h"
17 #include "extensions/browser/pending_extension_info.h"
18 #include "extensions/browser/pending_extension_manager.h"
19 #include "extensions/common/extension.h"
20 #include "extensions/common/extension_set.h"
21 #include "extensions/common/id_util.h"
22 #include "extensions/common/manifest_constants.h"
23 #include "sync/api/string_ordinal.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 using extensions::Extension;
27 using extensions::Manifest;
29 SyncExtensionHelper::ExtensionState::ExtensionState()
30 : enabled_state(ENABLED), incognito_enabled(false) {}
32 SyncExtensionHelper::ExtensionState::~ExtensionState() {}
34 bool SyncExtensionHelper::ExtensionState::Equals(
35 const SyncExtensionHelper::ExtensionState &other) const {
36 return ((enabled_state == other.enabled_state) &&
37 (incognito_enabled == other.incognito_enabled));
40 // static
41 SyncExtensionHelper* SyncExtensionHelper::GetInstance() {
42 SyncExtensionHelper* instance = Singleton<SyncExtensionHelper>::get();
43 instance->SetupIfNecessary(sync_datatype_helper::test());
44 return instance;
47 SyncExtensionHelper::SyncExtensionHelper() : setup_completed_(false) {}
49 SyncExtensionHelper::~SyncExtensionHelper() {}
51 void SyncExtensionHelper::SetupIfNecessary(SyncTest* test) {
52 if (setup_completed_)
53 return;
55 for (int i = 0; i < test->num_clients(); ++i) {
56 SetupProfile(test->GetProfile(i));
58 SetupProfile(test->verifier());
60 setup_completed_ = true;
63 std::string SyncExtensionHelper::InstallExtension(
64 Profile* profile, const std::string& name, Manifest::Type type) {
65 scoped_refptr<Extension> extension = GetExtension(profile, name, type);
66 if (!extension.get()) {
67 NOTREACHED() << "Could not install extension " << name;
68 return std::string();
70 profile->GetExtensionService()
71 ->OnExtensionInstalled(extension.get(),
72 syncer::StringOrdinal(),
73 false /* no requirement errors */,
74 extensions::NOT_BLACKLISTED,
75 false /* don't wait for idle to install */);
76 return extension->id();
79 void SyncExtensionHelper::UninstallExtension(
80 Profile* profile, const std::string& name) {
81 ExtensionService::UninstallExtensionHelper(
82 profile->GetExtensionService(),
83 extensions::id_util::GenerateId(name));
86 std::vector<std::string> SyncExtensionHelper::GetInstalledExtensionNames(
87 Profile* profile) const {
88 std::vector<std::string> names;
89 ExtensionService* extension_service = profile->GetExtensionService();
91 scoped_ptr<const extensions::ExtensionSet> extensions(
92 extension_service->GenerateInstalledExtensionsSet());
93 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
94 it != extensions->end(); ++it) {
95 names.push_back((*it)->name());
98 return names;
101 void SyncExtensionHelper::EnableExtension(Profile* profile,
102 const std::string& name) {
103 profile->GetExtensionService()->EnableExtension(
104 extensions::id_util::GenerateId(name));
107 void SyncExtensionHelper::DisableExtension(Profile* profile,
108 const std::string& name) {
109 profile->GetExtensionService()->DisableExtension(
110 extensions::id_util::GenerateId(name), Extension::DISABLE_USER_ACTION);
113 bool SyncExtensionHelper::IsExtensionEnabled(
114 Profile* profile, const std::string& name) const {
115 return profile->GetExtensionService()->IsExtensionEnabled(
116 extensions::id_util::GenerateId(name));
119 void SyncExtensionHelper::IncognitoEnableExtension(
120 Profile* profile, const std::string& name) {
121 extension_util::SetIsIncognitoEnabled(extensions::id_util::GenerateId(name),
122 profile->GetExtensionService(), true);
125 void SyncExtensionHelper::IncognitoDisableExtension(
126 Profile* profile, const std::string& name) {
127 extension_util::SetIsIncognitoEnabled(extensions::id_util::GenerateId(name),
128 profile->GetExtensionService(), false);
131 bool SyncExtensionHelper::IsIncognitoEnabled(
132 Profile* profile, const std::string& name) const {
133 return extension_util::IsIncognitoEnabled(
134 extensions::id_util::GenerateId(name), profile->GetExtensionService());
138 bool SyncExtensionHelper::IsExtensionPendingInstallForSync(
139 Profile* profile, const std::string& id) const {
140 const extensions::PendingExtensionManager* pending_extension_manager =
141 profile->GetExtensionService()->pending_extension_manager();
142 const extensions::PendingExtensionInfo* info =
143 pending_extension_manager->GetById(id);
144 if (!info)
145 return false;
146 return info->is_from_sync();
149 void SyncExtensionHelper::InstallExtensionsPendingForSync(Profile* profile) {
150 // TODO(akalin): Mock out the servers that the extensions auto-update
151 // mechanism talk to so as to more closely match what actually happens.
152 // Background networking will need to be re-enabled for extensions tests.
154 // We make a copy here since InstallExtension() removes the
155 // extension from the extensions service's copy.
156 const extensions::PendingExtensionManager* pending_extension_manager =
157 profile->GetExtensionService()->pending_extension_manager();
159 std::list<std::string> pending_crx_ids;
160 pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_crx_ids);
162 std::list<std::string>::const_iterator iter;
163 const extensions::PendingExtensionInfo* info = NULL;
164 for (iter = pending_crx_ids.begin(); iter != pending_crx_ids.end(); ++iter) {
165 ASSERT_TRUE((info = pending_extension_manager->GetById(*iter)));
166 if (!info->is_from_sync())
167 continue;
169 StringMap::const_iterator iter2 = id_to_name_.find(*iter);
170 if (iter2 == id_to_name_.end()) {
171 ADD_FAILURE() << "Could not get name for id " << *iter
172 << " (profile = " << profile->GetDebugName() << ")";
173 continue;
175 TypeMap::const_iterator iter3 = id_to_type_.find(*iter);
176 if (iter3 == id_to_type_.end()) {
177 ADD_FAILURE() << "Could not get type for id " << *iter
178 << " (profile = " << profile->GetDebugName() << ")";
180 InstallExtension(profile, iter2->second, iter3->second);
184 SyncExtensionHelper::ExtensionStateMap
185 SyncExtensionHelper::GetExtensionStates(Profile* profile) {
186 const std::string& profile_debug_name = profile->GetDebugName();
188 ExtensionStateMap extension_state_map;
190 ExtensionService* extension_service = profile->GetExtensionService();
192 scoped_ptr<const extensions::ExtensionSet> extensions(
193 extension_service->GenerateInstalledExtensionsSet());
194 for (extensions::ExtensionSet::const_iterator it = extensions->begin();
195 it != extensions->end(); ++it) {
196 const std::string& id = (*it)->id();
197 extension_state_map[id].enabled_state =
198 extension_service->IsExtensionEnabled(id) ?
199 ExtensionState::ENABLED :
200 ExtensionState::DISABLED;
201 extension_state_map[id].incognito_enabled =
202 extension_util::IsIncognitoEnabled(id, extension_service);
204 DVLOG(2) << "Extension " << (*it)->id() << " in profile "
205 << profile_debug_name << " is "
206 << (extension_service->IsExtensionEnabled(id) ?
207 "enabled" : "disabled");
210 const extensions::PendingExtensionManager* pending_extension_manager =
211 extension_service->pending_extension_manager();
213 std::list<std::string> pending_crx_ids;
214 pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_crx_ids);
216 std::list<std::string>::const_iterator id;
217 for (id = pending_crx_ids.begin(); id != pending_crx_ids.end(); ++id) {
218 extension_state_map[*id].enabled_state = ExtensionState::PENDING;
219 extension_state_map[*id].incognito_enabled =
220 extension_util::IsIncognitoEnabled(*id, extension_service);
221 DVLOG(2) << "Extension " << *id << " in profile "
222 << profile_debug_name << " is pending";
225 return extension_state_map;
228 bool SyncExtensionHelper::ExtensionStatesMatch(
229 Profile* profile1, Profile* profile2) {
230 const ExtensionStateMap& state_map1 = GetExtensionStates(profile1);
231 const ExtensionStateMap& state_map2 = GetExtensionStates(profile2);
232 if (state_map1.size() != state_map2.size()) {
233 DVLOG(1) << "Number of extensions for profile " << profile1->GetDebugName()
234 << " does not match profile " << profile2->GetDebugName();
235 return false;
238 ExtensionStateMap::const_iterator it1 = state_map1.begin();
239 ExtensionStateMap::const_iterator it2 = state_map2.begin();
240 while (it1 != state_map1.end()) {
241 if (it1->first != it2->first) {
242 DVLOG(1) << "Extensions for profile " << profile1->GetDebugName()
243 << " do not match profile " << profile2->GetDebugName();
244 return false;
245 } else if (!it1->second.Equals(it2->second)) {
246 DVLOG(1) << "Extension states for profile " << profile1->GetDebugName()
247 << " do not match profile " << profile2->GetDebugName();
248 return false;
250 ++it1;
251 ++it2;
253 return true;
256 void SyncExtensionHelper::SetupProfile(Profile* profile) {
257 extensions::ExtensionSystem::Get(profile)->InitForRegularProfile(true);
258 profile_extensions_.insert(make_pair(profile, ExtensionNameMap()));
261 namespace {
263 std::string NameToPublicKey(const std::string& name) {
264 std::string public_key;
265 std::string pem;
266 EXPECT_TRUE(Extension::ProducePEM(name, &pem) &&
267 Extension::FormatPEMForFileOutput(pem, &public_key,
268 true /* is_public */));
269 return public_key;
272 // TODO(akalin): Somehow unify this with MakeExtension() in
273 // extension_util_unittest.cc.
274 scoped_refptr<Extension> CreateExtension(const base::FilePath& base_dir,
275 const std::string& name,
276 Manifest::Type type) {
277 base::DictionaryValue source;
278 source.SetString(extensions::manifest_keys::kName, name);
279 const std::string& public_key = NameToPublicKey(name);
280 source.SetString(extensions::manifest_keys::kPublicKey, public_key);
281 source.SetString(extensions::manifest_keys::kVersion, "0.0.0.0");
282 switch (type) {
283 case Manifest::TYPE_EXTENSION:
284 // Do nothing.
285 break;
286 case Manifest::TYPE_THEME:
287 source.Set(extensions::manifest_keys::kTheme,
288 new base::DictionaryValue());
289 break;
290 case Manifest::TYPE_HOSTED_APP:
291 case Manifest::TYPE_LEGACY_PACKAGED_APP:
292 source.Set(extensions::manifest_keys::kApp, new base::DictionaryValue());
293 source.SetString(extensions::manifest_keys::kLaunchWebURL,
294 "http://www.example.com");
295 break;
296 case Manifest::TYPE_PLATFORM_APP: {
297 source.Set(extensions::manifest_keys::kApp, new base::DictionaryValue());
298 source.Set(extensions::manifest_keys::kPlatformAppBackground,
299 new base::DictionaryValue());
300 base::ListValue* scripts = new base::ListValue();
301 scripts->AppendString("main.js");
302 source.Set(extensions::manifest_keys::kPlatformAppBackgroundScripts,
303 scripts);
304 break;
306 default:
307 ADD_FAILURE();
308 return NULL;
310 const base::FilePath sub_dir = base::FilePath().AppendASCII(name);
311 base::FilePath extension_dir;
312 if (!base::PathExists(base_dir) &&
313 !base::CreateDirectory(base_dir)) {
314 ADD_FAILURE();
315 return NULL;
317 if (!base::CreateTemporaryDirInDir(base_dir, sub_dir.value(),
318 &extension_dir)) {
319 ADD_FAILURE();
320 return NULL;
322 std::string error;
323 scoped_refptr<Extension> extension =
324 Extension::Create(extension_dir, Manifest::INTERNAL, source,
325 Extension::NO_FLAGS, &error);
326 if (!error.empty()) {
327 ADD_FAILURE() << error;
328 return NULL;
330 if (!extension.get()) {
331 ADD_FAILURE();
332 return NULL;
334 if (extension->name() != name) {
335 EXPECT_EQ(name, extension->name());
336 return NULL;
338 if (extension->GetType() != type) {
339 EXPECT_EQ(type, extension->GetType());
340 return NULL;
342 return extension;
345 } // namespace
347 scoped_refptr<Extension> SyncExtensionHelper::GetExtension(
348 Profile* profile, const std::string& name, Manifest::Type type) {
349 if (name.empty()) {
350 ADD_FAILURE();
351 return NULL;
353 ProfileExtensionNameMap::iterator it = profile_extensions_.find(profile);
354 if (it == profile_extensions_.end()) {
355 ADD_FAILURE();
356 return NULL;
358 ExtensionNameMap::const_iterator it2 = it->second.find(name);
359 if (it2 != it->second.end()) {
360 return it2->second;
363 scoped_refptr<Extension> extension =
364 CreateExtension(profile->GetExtensionService()->install_directory(),
365 name, type);
366 if (!extension.get()) {
367 ADD_FAILURE();
368 return NULL;
370 const std::string& expected_id = extensions::id_util::GenerateId(name);
371 if (extension->id() != expected_id) {
372 EXPECT_EQ(expected_id, extension->id());
373 return NULL;
375 DVLOG(2) << "created extension with name = "
376 << name << ", id = " << expected_id;
377 (it->second)[name] = extension;
378 id_to_name_[expected_id] = name;
379 id_to_type_[expected_id] = type;
380 return extension;