Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / sync / test / integration / sync_extension_helper.cc
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.
4
5 #include "chrome/browser/sync/test/integration/sync_extension_helper.h"
6
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_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 "extensions/browser/extension_registry.h"
19 #include "extensions/browser/extension_system.h"
20 #include "extensions/browser/install_flag.h"
21 #include "extensions/browser/uninstall_reason.h"
22 #include "extensions/common/extension.h"
23 #include "extensions/common/extension_set.h"
24 #include "extensions/common/id_util.h"
25 #include "extensions/common/manifest_constants.h"
26 #include "sync/api/string_ordinal.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 using extensions::Extension;
30 using extensions::ExtensionRegistry;
31 using extensions::Manifest;
32
33 SyncExtensionHelper::ExtensionState::ExtensionState()
34     : enabled_state(ENABLED), incognito_enabled(false) {}
35
36 SyncExtensionHelper::ExtensionState::~ExtensionState() {}
37
38 bool SyncExtensionHelper::ExtensionState::Equals(
39     const SyncExtensionHelper::ExtensionState &other) const {
40   return ((enabled_state == other.enabled_state) &&
41           (incognito_enabled == other.incognito_enabled));
42 }
43
44 // static
45 SyncExtensionHelper* SyncExtensionHelper::GetInstance() {
46   SyncExtensionHelper* instance = Singleton<SyncExtensionHelper>::get();
47   instance->SetupIfNecessary(sync_datatype_helper::test());
48   return instance;
49 }
50
51 SyncExtensionHelper::SyncExtensionHelper() : setup_completed_(false) {}
52
53 SyncExtensionHelper::~SyncExtensionHelper() {}
54
55 void SyncExtensionHelper::SetupIfNecessary(SyncTest* test) {
56   if (setup_completed_)
57     return;
58
59   for (int i = 0; i < test->num_clients(); ++i) {
60     SetupProfile(test->GetProfile(i));
61   }
62   SetupProfile(test->verifier());
63
64   setup_completed_ = true;
65 }
66
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();
73   }
74   extensions::ExtensionSystem::Get(profile)
75       ->extension_service()
76       ->OnExtensionInstalled(extension.get(),
77                              syncer::StringOrdinal(),
78                              extensions::kInstallFlagInstallImmediately);
79   return extension->id();
80 }
81
82 void SyncExtensionHelper::UninstallExtension(
83     Profile* profile, const std::string& name) {
84   ExtensionService::UninstallExtensionHelper(
85       extensions::ExtensionSystem::Get(profile)->extension_service(),
86       extensions::id_util::GenerateId(name),
87       extensions::UNINSTALL_REASON_SYNC);
88 }
89
90 std::vector<std::string> SyncExtensionHelper::GetInstalledExtensionNames(
91     Profile* profile) const {
92   std::vector<std::string> names;
93
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());
100   }
101
102   return names;
103 }
104
105 void SyncExtensionHelper::EnableExtension(Profile* profile,
106                                           const std::string& name) {
107   extensions::ExtensionSystem::Get(profile)
108       ->extension_service()
109       ->EnableExtension(extensions::id_util::GenerateId(name));
110 }
111
112 void SyncExtensionHelper::DisableExtension(Profile* profile,
113                                            const std::string& name) {
114   extensions::ExtensionSystem::Get(profile)
115       ->extension_service()
116       ->DisableExtension(extensions::id_util::GenerateId(name),
117                          Extension::DISABLE_USER_ACTION);
118 }
119
120 bool SyncExtensionHelper::IsExtensionEnabled(
121     Profile* profile, const std::string& name) const {
122   return extensions::ExtensionSystem::Get(profile)
123       ->extension_service()
124       ->IsExtensionEnabled(extensions::id_util::GenerateId(name));
125 }
126
127 void SyncExtensionHelper::IncognitoEnableExtension(
128     Profile* profile, const std::string& name) {
129   extensions::util::SetIsIncognitoEnabled(
130       extensions::id_util::GenerateId(name), profile, true);
131 }
132
133 void SyncExtensionHelper::IncognitoDisableExtension(
134     Profile* profile, const std::string& name) {
135   extensions::util::SetIsIncognitoEnabled(
136       extensions::id_util::GenerateId(name), profile, false);
137 }
138
139 bool SyncExtensionHelper::IsIncognitoEnabled(
140     Profile* profile, const std::string& name) const {
141   return extensions::util::IsIncognitoEnabled(
142       extensions::id_util::GenerateId(name), profile);
143 }
144
145
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();
157 }
158
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.
163
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();
170
171   std::list<std::string> pending_crx_ids;
172   pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_crx_ids);
173
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;
180
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;
186     }
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() << ")";
191     }
192     InstallExtension(profile, iter2->second, iter3->second);
193   }
194 }
195
196 SyncExtensionHelper::ExtensionStateMap
197     SyncExtensionHelper::GetExtensionStates(Profile* profile) {
198   const std::string& profile_debug_name = profile->GetDebugName();
199
200   ExtensionStateMap extension_state_map;
201
202   scoped_ptr<const extensions::ExtensionSet> extensions(
203       extensions::ExtensionRegistry::Get(profile)
204           ->GenerateInstalledExtensionsSet());
205
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);
217
218     DVLOG(2) << "Extension " << (*it)->id() << " in profile "
219              << profile_debug_name << " is "
220              << (extension_service->IsExtensionEnabled(id) ?
221                  "enabled" : "disabled");
222   }
223
224   const extensions::PendingExtensionManager* pending_extension_manager =
225       extension_service->pending_extension_manager();
226
227   std::list<std::string> pending_crx_ids;
228   pending_extension_manager->GetPendingIdsForUpdateCheck(&pending_crx_ids);
229
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";
237   }
238
239   return extension_state_map;
240 }
241
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;
250   }
251
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;
263     }
264     ++it1;
265     ++it2;
266   }
267   return true;
268 }
269
270 void SyncExtensionHelper::SetupProfile(Profile* profile) {
271   extensions::ExtensionSystem::Get(profile)->InitForRegularProfile(true);
272   profile_extensions_.insert(make_pair(profile, ExtensionNameMap()));
273 }
274
275 namespace {
276
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;
284 }
285
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;
319     }
320     default:
321       ADD_FAILURE();
322       return NULL;
323   }
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;
330   }
331   if (!base::CreateTemporaryDirInDir(base_dir, sub_dir.value(),
332                                      &extension_dir)) {
333     ADD_FAILURE();
334     return NULL;
335   }
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;
343   }
344   if (!extension.get()) {
345     ADD_FAILURE();
346     return NULL;
347   }
348   if (extension->name() != name) {
349     EXPECT_EQ(name, extension->name());
350     return NULL;
351   }
352   if (extension->GetType() != type) {
353     EXPECT_EQ(type, extension->GetType());
354     return NULL;
355   }
356   return extension;
357 }
358
359 }  // namespace
360
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;
366   }
367   ProfileExtensionNameMap::iterator it = profile_extensions_.find(profile);
368   if (it == profile_extensions_.end()) {
369     ADD_FAILURE();
370     return NULL;
371   }
372   ExtensionNameMap::const_iterator it2 = it->second.find(name);
373   if (it2 != it->second.end()) {
374     return it2->second;
375   }
376
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;
386   }
387   const std::string& expected_id = extensions::id_util::GenerateId(name);
388   if (extension->id() != expected_id) {
389     EXPECT_EQ(expected_id, extension->id());
390     return NULL;
391   }
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;
398 }