extension_service_unittest.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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/extensions/extension_service_unittest.h"
6
7#include <algorithm>
8#include <set>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/command_line.h"
13#include "base/file_util.h"
14#include "base/json/json_reader.h"
15#include "base/message_loop.h"
16#include "base/path_service.h"
17#include "base/scoped_ptr.h"
18#include "base/stl_util-inl.h"
19#include "base/string16.h"
20#include "base/string_number_conversions.h"
21#include "base/string_util.h"
22#include "base/task.h"
23#include "base/utf_string_conversions.h"
24#include "base/version.h"
25#include "chrome/browser/appcache/chrome_appcache_service.h"
26#include "chrome/browser/browser_thread.h"
27#include "chrome/browser/extensions/crx_installer.h"
28#include "chrome/browser/extensions/extension_creator.h"
29#include "chrome/browser/extensions/extension_error_reporter.h"
30#include "chrome/browser/extensions/extension_service.h"
31#include "chrome/browser/extensions/external_extension_provider.h"
32#include "chrome/browser/extensions/external_pref_extension_provider.h"
33#include "chrome/browser/extensions/pack_extension_job.cc"
34#include "chrome/browser/file_system/browser_file_system_helper.h"
35#include "chrome/browser/in_process_webkit/dom_storage_context.h"
36#include "chrome/browser/in_process_webkit/webkit_context.h"
37#include "chrome/browser/prefs/browser_prefs.h"
38#include "chrome/browser/prefs/pref_service_mock_builder.h"
39#include "chrome/browser/prefs/scoped_pref_update.h"
40#include "chrome/common/chrome_paths.h"
41#include "chrome/common/chrome_switches.h"
42#include "chrome/common/extensions/extension.h"
43#include "chrome/common/extensions/extension_constants.h"
44#include "chrome/common/extensions/extension_resource.h"
45#include "chrome/common/extensions/url_pattern.h"
46#include "chrome/common/json_value_serializer.h"
47#include "chrome/common/net/url_request_context_getter.h"
48#include "chrome/common/notification_registrar.h"
49#include "chrome/common/notification_service.h"
50#include "chrome/common/notification_type.h"
51#include "chrome/common/pref_names.h"
52#include "chrome/common/url_constants.h"
53#include "chrome/test/testing_profile.h"
54#include "googleurl/src/gurl.h"
55#include "net/base/cookie_monster.h"
56#include "net/base/cookie_options.h"
57#include "net/url_request/url_request_context.h"
58#include "testing/gtest/include/gtest/gtest.h"
59#include "testing/platform_test.h"
60#include "webkit/database/database_tracker.h"
61#include "webkit/database/database_util.h"
62
63namespace keys = extension_manifest_keys;
64
65namespace {
66
67// Extension ids used during testing.
68const char* const all_zero = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
69const char* const zero_n_one = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab";
70const char* const good0 = "behllobkkfkfnphdnhnkndlbkcpglgmj";
71const char* const good1 = "hpiknbiabeeppbpihjehijgoemciehgk";
72const char* const good2 = "bjafgdebaacbbbecmhlhpofkepfkgcpa";
73const char* const good_crx = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
74const char* const page_action = "obcimlgaoabeegjmmpldobjndiealpln";
75const char* const theme_crx = "iamefpfkojoapidjnbafmgkgncegbkad";
76const char* const theme2_crx = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf";
77const char* const permissions_crx = "eagpmdpfmaekmmcejjbmjoecnejeiiin";
78
79struct ExtensionsOrder {
80  bool operator()(const Extension* a, const Extension* b) {
81    return a->name() < b->name();
82  }
83};
84
85static std::vector<std::string> GetErrors() {
86  const std::vector<std::string>* errors =
87      ExtensionErrorReporter::GetInstance()->GetErrors();
88  std::vector<std::string> ret_val;
89
90  for (std::vector<std::string>::const_iterator iter = errors->begin();
91       iter != errors->end(); ++iter) {
92    if (iter->find(".svn") == std::string::npos) {
93      ret_val.push_back(*iter);
94    }
95  }
96
97  // The tests rely on the errors being in a certain order, which can vary
98  // depending on how filesystem iteration works.
99  std::stable_sort(ret_val.begin(), ret_val.end());
100
101  return ret_val;
102}
103
104static void AddPattern(ExtensionExtent* extent, const std::string& pattern) {
105  int schemes = URLPattern::SCHEME_ALL;
106  extent->AddPattern(URLPattern(schemes, pattern));
107}
108
109static void AssertEqualExtents(ExtensionExtent* extent1,
110                               ExtensionExtent* extent2) {
111  std::vector<URLPattern> patterns1 = extent1->patterns();
112  std::vector<URLPattern> patterns2 = extent2->patterns();
113  std::set<std::string> strings1;
114  EXPECT_EQ(patterns1.size(), patterns2.size());
115
116  for (size_t i = 0; i < patterns1.size(); ++i)
117    strings1.insert(patterns1.at(i).GetAsString());
118
119  std::set<std::string> strings2;
120  for (size_t i = 0; i < patterns2.size(); ++i)
121    strings2.insert(patterns2.at(i).GetAsString());
122
123  EXPECT_EQ(strings1, strings2);
124}
125
126}  // namespace
127
128class MockExtensionProvider : public ExternalExtensionProvider {
129 public:
130  explicit MockExtensionProvider(Extension::Location location)
131    : location_(location), visit_count_(0) {}
132  virtual ~MockExtensionProvider() {}
133
134  void UpdateOrAddExtension(const std::string& id,
135                            const std::string& version,
136                            const FilePath& path) {
137    extension_map_[id] = std::make_pair(version, path);
138  }
139
140  void RemoveExtension(const std::string& id) {
141    extension_map_.erase(id);
142  }
143
144  // ExternalExtensionProvider implementation:
145  virtual void VisitRegisteredExtension(Visitor* visitor) const {
146    visit_count_++;
147    for (DataMap::const_iterator i = extension_map_.begin();
148         i != extension_map_.end(); ++i) {
149      scoped_ptr<Version> version;
150      version.reset(Version::GetVersionFromString(i->second.first));
151
152      visitor->OnExternalExtensionFileFound(
153          i->first, version.get(), i->second.second, location_);
154    }
155  }
156
157  virtual bool HasExtension(const std::string& id) const {
158    return extension_map_.find(id) != extension_map_.end();
159  }
160
161  virtual bool GetExtensionDetails(const std::string& id,
162                                   Extension::Location* location,
163                                   scoped_ptr<Version>* version) const {
164    DataMap::const_iterator it = extension_map_.find(id);
165    if (it == extension_map_.end())
166      return false;
167
168    if (version)
169      version->reset(Version::GetVersionFromString(it->second.first));
170
171    if (location)
172      *location = location_;
173
174    return true;
175  }
176  int visit_count() const { return visit_count_; }
177  void set_visit_count(int visit_count) {
178    visit_count_ = visit_count;
179  }
180
181 private:
182  typedef std::map< std::string, std::pair<std::string, FilePath> > DataMap;
183  DataMap extension_map_;
184  Extension::Location location_;
185
186  // visit_count_ tracks the number of calls to VisitRegisteredExtension().
187  // Mutable because it must be incremented on each call to
188  // VisitRegisteredExtension(), which must be a const method to inherit
189  // from the class being mocked.
190  mutable int visit_count_;
191
192  DISALLOW_COPY_AND_ASSIGN(MockExtensionProvider);
193};
194
195class MockProviderVisitor : public ExternalExtensionProvider::Visitor {
196 public:
197  MockProviderVisitor() : ids_found_(0) {
198  }
199
200  int Visit(const std::string& json_data) {
201    // Give the test json file to the provider for parsing.
202    provider_.reset(new ExternalPrefExtensionProvider());
203    provider_->SetPreferencesForTesting(json_data);
204
205    // We also parse the file into a dictionary to compare what we get back
206    // from the provider.
207    JSONStringValueSerializer serializer(json_data);
208    Value* json_value = serializer.Deserialize(NULL, NULL);
209
210    if (!json_value || !json_value->IsType(Value::TYPE_DICTIONARY)) {
211      NOTREACHED() << "Unable to deserialize json data";
212      return -1;
213    } else {
214      DictionaryValue* external_extensions =
215          static_cast<DictionaryValue*>(json_value);
216      prefs_.reset(external_extensions);
217    }
218
219    // Reset our counter.
220    ids_found_ = 0;
221    // Ask the provider to look up all extensions and return them.
222    provider_->VisitRegisteredExtension(this);
223
224    return ids_found_;
225  }
226
227  virtual void OnExternalExtensionFileFound(const std::string& id,
228                                            const Version* version,
229                                            const FilePath& path,
230                                            Extension::Location unused) {
231    ++ids_found_;
232    DictionaryValue* pref;
233    // This tests is to make sure that the provider only notifies us of the
234    // values we gave it. So if the id we doesn't exist in our internal
235    // dictionary then something is wrong.
236    EXPECT_TRUE(prefs_->GetDictionary(id, &pref))
237       << "Got back ID (" << id.c_str() << ") we weren't expecting";
238
239    if (pref) {
240      EXPECT_TRUE(provider_->HasExtension(id));
241
242      // Ask provider if the extension we got back is registered.
243      Extension::Location location = Extension::INVALID;
244      scoped_ptr<Version> v1;
245      FilePath crx_path;
246
247      EXPECT_TRUE(provider_->GetExtensionDetails(id, NULL, &v1));
248      EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str());
249
250      scoped_ptr<Version> v2;
251      EXPECT_TRUE(provider_->GetExtensionDetails(id, &location, &v2));
252      EXPECT_STREQ(version->GetString().c_str(), v1->GetString().c_str());
253      EXPECT_STREQ(version->GetString().c_str(), v2->GetString().c_str());
254      EXPECT_EQ(Extension::EXTERNAL_PREF, location);
255
256      // Remove it so we won't count it ever again.
257      prefs_->Remove(id, NULL);
258    }
259  }
260
261  virtual void OnExternalExtensionUpdateUrlFound(
262      const std::string& id, const GURL& update_url,
263      Extension::Location location) {
264    ++ids_found_;
265    DictionaryValue* pref;
266    // This tests is to make sure that the provider only notifies us of the
267    // values we gave it. So if the id we doesn't exist in our internal
268    // dictionary then something is wrong.
269    EXPECT_TRUE(prefs_->GetDictionary(id, &pref))
270       << L"Got back ID (" << id.c_str() << ") we weren't expecting";
271    EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location);
272
273    if (pref) {
274      EXPECT_TRUE(provider_->HasExtension(id));
275
276      // External extensions with update URLs do not have versions.
277      scoped_ptr<Version> v1;
278      Extension::Location location1 = Extension::INVALID;
279      EXPECT_TRUE(provider_->GetExtensionDetails(id, &location1, &v1));
280      EXPECT_FALSE(v1.get());
281      EXPECT_EQ(Extension::EXTERNAL_PREF_DOWNLOAD, location1);
282
283      // Remove it so we won't count it again.
284      prefs_->Remove(id, NULL);
285    }
286  }
287
288 private:
289  int ids_found_;
290
291  scoped_ptr<ExternalPrefExtensionProvider> provider_;
292  scoped_ptr<DictionaryValue> prefs_;
293
294  DISALLOW_COPY_AND_ASSIGN(MockProviderVisitor);
295};
296
297class ExtensionTestingProfile : public TestingProfile {
298 public:
299  ExtensionTestingProfile() : service_(NULL) {
300  }
301
302  void set_extensions_service(ExtensionService* service) {
303    service_ = service;
304  }
305  virtual ExtensionService* GetExtensionService() { return service_; }
306
307  virtual ChromeAppCacheService* GetAppCacheService() {
308    if (!appcache_service_) {
309      appcache_service_ = new ChromeAppCacheService;
310      BrowserThread::PostTask(
311          BrowserThread::IO, FROM_HERE,
312          NewRunnableMethod(appcache_service_.get(),
313                            &ChromeAppCacheService::InitializeOnIOThread,
314                            GetPath(), IsOffTheRecord(),
315                            make_scoped_refptr(GetHostContentSettingsMap())));
316    }
317    return appcache_service_;
318  }
319
320  virtual fileapi::SandboxedFileSystemContext* GetFileSystemContext() {
321    if (!file_system_context_)
322      file_system_context_ = CreateFileSystemContext(
323          GetPath(), IsOffTheRecord());
324    return file_system_context_;
325  }
326
327 private:
328  ExtensionService* service_;
329  scoped_refptr<ChromeAppCacheService> appcache_service_;
330  scoped_refptr<fileapi::SandboxedFileSystemContext> file_system_context_;
331};
332
333// Our message loop may be used in tests which require it to be an IO loop.
334ExtensionServiceTestBase::ExtensionServiceTestBase()
335    : total_successes_(0),
336      loop_(MessageLoop::TYPE_IO),
337      ui_thread_(BrowserThread::UI, &loop_),
338      db_thread_(BrowserThread::DB, &loop_),
339      webkit_thread_(BrowserThread::WEBKIT, &loop_),
340      file_thread_(BrowserThread::FILE, &loop_),
341      io_thread_(BrowserThread::IO, &loop_) {
342}
343
344ExtensionServiceTestBase::~ExtensionServiceTestBase() {
345  // Drop our reference to ExtensionService and TestingProfile, so that they
346  // can be destroyed while BrowserThreads and MessageLoop are still around
347  // (they are used in the destruction process).
348  service_ = NULL;
349  profile_.reset(NULL);
350  MessageLoop::current()->RunAllPending();
351}
352
353void ExtensionServiceTestBase::InitializeExtensionService(
354    const FilePath& pref_file, const FilePath& extensions_install_dir) {
355  ExtensionTestingProfile* profile = new ExtensionTestingProfile();
356  // Create a PrefService that only contains user defined preference values.
357  PrefService* prefs =
358      PrefServiceMockBuilder().WithUserFilePrefs(pref_file).Create();
359  Profile::RegisterUserPrefs(prefs);
360  browser::RegisterUserPrefs(prefs);
361  profile->SetPrefService(prefs);
362
363  profile_.reset(profile);
364
365  service_ = profile->CreateExtensionService(
366      CommandLine::ForCurrentProcess(),
367      extensions_install_dir);
368  service_->set_extensions_enabled(true);
369  service_->set_show_extensions_prompts(false);
370  profile->set_extensions_service(service_.get());
371
372  // When we start up, we want to make sure there is no external provider,
373  // since the ExtensionService on Windows will use the Registry as a default
374  // provider and if there is something already registered there then it will
375  // interfere with the tests. Those tests that need an external provider
376  // will register one specifically.
377  service_->ClearProvidersForTesting();
378
379  total_successes_ = 0;
380}
381
382void ExtensionServiceTestBase::InitializeInstalledExtensionService(
383    const FilePath& prefs_file, const FilePath& source_install_dir) {
384  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
385  FilePath path_ = temp_dir_.path();
386  path_ = path_.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
387  file_util::Delete(path_, true);
388  file_util::CreateDirectory(path_);
389  FilePath temp_prefs = path_.Append(FILE_PATH_LITERAL("Preferences"));
390  file_util::CopyFile(prefs_file, temp_prefs);
391
392  extensions_install_dir_ = path_.Append(FILE_PATH_LITERAL("Extensions"));
393  file_util::Delete(extensions_install_dir_, true);
394  file_util::CopyDirectory(source_install_dir, extensions_install_dir_, true);
395
396  InitializeExtensionService(temp_prefs, extensions_install_dir_);
397}
398
399void ExtensionServiceTestBase::InitializeEmptyExtensionService() {
400  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
401  FilePath path_ = temp_dir_.path();
402  path_ = path_.Append(FILE_PATH_LITERAL("TestingExtensionsPath"));
403  file_util::Delete(path_, true);
404  file_util::CreateDirectory(path_);
405  FilePath prefs_filename = path_
406      .Append(FILE_PATH_LITERAL("TestPreferences"));
407  extensions_install_dir_ = path_.Append(FILE_PATH_LITERAL("Extensions"));
408  file_util::Delete(extensions_install_dir_, true);
409  file_util::CreateDirectory(extensions_install_dir_);
410
411  InitializeExtensionService(prefs_filename, extensions_install_dir_);
412}
413
414// static
415void ExtensionServiceTestBase::SetUpTestCase() {
416  ExtensionErrorReporter::Init(false);  // no noisy errors
417}
418
419void ExtensionServiceTestBase::SetUp() {
420  ExtensionErrorReporter::GetInstance()->ClearErrors();
421}
422
423class ExtensionServiceTest
424  : public ExtensionServiceTestBase, public NotificationObserver {
425 public:
426  ExtensionServiceTest() : installed_(NULL) {
427    registrar_.Add(this, NotificationType::EXTENSION_LOADED,
428                   NotificationService::AllSources());
429    registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
430                   NotificationService::AllSources());
431    registrar_.Add(this, NotificationType::EXTENSION_INSTALLED,
432                   NotificationService::AllSources());
433    registrar_.Add(this, NotificationType::THEME_INSTALLED,
434                   NotificationService::AllSources());
435  }
436
437  virtual void Observe(NotificationType type,
438                       const NotificationSource& source,
439                       const NotificationDetails& details) {
440    switch (type.value) {
441      case NotificationType::EXTENSION_LOADED: {
442        const Extension* extension = Details<const Extension>(details).ptr();
443        loaded_.push_back(make_scoped_refptr(extension));
444        // The tests rely on the errors being in a certain order, which can vary
445        // depending on how filesystem iteration works.
446        std::stable_sort(loaded_.begin(), loaded_.end(), ExtensionsOrder());
447        break;
448      }
449
450      case NotificationType::EXTENSION_UNLOADED: {
451        const Extension* e =
452            Details<UnloadedExtensionInfo>(details)->extension;
453        unloaded_id_ = e->id();
454        ExtensionList::iterator i =
455            std::find(loaded_.begin(), loaded_.end(), e);
456        // TODO(erikkay) fix so this can be an assert.  Right now the tests
457        // are manually calling clear() on loaded_, so this isn't doable.
458        if (i == loaded_.end())
459          return;
460        loaded_.erase(i);
461        break;
462      }
463      case NotificationType::EXTENSION_INSTALLED:
464      case NotificationType::THEME_INSTALLED:
465        installed_ = Details<const Extension>(details).ptr();
466        break;
467
468      default:
469        DCHECK(false);
470    }
471  }
472
473  void AddMockExternalProvider(ExternalExtensionProvider* provider) {
474    service_->AddProviderForTesting(provider);
475  }
476
477 protected:
478  void TestExternalProvider(MockExtensionProvider* provider,
479                            Extension::Location location);
480
481  void PackAndInstallExtension(const FilePath& dir_path,
482                               const FilePath& pem_path,
483                               bool should_succeed) {
484    FilePath crx_path;
485    ASSERT_TRUE(PathService::Get(base::DIR_TEMP, &crx_path));
486    crx_path = crx_path.AppendASCII("temp.crx");
487
488    // Use the existing pem key, if provided.
489    FilePath pem_output_path;
490    if (pem_path.value().empty()) {
491      pem_output_path = crx_path.DirName().AppendASCII("temp.pem");
492      ASSERT_TRUE(file_util::Delete(pem_output_path, false));
493    } else {
494      ASSERT_TRUE(file_util::PathExists(pem_path));
495    }
496
497    ASSERT_TRUE(file_util::Delete(crx_path, false));
498
499    scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
500    ASSERT_TRUE(creator->Run(dir_path,
501                             crx_path,
502                             pem_path,
503                             pem_output_path));
504
505    ASSERT_TRUE(file_util::PathExists(crx_path));
506
507    InstallExtension(crx_path, should_succeed);
508  }
509
510  void PackAndInstallExtension(const FilePath& dir_path,
511                               bool should_succeed) {
512      PackAndInstallExtension(dir_path, FilePath(), should_succeed);
513  }
514
515  void InstallExtension(const FilePath& path,
516                        bool should_succeed) {
517    ASSERT_TRUE(file_util::PathExists(path));
518    service_->InstallExtension(path);
519    loop_.RunAllPending();
520    std::vector<std::string> errors = GetErrors();
521    if (should_succeed) {
522      ++total_successes_;
523
524      EXPECT_TRUE(installed_) << path.value();
525
526      ASSERT_EQ(1u, loaded_.size()) << path.value();
527      EXPECT_EQ(0u, errors.size()) << path.value();
528      EXPECT_EQ(total_successes_, service_->extensions()->size()) <<
529          path.value();
530      EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false)) <<
531          path.value();
532      for (std::vector<std::string>::iterator err = errors.begin();
533        err != errors.end(); ++err) {
534        LOG(ERROR) << *err;
535      }
536    } else {
537      EXPECT_FALSE(installed_) << path.value();
538      EXPECT_EQ(0u, loaded_.size()) << path.value();
539      EXPECT_EQ(1u, errors.size()) << path.value();
540    }
541
542    installed_ = NULL;
543    loaded_.clear();
544    ExtensionErrorReporter::GetInstance()->ClearErrors();
545  }
546
547  enum UpdateState {
548    FAILED_SILENTLY,
549    FAILED,
550    UPDATED,
551    INSTALLED,
552    ENABLED
553  };
554
555  void UpdateExtension(const std::string& id, const FilePath& in_path,
556                       UpdateState expected_state) {
557    ASSERT_TRUE(file_util::PathExists(in_path));
558
559    // We need to copy this to a temporary location because Update() will delete
560    // it.
561    FilePath path = temp_dir_.path();
562    path = path.Append(in_path.BaseName());
563    ASSERT_TRUE(file_util::CopyFile(in_path, path));
564
565    int previous_enabled_extension_count =
566        service_->extensions()->size();
567    int previous_installed_extension_count =
568        previous_enabled_extension_count +
569        service_->disabled_extensions()->size();
570
571    service_->UpdateExtension(id, path, GURL());
572    loop_.RunAllPending();
573
574    std::vector<std::string> errors = GetErrors();
575    int error_count = errors.size();
576    int enabled_extension_count =
577        service_->extensions()->size();
578    int installed_extension_count =
579        enabled_extension_count + service_->disabled_extensions()->size();
580
581    int expected_error_count = (expected_state == FAILED) ? 1 : 0;
582    EXPECT_EQ(expected_error_count, error_count) << path.value();
583
584    if (expected_state <= FAILED) {
585      EXPECT_EQ(previous_enabled_extension_count,
586                enabled_extension_count);
587      EXPECT_EQ(previous_installed_extension_count,
588                installed_extension_count);
589    } else {
590      int expected_installed_extension_count =
591          (expected_state >= INSTALLED) ? 1 : 0;
592      int expected_enabled_extension_count =
593          (expected_state >= ENABLED) ? 1 : 0;
594      EXPECT_EQ(expected_installed_extension_count,
595                installed_extension_count);
596      EXPECT_EQ(expected_enabled_extension_count,
597                enabled_extension_count);
598    }
599
600    // Update() should delete the temporary input file.
601    EXPECT_FALSE(file_util::PathExists(path));
602  }
603
604  void ValidatePrefKeyCount(size_t count) {
605    DictionaryValue* dict =
606        profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
607    ASSERT_TRUE(dict != NULL);
608    EXPECT_EQ(count, dict->size());
609  }
610
611  void ValidateBooleanPref(const std::string& extension_id,
612                           const std::string& pref_path,
613                           bool expected_val) {
614    std::string msg = " while checking: ";
615    msg += extension_id;
616    msg += " ";
617    msg += pref_path;
618    msg += " == ";
619    msg += expected_val ? "true" : "false";
620
621    PrefService* prefs = profile_->GetPrefs();
622    const DictionaryValue* dict =
623        prefs->GetDictionary("extensions.settings");
624    ASSERT_TRUE(dict != NULL) << msg;
625    DictionaryValue* pref = NULL;
626    ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
627    EXPECT_TRUE(pref != NULL) << msg;
628    bool val;
629    ASSERT_TRUE(pref->GetBoolean(pref_path, &val)) << msg;
630    EXPECT_EQ(expected_val, val) << msg;
631  }
632
633  bool IsPrefExist(const std::string& extension_id,
634                   const std::string& pref_path) {
635    const DictionaryValue* dict =
636        profile_->GetPrefs()->GetDictionary("extensions.settings");
637    if (dict == NULL) return false;
638    DictionaryValue* pref = NULL;
639    if (!dict->GetDictionary(extension_id, &pref)) {
640      return false;
641    }
642    if (pref == NULL) {
643      return false;
644    }
645    bool val;
646    if (!pref->GetBoolean(pref_path, &val)) {
647      return false;
648    }
649    return true;
650  }
651
652  void ValidateIntegerPref(const std::string& extension_id,
653                           const std::string& pref_path,
654                           int expected_val) {
655    std::string msg = " while checking: ";
656    msg += extension_id;
657    msg += " ";
658    msg += pref_path;
659    msg += " == ";
660    msg += base::IntToString(expected_val);
661
662    PrefService* prefs = profile_->GetPrefs();
663    const DictionaryValue* dict =
664        prefs->GetDictionary("extensions.settings");
665    ASSERT_TRUE(dict != NULL) << msg;
666    DictionaryValue* pref = NULL;
667    ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
668    EXPECT_TRUE(pref != NULL) << msg;
669    int val;
670    ASSERT_TRUE(pref->GetInteger(pref_path, &val)) << msg;
671    EXPECT_EQ(expected_val, val) << msg;
672  }
673
674  void ValidateStringPref(const std::string& extension_id,
675                          const std::string& pref_path,
676                          const std::string& expected_val) {
677    std::string msg = " while checking: ";
678    msg += extension_id;
679    msg += ".manifest.";
680    msg += pref_path;
681    msg += " == ";
682    msg += expected_val;
683
684    const DictionaryValue* dict =
685        profile_->GetPrefs()->GetDictionary("extensions.settings");
686    ASSERT_TRUE(dict != NULL) << msg;
687    DictionaryValue* pref = NULL;
688    std::string manifest_path = extension_id + ".manifest";
689    ASSERT_TRUE(dict->GetDictionary(manifest_path, &pref)) << msg;
690    EXPECT_TRUE(pref != NULL) << msg;
691    std::string val;
692    ASSERT_TRUE(pref->GetString(pref_path, &val)) << msg;
693    EXPECT_EQ(expected_val, val) << msg;
694  }
695
696  void SetPref(const std::string& extension_id,
697               const std::string& pref_path,
698               Value* value,
699               const std::string& msg) {
700    const DictionaryValue* dict =
701        profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
702    ASSERT_TRUE(dict != NULL) << msg;
703    DictionaryValue* pref = NULL;
704    ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
705    EXPECT_TRUE(pref != NULL) << msg;
706    pref->Set(pref_path, value);
707  }
708
709  void SetPrefInteg(const std::string& extension_id,
710                    const std::string& pref_path,
711                    int value) {
712    std::string msg = " while setting: ";
713    msg += extension_id;
714    msg += " ";
715    msg += pref_path;
716    msg += " = ";
717    msg += base::IntToString(value);
718
719    SetPref(extension_id, pref_path, Value::CreateIntegerValue(value), msg);
720  }
721
722  void SetPrefBool(const std::string& extension_id,
723                   const std::string& pref_path,
724                   bool value) {
725    std::string msg = " while setting: ";
726    msg += extension_id + " " + pref_path;
727    msg += " = ";
728    msg += (value ? "true" : "false");
729
730    SetPref(extension_id, pref_path, Value::CreateBooleanValue(value), msg);
731  }
732
733  void ClearPref(const std::string& extension_id,
734                 const std::string& pref_path) {
735    std::string msg = " while clearing: ";
736    msg += extension_id + " " + pref_path;
737
738    const DictionaryValue* dict =
739        profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
740    ASSERT_TRUE(dict != NULL) << msg;
741    DictionaryValue* pref = NULL;
742    ASSERT_TRUE(dict->GetDictionary(extension_id, &pref)) << msg;
743    EXPECT_TRUE(pref != NULL) << msg;
744    pref->Remove(pref_path, NULL);
745  }
746
747  void SetPrefStringSet(const std::string& extension_id,
748                        const std::string& pref_path,
749                        const std::set<std::string>& value) {
750    std::string msg = " while setting: ";
751    msg += extension_id + " " + pref_path;
752
753    ListValue* list_value = new ListValue();
754    for (std::set<std::string>::const_iterator iter = value.begin();
755         iter != value.end(); ++iter)
756      list_value->Append(Value::CreateStringValue(*iter));
757
758    SetPref(extension_id, pref_path, list_value, msg);
759  }
760
761 protected:
762  ExtensionList loaded_;
763  std::string unloaded_id_;
764  const Extension* installed_;
765
766 private:
767  NotificationRegistrar registrar_;
768};
769
770FilePath NormalizeSeparators(const FilePath& path) {
771#if defined(FILE_PATH_USES_WIN_SEPARATORS)
772  return path.NormalizeWindowsPathSeparators();
773#else
774  return path;
775#endif  // FILE_PATH_USES_WIN_SEPARATORS
776}
777
778// Receives notifications from a PackExtensionJob, indicating either that
779// packing succeeded or that there was some error.
780class PackExtensionTestClient : public PackExtensionJob::Client {
781 public:
782  PackExtensionTestClient(const FilePath& expected_crx_path,
783                          const FilePath& expected_private_key_path);
784  virtual void OnPackSuccess(const FilePath& crx_path,
785                             const FilePath& private_key_path);
786  virtual void OnPackFailure(const std::string& error_message);
787
788 private:
789  const FilePath expected_crx_path_;
790  const FilePath expected_private_key_path_;
791  DISALLOW_COPY_AND_ASSIGN(PackExtensionTestClient);
792};
793
794PackExtensionTestClient::PackExtensionTestClient(
795    const FilePath& expected_crx_path,
796    const FilePath& expected_private_key_path)
797    : expected_crx_path_(expected_crx_path),
798      expected_private_key_path_(expected_private_key_path) {}
799
800// If packing succeeded, we make sure that the package names match our
801// expectations.
802void PackExtensionTestClient::OnPackSuccess(const FilePath& crx_path,
803                                            const FilePath& private_key_path) {
804  // We got the notification and processed it; we don't expect any further tasks
805  // to be posted to the current thread, so we should stop blocking and continue
806  // on with the rest of the test.
807  // This call to |Quit()| matches the call to |Run()| in the
808  // |PackPunctuatedExtension| test.
809  MessageLoop::current()->Quit();
810  EXPECT_EQ(expected_crx_path_.value(), crx_path.value());
811  EXPECT_EQ(expected_private_key_path_.value(), private_key_path.value());
812  ASSERT_TRUE(file_util::PathExists(private_key_path));
813}
814
815// The tests are designed so that we never expect to see a packing error.
816void PackExtensionTestClient::OnPackFailure(const std::string& error_message) {
817  FAIL() << "Packing should not fail.";
818}
819
820// Test loading good extensions from the profile directory.
821TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectorySuccess) {
822  // Initialize the test dir with a good Preferences/extensions.
823  FilePath source_install_dir;
824  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
825  source_install_dir = source_install_dir
826      .AppendASCII("extensions")
827      .AppendASCII("good")
828      .AppendASCII("Extensions");
829  FilePath pref_path = source_install_dir
830      .DirName()
831      .AppendASCII("Preferences");
832  InitializeInstalledExtensionService(pref_path, source_install_dir);
833
834  service_->Init();
835
836  // On Chrome OS, we disallow extensions with plugins.  "good1" has plugins,
837  // so we need to edit it out here.
838  uint32 expected_num_extensions = 3u;
839#if defined(OS_CHROMEOS)
840  --expected_num_extensions;
841#endif
842  ASSERT_EQ(expected_num_extensions, loaded_.size());
843
844  EXPECT_EQ(std::string(good0), loaded_[0]->id());
845  EXPECT_EQ(std::string("My extension 1"),
846            loaded_[0]->name());
847  EXPECT_EQ(std::string("The first extension that I made."),
848            loaded_[0]->description());
849  EXPECT_EQ(Extension::INTERNAL, loaded_[0]->location());
850  EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false));
851  EXPECT_EQ(expected_num_extensions, service_->extensions()->size());
852
853  ValidatePrefKeyCount(3);
854  ValidateIntegerPref(good0, "state", Extension::ENABLED);
855  ValidateIntegerPref(good0, "location", Extension::INTERNAL);
856  ValidateIntegerPref(good1, "state", Extension::ENABLED);
857  ValidateIntegerPref(good1, "location", Extension::INTERNAL);
858  ValidateIntegerPref(good2, "state", Extension::ENABLED);
859  ValidateIntegerPref(good2, "location", Extension::INTERNAL);
860
861  const Extension* extension = loaded_[0];
862  const UserScriptList& scripts = extension->content_scripts();
863  ASSERT_EQ(2u, scripts.size());
864  EXPECT_EQ(3u, scripts[0].url_patterns().size());
865  EXPECT_EQ("file://*",
866            scripts[0].url_patterns()[0].GetAsString());
867  EXPECT_EQ("http://*.google.com/*",
868            scripts[0].url_patterns()[1].GetAsString());
869  EXPECT_EQ("https://*.google.com/*",
870            scripts[0].url_patterns()[2].GetAsString());
871  EXPECT_EQ(2u, scripts[0].js_scripts().size());
872  ExtensionResource resource00(extension->id(),
873                               scripts[0].js_scripts()[0].extension_root(),
874                               scripts[0].js_scripts()[0].relative_path());
875  FilePath expected_path(extension->path().AppendASCII("script1.js"));
876  ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
877  EXPECT_TRUE(resource00.ComparePathWithDefault(expected_path));
878  ExtensionResource resource01(extension->id(),
879                               scripts[0].js_scripts()[1].extension_root(),
880                               scripts[0].js_scripts()[1].relative_path());
881  expected_path = extension->path().AppendASCII("script2.js");
882  ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
883  EXPECT_TRUE(resource01.ComparePathWithDefault(expected_path));
884  EXPECT_TRUE(extension->plugins().empty());
885  EXPECT_EQ(1u, scripts[1].url_patterns().size());
886  EXPECT_EQ("http://*.news.com/*", scripts[1].url_patterns()[0].GetAsString());
887  ExtensionResource resource10(extension->id(),
888                               scripts[1].js_scripts()[0].extension_root(),
889                               scripts[1].js_scripts()[0].relative_path());
890  expected_path =
891      extension->path().AppendASCII("js_files").AppendASCII("script3.js");
892  ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
893  EXPECT_TRUE(resource10.ComparePathWithDefault(expected_path));
894  const std::vector<URLPattern> permissions = extension->host_permissions();
895  ASSERT_EQ(2u, permissions.size());
896  EXPECT_EQ("http://*.google.com/*", permissions[0].GetAsString());
897  EXPECT_EQ("https://*.google.com/*", permissions[1].GetAsString());
898
899#if !defined(OS_CHROMEOS)
900  EXPECT_EQ(std::string(good1), loaded_[1]->id());
901  EXPECT_EQ(std::string("My extension 2"), loaded_[1]->name());
902  EXPECT_EQ(std::string(""), loaded_[1]->description());
903  EXPECT_EQ(loaded_[1]->GetResourceURL("background.html"),
904            loaded_[1]->background_url());
905  EXPECT_EQ(0u, loaded_[1]->content_scripts().size());
906  EXPECT_EQ(2u, loaded_[1]->plugins().size());
907  EXPECT_EQ(loaded_[1]->path().AppendASCII("content_plugin.dll").value(),
908            loaded_[1]->plugins()[0].path.value());
909  EXPECT_TRUE(loaded_[1]->plugins()[0].is_public);
910  EXPECT_EQ(loaded_[1]->path().AppendASCII("extension_plugin.dll").value(),
911            loaded_[1]->plugins()[1].path.value());
912  EXPECT_FALSE(loaded_[1]->plugins()[1].is_public);
913  EXPECT_EQ(Extension::INTERNAL, loaded_[1]->location());
914#endif
915
916  int index = expected_num_extensions - 1;
917  EXPECT_EQ(std::string(good2), loaded_[index]->id());
918  EXPECT_EQ(std::string("My extension 3"), loaded_[index]->name());
919  EXPECT_EQ(std::string(""), loaded_[index]->description());
920  EXPECT_EQ(0u, loaded_[index]->content_scripts().size());
921  EXPECT_EQ(Extension::INTERNAL, loaded_[index]->location());
922};
923
924// Test loading bad extensions from the profile directory.
925TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectoryFail) {
926  // Initialize the test dir with a bad Preferences/extensions.
927  FilePath source_install_dir;
928  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
929  source_install_dir = source_install_dir
930      .AppendASCII("extensions")
931      .AppendASCII("bad")
932      .AppendASCII("Extensions");
933  FilePath pref_path = source_install_dir
934      .DirName()
935      .AppendASCII("Preferences");
936
937  InitializeInstalledExtensionService(pref_path, source_install_dir);
938
939  service_->Init();
940  loop_.RunAllPending();
941
942  ASSERT_EQ(4u, GetErrors().size());
943  ASSERT_EQ(0u, loaded_.size());
944
945  EXPECT_TRUE(MatchPattern(GetErrors()[0],
946      std::string("Could not load extension from '*'. ") +
947      extension_manifest_errors::kManifestUnreadable)) << GetErrors()[0];
948
949  EXPECT_TRUE(MatchPattern(GetErrors()[1],
950      std::string("Could not load extension from '*'. ") +
951      extension_manifest_errors::kManifestUnreadable)) << GetErrors()[1];
952
953  EXPECT_TRUE(MatchPattern(GetErrors()[2],
954      std::string("Could not load extension from '*'. ") +
955      extension_manifest_errors::kMissingFile)) << GetErrors()[2];
956
957  EXPECT_TRUE(MatchPattern(GetErrors()[3],
958      std::string("Could not load extension from '*'. ") +
959      extension_manifest_errors::kManifestUnreadable)) << GetErrors()[3];
960};
961
962// Test that partially deleted extensions are cleaned up during startup
963// Test loading bad extensions from the profile directory.
964TEST_F(ExtensionServiceTest, CleanupOnStartup) {
965  FilePath source_install_dir;
966  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
967  source_install_dir = source_install_dir
968      .AppendASCII("extensions")
969      .AppendASCII("good")
970      .AppendASCII("Extensions");
971  FilePath pref_path = source_install_dir
972      .DirName()
973      .AppendASCII("Preferences");
974
975  InitializeInstalledExtensionService(pref_path, source_install_dir);
976
977  // Simulate that one of them got partially deleted by clearing its pref.
978  DictionaryValue* dict =
979      profile_->GetPrefs()->GetMutableDictionary("extensions.settings");
980  ASSERT_TRUE(dict != NULL);
981  dict->Remove("behllobkkfkfnphdnhnkndlbkcpglgmj", NULL);
982
983  service_->Init();
984  loop_.RunAllPending();
985
986  file_util::FileEnumerator dirs(extensions_install_dir_, false,
987                                 file_util::FileEnumerator::DIRECTORIES);
988  size_t count = 0;
989  while (!dirs.Next().empty())
990    count++;
991
992  // We should have only gotten two extensions now.
993  EXPECT_EQ(2u, count);
994
995  // And extension1 dir should now be toast.
996  FilePath extension_dir = extensions_install_dir_
997      .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj");
998  ASSERT_FALSE(file_util::PathExists(extension_dir));
999}
1000
1001// Test installing extensions. This test tries to install few extensions using
1002// crx files. If you need to change those crx files, feel free to repackage
1003// them, throw away the key used and change the id's above.
1004TEST_F(ExtensionServiceTest, InstallExtension) {
1005  InitializeEmptyExtensionService();
1006
1007  FilePath extensions_path;
1008  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1009  extensions_path = extensions_path.AppendASCII("extensions");
1010
1011  // Extensions not enabled.
1012  set_extensions_enabled(false);
1013  FilePath path = extensions_path.AppendASCII("good.crx");
1014  InstallExtension(path, false);
1015  set_extensions_enabled(true);
1016
1017  ValidatePrefKeyCount(0);
1018
1019  // A simple extension that should install without error.
1020  path = extensions_path.AppendASCII("good.crx");
1021  InstallExtension(path, true);
1022  // TODO(erikkay): verify the contents of the installed extension.
1023
1024  int pref_count = 0;
1025  ValidatePrefKeyCount(++pref_count);
1026  ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
1027  ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
1028
1029  // An extension with page actions.
1030  path = extensions_path.AppendASCII("page_action.crx");
1031  InstallExtension(path, true);
1032  ValidatePrefKeyCount(++pref_count);
1033  ValidateIntegerPref(page_action, "state", Extension::ENABLED);
1034  ValidateIntegerPref(page_action, "location", Extension::INTERNAL);
1035
1036  // Bad signature.
1037  path = extensions_path.AppendASCII("bad_signature.crx");
1038  InstallExtension(path, false);
1039  ValidatePrefKeyCount(pref_count);
1040
1041  // 0-length extension file.
1042  path = extensions_path.AppendASCII("not_an_extension.crx");
1043  InstallExtension(path, false);
1044  ValidatePrefKeyCount(pref_count);
1045
1046  // Bad magic number.
1047  path = extensions_path.AppendASCII("bad_magic.crx");
1048  InstallExtension(path, false);
1049  ValidatePrefKeyCount(pref_count);
1050
1051  // Extensions cannot have folders or files that have underscores except in
1052  // certain whitelisted cases (eg _locales). This is an example of a broader
1053  // class of validation that we do to the directory structure of the extension.
1054  // We did not used to handle this correctly for installation.
1055  path = extensions_path.AppendASCII("bad_underscore.crx");
1056  InstallExtension(path, false);
1057  ValidatePrefKeyCount(pref_count);
1058
1059  // TODO(erikkay): add more tests for many of the failure cases.
1060  // TODO(erikkay): add tests for upgrade cases.
1061}
1062
1063// Test the handling of killed extensions.
1064TEST_F(ExtensionServiceTest, KilledExtensions) {
1065  InitializeEmptyExtensionService();
1066
1067  FilePath extensions_path;
1068  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1069  extensions_path = extensions_path.AppendASCII("extensions");
1070  FilePath path = extensions_path.AppendASCII("good.crx");
1071  set_extensions_enabled(true);
1072
1073  // Install an external extension.
1074  service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0",
1075                                         path, Extension::EXTERNAL_PREF);
1076  loop_.RunAllPending();
1077  ASSERT_TRUE(NULL != service_->GetExtensionById(good_crx, false));
1078
1079  // Uninstall it and check that its killbit gets set.
1080  service_->UninstallExtension(good_crx, false);
1081  loop_.RunAllPending();
1082  ValidateIntegerPref(good_crx, "location", Extension::KILLBIT);
1083
1084  // Try to re-install it externally. This should fail because of the killbit.
1085  service_->OnExternalExtensionFileFound(good_crx, "1.0.0.0",
1086                                         path, Extension::EXTERNAL_PREF);
1087  loop_.RunAllPending();
1088  ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false));
1089  ValidateIntegerPref(good_crx, "location", Extension::KILLBIT);
1090
1091  // Repeat the same thing with a newer version of the extension.
1092  path = extensions_path.AppendASCII("good2.crx");
1093  service_->OnExternalExtensionFileFound(good_crx, "1.0.0.1",
1094                                         path, Extension::EXTERNAL_PREF);
1095  loop_.RunAllPending();
1096  ASSERT_TRUE(NULL == service_->GetExtensionById(good_crx, false));
1097  ValidateIntegerPref(good_crx, "location", Extension::KILLBIT);
1098
1099  // Try adding the same extension from an external update URL.
1100  service_->AddPendingExtensionFromExternalUpdateUrl(
1101      good_crx,
1102      GURL("http:://fake.update/url"),
1103      Extension::EXTERNAL_PREF_DOWNLOAD);
1104  const PendingExtensionMap& pending_extensions =
1105      service_->pending_extensions();
1106  ASSERT_TRUE(pending_extensions.find(good_crx) == pending_extensions.end());
1107}
1108
1109// Install a user script (they get converted automatically to an extension)
1110TEST_F(ExtensionServiceTest, InstallUserScript) {
1111  // The details of script conversion are tested elsewhere, this just tests
1112  // integration with ExtensionService.
1113  InitializeEmptyExtensionService();
1114
1115  FilePath path;
1116  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
1117  path = path.AppendASCII("extensions")
1118             .AppendASCII("user_script_basic.user.js");
1119
1120  ASSERT_TRUE(file_util::PathExists(path));
1121  scoped_refptr<CrxInstaller> installer(
1122      new CrxInstaller(service_, NULL));  // silent install
1123  installer->InstallUserScript(
1124      path,
1125      GURL("http://www.aaronboodman.com/scripts/user_script_basic.user.js"));
1126
1127  loop_.RunAllPending();
1128  std::vector<std::string> errors = GetErrors();
1129  EXPECT_TRUE(installed_) << "Nothing was installed.";
1130  ASSERT_EQ(1u, loaded_.size()) << "Nothing was loaded.";
1131  EXPECT_EQ(0u, errors.size()) << "There were errors: "
1132                               << JoinString(errors, ',');
1133  EXPECT_TRUE(service_->GetExtensionById(loaded_[0]->id(), false)) <<
1134              path.value();
1135
1136  installed_ = NULL;
1137  loaded_.clear();
1138  ExtensionErrorReporter::GetInstance()->ClearErrors();
1139}
1140
1141// This tests that the granted permissions preferences are correctly set when
1142// installing an extension.
1143TEST_F(ExtensionServiceTest, GrantedPermissions) {
1144  InitializeEmptyExtensionService();
1145  FilePath path;
1146  FilePath pem_path;
1147  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
1148  path = path.AppendASCII("extensions")
1149      .AppendASCII("permissions");
1150
1151  pem_path = path.AppendASCII("unknown.pem");
1152  path = path.AppendASCII("unknown");
1153
1154  ASSERT_TRUE(file_util::PathExists(pem_path));
1155  ASSERT_TRUE(file_util::PathExists(path));
1156
1157  ExtensionPrefs* prefs = service_->extension_prefs();
1158
1159  std::set<std::string> expected_api_perms;
1160  std::set<std::string> known_api_perms;
1161  bool full_access;
1162  ExtensionExtent expected_host_perms;
1163  ExtensionExtent known_host_perms;
1164
1165  // Make sure there aren't any granted permissions before the
1166  // extension is installed.
1167  EXPECT_FALSE(prefs->GetGrantedPermissions(
1168      permissions_crx, &full_access, &known_api_perms, &known_host_perms));
1169  EXPECT_TRUE(known_api_perms.empty());
1170  EXPECT_TRUE(known_host_perms.is_empty());
1171
1172  PackAndInstallExtension(path, pem_path, true);
1173
1174  EXPECT_EQ(0u, GetErrors().size());
1175  ASSERT_EQ(1u, service_->extensions()->size());
1176  std::string extension_id = service_->extensions()->at(0)->id();
1177  EXPECT_EQ(permissions_crx, extension_id);
1178
1179
1180  // Verify that the valid API permissions have been recognized.
1181  expected_api_perms.insert("tabs");
1182
1183  AddPattern(&expected_host_perms, "http://*.google.com/*");
1184  AddPattern(&expected_host_perms, "https://*.google.com/*");
1185  AddPattern(&expected_host_perms, "http://*.google.com.hk/*");
1186  AddPattern(&expected_host_perms, "http://www.example.com/*");
1187
1188  EXPECT_TRUE(prefs->GetGrantedPermissions(extension_id,
1189                                           &full_access,
1190                                           &known_api_perms,
1191                                           &known_host_perms));
1192
1193  EXPECT_EQ(expected_api_perms, known_api_perms);
1194  EXPECT_FALSE(full_access);
1195  AssertEqualExtents(&expected_host_perms, &known_host_perms);
1196}
1197
1198#if !defined(OS_CHROMEOS)
1199// Tests that the granted permissions full_access bit gets set correctly when
1200// an extension contains an NPAPI plugin. Don't run this test on Chrome OS
1201// since they don't support plugins.
1202TEST_F(ExtensionServiceTest, GrantedFullAccessPermissions) {
1203  InitializeEmptyExtensionService();
1204
1205  FilePath path;
1206  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
1207  path = path.AppendASCII("extensions")
1208      .AppendASCII("good")
1209      .AppendASCII("Extensions")
1210      .AppendASCII(good1)
1211      .AppendASCII("2");
1212
1213  ASSERT_TRUE(file_util::PathExists(path));
1214
1215  PackAndInstallExtension(path, true);
1216
1217  EXPECT_EQ(0u, GetErrors().size());
1218  EXPECT_EQ(1u, service_->extensions()->size());
1219  const Extension* extension = service_->extensions()->at(0);
1220  std::string extension_id = extension->id();
1221  ExtensionPrefs* prefs = service_->extension_prefs();
1222
1223  bool full_access;
1224  std::set<std::string> api_permissions;
1225  ExtensionExtent host_permissions;
1226  EXPECT_TRUE(prefs->GetGrantedPermissions(
1227      extension_id, &full_access, &api_permissions, &host_permissions));
1228
1229  EXPECT_TRUE(full_access);
1230  EXPECT_TRUE(api_permissions.empty());
1231  EXPECT_TRUE(host_permissions.is_empty());
1232}
1233#endif
1234
1235// Tests that the extension is disabled when permissions are missing from
1236// the extension's granted permissions preferences. (This simulates updating
1237// the browser to a version which recognizes more permissions).
1238TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) {
1239  InitializeEmptyExtensionService();
1240
1241  FilePath path;
1242  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
1243  path = path.AppendASCII("extensions")
1244      .AppendASCII("permissions")
1245      .AppendASCII("unknown");
1246
1247  ASSERT_TRUE(file_util::PathExists(path));
1248
1249  PackAndInstallExtension(path, true);
1250
1251  EXPECT_EQ(0u, GetErrors().size());
1252  EXPECT_EQ(1u, service_->extensions()->size());
1253  const Extension* extension = service_->extensions()->at(0);
1254  std::string extension_id = extension->id();
1255
1256  ExtensionPrefs* prefs = service_->extension_prefs();
1257
1258  std::set<std::string> expected_api_permissions;
1259  ExtensionExtent expected_host_permissions;
1260
1261  expected_api_permissions.insert("tabs");
1262  AddPattern(&expected_host_permissions, "http://*.google.com/*");
1263  AddPattern(&expected_host_permissions, "https://*.google.com/*");
1264  AddPattern(&expected_host_permissions, "http://*.google.com.hk/*");
1265  AddPattern(&expected_host_permissions, "http://www.example.com/*");
1266
1267  std::set<std::string> api_permissions;
1268  std::set<std::string> host_permissions;
1269
1270  // Test that the extension is disabled when an API permission is missing from
1271  // the extension's granted api permissions preference. (This simulates
1272  // updating the browser to a version which recognizes a new API permission).
1273  SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions);
1274
1275  service_->ReloadExtensions();
1276
1277  EXPECT_EQ(1u, service_->disabled_extensions()->size());
1278  extension = service_->disabled_extensions()->at(0);
1279
1280  ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::DISABLED);
1281  ASSERT_TRUE(prefs->DidExtensionEscalatePermissions(extension_id));
1282
1283  // Now grant and re-enable the extension, making sure the prefs are updated.
1284  service_->GrantPermissionsAndEnableExtension(extension);
1285
1286  ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
1287  ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
1288
1289  std::set<std::string> current_api_permissions;
1290  ExtensionExtent current_host_permissions;
1291  bool current_full_access;
1292
1293  ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
1294                                           &current_full_access,
1295                                           &current_api_permissions,
1296                                           &current_host_permissions));
1297
1298  ASSERT_FALSE(current_full_access);
1299  ASSERT_EQ(expected_api_permissions, current_api_permissions);
1300  AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
1301
1302  // Tests that the extension is disabled when a host permission is missing from
1303  // the extension's granted host permissions preference. (This simulates
1304  // updating the browser to a version which recognizes additional host
1305  // permissions).
1306  api_permissions.clear();
1307  host_permissions.clear();
1308  current_api_permissions.clear();
1309  current_host_permissions.ClearPaths();
1310
1311  api_permissions.insert("tabs");
1312  host_permissions.insert("http://*.google.com/*");
1313  host_permissions.insert("https://*.google.com/*");
1314  host_permissions.insert("http://*.google.com.hk/*");
1315
1316  SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions);
1317  SetPrefStringSet(extension_id, "granted_permissions.host", host_permissions);
1318
1319  service_->ReloadExtensions();
1320
1321  EXPECT_EQ(1u, service_->disabled_extensions()->size());
1322  extension = service_->disabled_extensions()->at(0);
1323
1324  ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::DISABLED);
1325  ASSERT_TRUE(prefs->DidExtensionEscalatePermissions(extension_id));
1326
1327  // Now grant and re-enable the extension, making sure the prefs are updated.
1328  service_->GrantPermissionsAndEnableExtension(extension);
1329
1330  ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
1331  ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
1332
1333  ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
1334                                           &current_full_access,
1335                                           &current_api_permissions,
1336                                           &current_host_permissions));
1337
1338  ASSERT_FALSE(current_full_access);
1339  ASSERT_EQ(expected_api_permissions, current_api_permissions);
1340  AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
1341
1342  // Tests that the granted permissions preferences are initialized when
1343  // migrating from the old pref schema.
1344  current_api_permissions.clear();
1345  current_host_permissions.ClearPaths();
1346
1347  ClearPref(extension_id, "granted_permissions");
1348
1349  service_->ReloadExtensions();
1350
1351  EXPECT_EQ(1u, service_->extensions()->size());
1352  extension = service_->extensions()->at(0);
1353
1354  ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
1355  ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
1356
1357  ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
1358                                           &current_full_access,
1359                                           &current_api_permissions,
1360                                           &current_host_permissions));
1361
1362  ASSERT_FALSE(current_full_access);
1363  ASSERT_EQ(expected_api_permissions, current_api_permissions);
1364  AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
1365}
1366
1367// Test Packaging and installing an extension.
1368TEST_F(ExtensionServiceTest, PackExtension) {
1369  InitializeEmptyExtensionService();
1370  FilePath extensions_path;
1371  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1372  extensions_path = extensions_path.AppendASCII("extensions");
1373  FilePath input_directory = extensions_path
1374      .AppendASCII("good")
1375      .AppendASCII("Extensions")
1376      .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
1377      .AppendASCII("1.0.0.0");
1378
1379  ScopedTempDir temp_dir;
1380  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1381  FilePath output_directory = temp_dir.path();
1382
1383  FilePath crx_path(output_directory.AppendASCII("ex1.crx"));
1384  FilePath privkey_path(output_directory.AppendASCII("privkey.pem"));
1385
1386  scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
1387  ASSERT_TRUE(creator->Run(input_directory, crx_path, FilePath(),
1388      privkey_path));
1389
1390  ASSERT_TRUE(file_util::PathExists(privkey_path));
1391  InstallExtension(crx_path, true);
1392
1393  // Try packing with invalid paths.
1394  creator.reset(new ExtensionCreator());
1395  ASSERT_FALSE(creator->Run(FilePath(), FilePath(), FilePath(), FilePath()));
1396
1397  // Try packing an empty directory. Should fail because an empty directory is
1398  // not a valid extension.
1399  ScopedTempDir temp_dir2;
1400  ASSERT_TRUE(temp_dir2.CreateUniqueTempDir());
1401  creator.reset(new ExtensionCreator());
1402  ASSERT_FALSE(creator->Run(temp_dir2.path(), crx_path, privkey_path,
1403                            FilePath()));
1404
1405  // Try packing with an invalid manifest.
1406  std::string invalid_manifest_content = "I am not a manifest.";
1407  ASSERT_TRUE(file_util::WriteFile(
1408      temp_dir2.path().Append(Extension::kManifestFilename),
1409      invalid_manifest_content.c_str(), invalid_manifest_content.size()));
1410  creator.reset(new ExtensionCreator());
1411  ASSERT_FALSE(creator->Run(temp_dir2.path(), crx_path, privkey_path,
1412                            FilePath()));
1413}
1414
1415// Test Packaging and installing an extension whose name contains punctuation.
1416TEST_F(ExtensionServiceTest, PackPunctuatedExtension) {
1417  InitializeEmptyExtensionService();
1418  FilePath extensions_path;
1419  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1420  extensions_path = extensions_path.AppendASCII("extensions");
1421  FilePath input_directory = extensions_path
1422      .AppendASCII("good")
1423      .AppendASCII("Extensions")
1424      .AppendASCII(good0)
1425      .AppendASCII("1.0.0.0");
1426
1427  ScopedTempDir temp_dir;
1428  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1429
1430  // Extension names containing punctuation, and the expected names for the
1431  // packed extensions.
1432  const FilePath punctuated_names[] = {
1433    FilePath(FilePath::StringType(
1434        FILE_PATH_LITERAL("this.extensions.name.has.periods"))),
1435    FilePath(FilePath::StringType(
1436        FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod"))),
1437    NormalizeSeparators(FilePath(FilePath::StringType(
1438        FILE_PATH_LITERAL("thisextensionhasaslashinitsname/")))),
1439  };
1440  const FilePath expected_crx_names[] = {
1441    FilePath(FilePath::StringType(
1442        FILE_PATH_LITERAL("this.extensions.name.has.periods.crx"))),
1443    FilePath(FilePath::StringType(
1444        FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod.crx"))),
1445    FilePath(FilePath::StringType(
1446        FILE_PATH_LITERAL("thisextensionhasaslashinitsname.crx"))),
1447  };
1448  const FilePath expected_private_key_names[] = {
1449    FilePath(FilePath::StringType(
1450        FILE_PATH_LITERAL("this.extensions.name.has.periods.pem"))),
1451    FilePath(FilePath::StringType(
1452        FILE_PATH_LITERAL(".thisextensionsnamestartswithaperiod.pem"))),
1453    FilePath(FilePath::StringType(
1454        FILE_PATH_LITERAL("thisextensionhasaslashinitsname.pem"))),
1455  };
1456
1457  for (size_t i = 0; i < arraysize(punctuated_names); ++i) {
1458    SCOPED_TRACE(punctuated_names[i].value().c_str());
1459    FilePath output_dir = temp_dir.path().Append(punctuated_names[i]);
1460
1461    // Copy the extension into the output directory, as PackExtensionJob doesn't
1462    // let us choose where to output the packed extension.
1463    ASSERT_TRUE(file_util::CopyDirectory(input_directory, output_dir, true));
1464
1465    FilePath expected_crx_path = temp_dir.path().Append(expected_crx_names[i]);
1466    FilePath expected_private_key_path =
1467        temp_dir.path().Append(expected_private_key_names[i]);
1468    PackExtensionTestClient pack_client(expected_crx_path,
1469                                        expected_private_key_path);
1470    scoped_refptr<PackExtensionJob> packer(new PackExtensionJob(&pack_client,
1471                                                                output_dir,
1472                                                                FilePath()));
1473    packer->Start();
1474
1475    // The packer will post a notification task to the current thread's message
1476    // loop when it is finished.  We manually run the loop here so that we
1477    // block and catch the notification; otherwise, the process would exit.
1478    // This call to |Run()| is matched by a call to |Quit()| in the
1479    // |PackExtensionTestClient|'s notification handling code.
1480    MessageLoop::current()->Run();
1481
1482    if (HasFatalFailure())
1483      return;
1484
1485    InstallExtension(expected_crx_path, true);
1486  }
1487}
1488
1489// Test Packaging and installing an extension using an openssl generated key.
1490// The openssl is generated with the following:
1491// > openssl genrsa -out privkey.pem 1024
1492// > openssl pkcs8 -topk8 -nocrypt -in privkey.pem -out privkey_asn1.pem
1493// The privkey.pem is a PrivateKey, and the pcks8 -topk8 creates a
1494// PrivateKeyInfo ASN.1 structure, we our RSAPrivateKey expects.
1495TEST_F(ExtensionServiceTest, PackExtensionOpenSSLKey) {
1496  InitializeEmptyExtensionService();
1497  FilePath extensions_path;
1498  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1499  extensions_path = extensions_path.AppendASCII("extensions");
1500  FilePath input_directory = extensions_path
1501      .AppendASCII("good")
1502      .AppendASCII("Extensions")
1503      .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
1504      .AppendASCII("1.0.0.0");
1505  FilePath privkey_path(extensions_path.AppendASCII(
1506      "openssl_privkey_asn1.pem"));
1507  ASSERT_TRUE(file_util::PathExists(privkey_path));
1508
1509  ScopedTempDir temp_dir;
1510  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
1511  FilePath output_directory = temp_dir.path();
1512
1513  FilePath crx_path(output_directory.AppendASCII("ex1.crx"));
1514
1515  scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
1516  ASSERT_TRUE(creator->Run(input_directory, crx_path, privkey_path,
1517      FilePath()));
1518
1519  InstallExtension(crx_path, true);
1520}
1521
1522TEST_F(ExtensionServiceTest, InstallTheme) {
1523  InitializeEmptyExtensionService();
1524  FilePath extensions_path;
1525  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1526  extensions_path = extensions_path.AppendASCII("extensions");
1527
1528  // A theme.
1529  FilePath path = extensions_path.AppendASCII("theme.crx");
1530  InstallExtension(path, true);
1531  int pref_count = 0;
1532  ValidatePrefKeyCount(++pref_count);
1533  ValidateIntegerPref(theme_crx, "state", Extension::ENABLED);
1534  ValidateIntegerPref(theme_crx, "location", Extension::INTERNAL);
1535
1536  // A theme when extensions are disabled. Themes can be installed, even when
1537  // extensions are disabled.
1538  set_extensions_enabled(false);
1539  path = extensions_path.AppendASCII("theme2.crx");
1540  InstallExtension(path, true);
1541  ValidatePrefKeyCount(++pref_count);
1542  ValidateIntegerPref(theme2_crx, "state", Extension::ENABLED);
1543  ValidateIntegerPref(theme2_crx, "location", Extension::INTERNAL);
1544
1545  // A theme with extension elements. Themes cannot have extension elements so
1546  // this test should fail.
1547  set_extensions_enabled(true);
1548  path = extensions_path.AppendASCII("theme_with_extension.crx");
1549  InstallExtension(path, false);
1550  ValidatePrefKeyCount(pref_count);
1551
1552  // A theme with image resources missing (misspelt path).
1553  path = extensions_path.AppendASCII("theme_missing_image.crx");
1554  InstallExtension(path, false);
1555  ValidatePrefKeyCount(pref_count);
1556}
1557
1558TEST_F(ExtensionServiceTest, LoadLocalizedTheme) {
1559  // Load.
1560  InitializeEmptyExtensionService();
1561  FilePath extension_path;
1562  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extension_path));
1563  extension_path = extension_path
1564      .AppendASCII("extensions")
1565      .AppendASCII("theme_i18n");
1566
1567  service_->LoadExtension(extension_path);
1568  loop_.RunAllPending();
1569  EXPECT_EQ(0u, GetErrors().size());
1570  ASSERT_EQ(1u, loaded_.size());
1571  EXPECT_EQ(1u, service_->extensions()->size());
1572  EXPECT_EQ("name", service_->extensions()->at(0)->name());
1573  EXPECT_EQ("description", service_->extensions()->at(0)->description());
1574}
1575
1576TEST_F(ExtensionServiceTest, InstallLocalizedTheme) {
1577  InitializeEmptyExtensionService();
1578  FilePath theme_path;
1579  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &theme_path));
1580  theme_path = theme_path
1581      .AppendASCII("extensions")
1582      .AppendASCII("theme_i18n");
1583
1584  PackAndInstallExtension(theme_path, true);
1585
1586  EXPECT_EQ(0u, GetErrors().size());
1587  EXPECT_EQ(1u, service_->extensions()->size());
1588  EXPECT_EQ("name", service_->extensions()->at(0)->name());
1589  EXPECT_EQ("description", service_->extensions()->at(0)->description());
1590}
1591
1592TEST_F(ExtensionServiceTest, InstallApps) {
1593  InitializeEmptyExtensionService();
1594  FilePath extensions_path;
1595  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1596  extensions_path = extensions_path.AppendASCII("extensions");
1597
1598  // An empty app.
1599  PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
1600  int pref_count = 0;
1601  ValidatePrefKeyCount(++pref_count);
1602  ASSERT_EQ(1u, service_->extensions()->size());
1603  std::string id = service_->extensions()->at(0)->id();
1604  ValidateIntegerPref(id, "state", Extension::ENABLED);
1605  ValidateIntegerPref(id, "location", Extension::INTERNAL);
1606
1607  // Another app with non-overlapping extent. Should succeed.
1608  PackAndInstallExtension(extensions_path.AppendASCII("app2"), true);
1609  ValidatePrefKeyCount(++pref_count);
1610
1611  // A third app whose extent overlaps the first. Should fail.
1612  PackAndInstallExtension(extensions_path.AppendASCII("app3"), false);
1613  ValidatePrefKeyCount(pref_count);
1614}
1615
1616TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) {
1617  InitializeEmptyExtensionService();
1618  EXPECT_TRUE(service_->extensions()->empty());
1619  EXPECT_TRUE(service_->unlimited_storage_map_.empty());
1620
1621  FilePath extensions_path;
1622  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1623  extensions_path = extensions_path.AppendASCII("extensions");
1624  int pref_count = 0;
1625  ChromeAppCacheService* appcache_service = profile_->GetAppCacheService();
1626
1627  // Install app1 with unlimited storage.
1628  PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
1629  ValidatePrefKeyCount(++pref_count);
1630  ASSERT_EQ(1u, service_->extensions()->size());
1631  const Extension* extension = service_->extensions()->at(0);
1632  const std::string id1 = extension->id();
1633  EXPECT_TRUE(extension->HasApiPermission(
1634                  Extension::kUnlimitedStoragePermission));
1635  EXPECT_TRUE(extension->web_extent().ContainsURL(
1636                  extension->GetFullLaunchURL()));
1637  const GURL origin1(extension->GetFullLaunchURL().GetOrigin());
1638  EXPECT_EQ(kint64max,
1639            appcache_service->storage()->GetOriginQuotaInMemory(origin1));
1640  EXPECT_FALSE(service_->unlimited_storage_map_.empty());
1641
1642  // Install app2 from the same origin with unlimited storage.
1643  PackAndInstallExtension(extensions_path.AppendASCII("app2"), true);
1644  ValidatePrefKeyCount(++pref_count);
1645  ASSERT_EQ(2u, service_->extensions()->size());
1646  extension = service_->extensions()->at(1);
1647  const std::string id2 = extension->id();
1648  EXPECT_TRUE(extension->HasApiPermission(
1649                  Extension::kUnlimitedStoragePermission));
1650  EXPECT_TRUE(extension->web_extent().ContainsURL(
1651                  extension->GetFullLaunchURL()));
1652  const GURL origin2(extension->GetFullLaunchURL().GetOrigin());
1653  EXPECT_EQ(origin1, origin2);
1654  EXPECT_EQ(kint64max,
1655            appcache_service->storage()->GetOriginQuotaInMemory(origin2));
1656  EXPECT_FALSE(service_->unlimited_storage_map_.empty());
1657
1658  // Uninstall one of them, unlimited storage should still be granted
1659  // to the origin.
1660  service_->UninstallExtension(id1, false);
1661  loop_.RunAllPending();
1662  EXPECT_EQ(1u, service_->extensions()->size());
1663  EXPECT_EQ(kint64max,
1664            appcache_service->storage()->GetOriginQuotaInMemory(origin1));
1665  EXPECT_FALSE(service_->unlimited_storage_map_.empty());
1666
1667  // Uninstall the other, unlimited storage should be revoked.
1668  service_->UninstallExtension(id2, false);
1669  loop_.RunAllPending();
1670  EXPECT_EQ(0u, service_->extensions()->size());
1671  EXPECT_EQ(-1L,
1672            appcache_service->storage()->GetOriginQuotaInMemory(origin2));
1673  EXPECT_TRUE(service_->unlimited_storage_map_.empty());
1674}
1675
1676TEST_F(ExtensionServiceTest, InstallAppsAndCheckStorageProtection) {
1677  InitializeEmptyExtensionService();
1678  EXPECT_TRUE(service_->extensions()->empty());
1679  EXPECT_TRUE(service_->protected_storage_map_.empty());
1680
1681  FilePath extensions_path;
1682  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1683  extensions_path = extensions_path.AppendASCII("extensions");
1684  int pref_count = 0;
1685
1686  PackAndInstallExtension(extensions_path.AppendASCII("app1"), true);
1687  ValidatePrefKeyCount(++pref_count);
1688  ASSERT_EQ(1u, service_->extensions()->size());
1689  const Extension* extension = service_->extensions()->at(0);
1690  EXPECT_TRUE(extension->is_app());
1691  const std::string id1 = extension->id();
1692  EXPECT_FALSE(service_->protected_storage_map_.empty());
1693  const GURL origin1(extension->GetFullLaunchURL().GetOrigin());
1694  ASSERT_EQ(1, service_->protected_storage_map_[origin1]);
1695
1696  // App 4 has a different origin (maps.google.com).
1697  PackAndInstallExtension(extensions_path.AppendASCII("app4"), true);
1698  ValidatePrefKeyCount(++pref_count);
1699  ASSERT_EQ(2u, service_->extensions()->size());
1700  extension = service_->extensions()->at(1);
1701  const std::string id2 = extension->id();
1702  EXPECT_FALSE(service_->protected_storage_map_.empty());
1703  const GURL origin2(extension->GetFullLaunchURL().GetOrigin());
1704  ASSERT_NE(origin1, origin2);
1705  ASSERT_EQ(1, service_->protected_storage_map_[origin2]);
1706
1707  service_->UninstallExtension(id1, false);
1708  loop_.RunAllPending();
1709  EXPECT_EQ(1u, service_->extensions()->size());
1710  EXPECT_FALSE(service_->protected_storage_map_.empty());
1711
1712  service_->UninstallExtension(id2, false);
1713  loop_.RunAllPending();
1714
1715  EXPECT_TRUE(service_->extensions()->empty());
1716  EXPECT_TRUE(service_->protected_storage_map_.empty());
1717}
1718
1719// Test that when an extension version is reinstalled, nothing happens.
1720TEST_F(ExtensionServiceTest, Reinstall) {
1721  InitializeEmptyExtensionService();
1722  FilePath extensions_path;
1723  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1724  extensions_path = extensions_path.AppendASCII("extensions");
1725
1726  // A simple extension that should install without error.
1727  FilePath path = extensions_path.AppendASCII("good.crx");
1728  service_->InstallExtension(path);
1729  loop_.RunAllPending();
1730
1731  ASSERT_TRUE(installed_);
1732  ASSERT_EQ(1u, loaded_.size());
1733  ASSERT_EQ(0u, GetErrors().size());
1734  ValidatePrefKeyCount(1);
1735  ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
1736  ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
1737
1738  installed_ = NULL;
1739  loaded_.clear();
1740  ExtensionErrorReporter::GetInstance()->ClearErrors();
1741
1742  // Reinstall the same version, it should overwrite the previous one.
1743  service_->InstallExtension(path);
1744  loop_.RunAllPending();
1745
1746  ASSERT_TRUE(installed_);
1747  ASSERT_EQ(1u, loaded_.size());
1748  ASSERT_EQ(0u, GetErrors().size());
1749  ValidatePrefKeyCount(1);
1750  ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
1751  ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
1752}
1753
1754// Test upgrading a signed extension.
1755TEST_F(ExtensionServiceTest, UpgradeSignedGood) {
1756  InitializeEmptyExtensionService();
1757  FilePath extensions_path;
1758  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1759  extensions_path = extensions_path.AppendASCII("extensions");
1760
1761  FilePath path = extensions_path.AppendASCII("good.crx");
1762  service_->InstallExtension(path);
1763  loop_.RunAllPending();
1764
1765  ASSERT_TRUE(installed_);
1766  ASSERT_EQ(1u, loaded_.size());
1767  ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString());
1768  ASSERT_EQ(0u, GetErrors().size());
1769
1770  // Upgrade to version 2.0
1771  path = extensions_path.AppendASCII("good2.crx");
1772  service_->InstallExtension(path);
1773  loop_.RunAllPending();
1774
1775  ASSERT_TRUE(installed_);
1776  ASSERT_EQ(1u, loaded_.size());
1777  ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
1778  ASSERT_EQ(0u, GetErrors().size());
1779}
1780
1781// Test upgrading a signed extension with a bad signature.
1782TEST_F(ExtensionServiceTest, UpgradeSignedBad) {
1783  InitializeEmptyExtensionService();
1784  FilePath extensions_path;
1785  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1786  extensions_path = extensions_path.AppendASCII("extensions");
1787
1788  FilePath path = extensions_path.AppendASCII("good.crx");
1789  service_->InstallExtension(path);
1790  loop_.RunAllPending();
1791
1792  ASSERT_TRUE(installed_);
1793  ASSERT_EQ(1u, loaded_.size());
1794  ASSERT_EQ(0u, GetErrors().size());
1795  installed_ = NULL;
1796
1797  // Try upgrading with a bad signature. This should fail during the unpack,
1798  // because the key will not match the signature.
1799  path = extensions_path.AppendASCII("good2_bad_signature.crx");
1800  service_->InstallExtension(path);
1801  loop_.RunAllPending();
1802
1803  ASSERT_FALSE(installed_);
1804  ASSERT_EQ(1u, loaded_.size());
1805  ASSERT_EQ(1u, GetErrors().size());
1806}
1807
1808// Test a normal update via the UpdateExtension API
1809TEST_F(ExtensionServiceTest, UpdateExtension) {
1810  InitializeEmptyExtensionService();
1811  FilePath extensions_path;
1812  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1813  extensions_path = extensions_path.AppendASCII("extensions");
1814
1815  FilePath path = extensions_path.AppendASCII("good.crx");
1816
1817  InstallExtension(path, true);
1818  const Extension* good = service_->extensions()->at(0);
1819  ASSERT_EQ("1.0.0.0", good->VersionString());
1820  ASSERT_EQ(good_crx, good->id());
1821
1822  path = extensions_path.AppendASCII("good2.crx");
1823  UpdateExtension(good_crx, path, ENABLED);
1824  ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
1825}
1826
1827// Test updating a not-already-installed extension - this should fail
1828TEST_F(ExtensionServiceTest, UpdateNotInstalledExtension) {
1829  InitializeEmptyExtensionService();
1830  FilePath extensions_path;
1831  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1832  extensions_path = extensions_path.AppendASCII("extensions");
1833
1834  FilePath path = extensions_path.AppendASCII("good.crx");
1835  UpdateExtension(good_crx, path, UPDATED);
1836  loop_.RunAllPending();
1837
1838  ASSERT_EQ(0u, service_->extensions()->size());
1839  ASSERT_FALSE(installed_);
1840  ASSERT_EQ(0u, loaded_.size());
1841}
1842
1843// Makes sure you can't downgrade an extension via UpdateExtension
1844TEST_F(ExtensionServiceTest, UpdateWillNotDowngrade) {
1845  InitializeEmptyExtensionService();
1846  FilePath extensions_path;
1847  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1848  extensions_path = extensions_path.AppendASCII("extensions");
1849
1850  FilePath path = extensions_path.AppendASCII("good2.crx");
1851
1852  InstallExtension(path, true);
1853  const Extension* good = service_->extensions()->at(0);
1854  ASSERT_EQ("1.0.0.1", good->VersionString());
1855  ASSERT_EQ(good_crx, good->id());
1856
1857  // Change path from good2.crx -> good.crx
1858  path = extensions_path.AppendASCII("good.crx");
1859  UpdateExtension(good_crx, path, FAILED);
1860  ASSERT_EQ("1.0.0.1", service_->extensions()->at(0)->VersionString());
1861}
1862
1863// Make sure calling update with an identical version does nothing
1864TEST_F(ExtensionServiceTest, UpdateToSameVersionIsNoop) {
1865  InitializeEmptyExtensionService();
1866  FilePath extensions_path;
1867  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1868  extensions_path = extensions_path.AppendASCII("extensions");
1869
1870  FilePath path = extensions_path.AppendASCII("good.crx");
1871
1872  InstallExtension(path, true);
1873  const Extension* good = service_->extensions()->at(0);
1874  ASSERT_EQ(good_crx, good->id());
1875  UpdateExtension(good_crx, path, FAILED_SILENTLY);
1876}
1877
1878// Tests that updating an extension does not clobber old state.
1879TEST_F(ExtensionServiceTest, UpdateExtensionPreservesState) {
1880  InitializeEmptyExtensionService();
1881  FilePath extensions_path;
1882  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1883  extensions_path = extensions_path.AppendASCII("extensions");
1884
1885  FilePath path = extensions_path.AppendASCII("good.crx");
1886
1887  InstallExtension(path, true);
1888  const Extension* good = service_->extensions()->at(0);
1889  ASSERT_EQ("1.0.0.0", good->VersionString());
1890  ASSERT_EQ(good_crx, good->id());
1891
1892  // Disable it and allow it to run in incognito. These settings should carry
1893  // over to the updated version.
1894  service_->DisableExtension(good->id());
1895  service_->SetIsIncognitoEnabled(good, true);
1896
1897  path = extensions_path.AppendASCII("good2.crx");
1898  UpdateExtension(good_crx, path, INSTALLED);
1899  ASSERT_EQ(1u, service_->disabled_extensions()->size());
1900  const Extension* good2 = service_->disabled_extensions()->at(0);
1901  ASSERT_EQ("1.0.0.1", good2->version()->GetString());
1902  EXPECT_TRUE(service_->IsIncognitoEnabled(good2));
1903}
1904
1905// Tests that updating preserves extension location.
1906TEST_F(ExtensionServiceTest, UpdateExtensionPreservesLocation) {
1907  InitializeEmptyExtensionService();
1908  FilePath extensions_path;
1909  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
1910  extensions_path = extensions_path.AppendASCII("extensions");
1911
1912  FilePath path = extensions_path.AppendASCII("good.crx");
1913
1914  InstallExtension(path, true);
1915  const Extension* good = service_->extensions()->at(0);
1916
1917  ASSERT_EQ("1.0.0.0", good->VersionString());
1918  ASSERT_EQ(good_crx, good->id());
1919
1920  // Simulate non-internal location.
1921  const_cast<Extension*>(good)->location_ = Extension::EXTERNAL_PREF;
1922
1923  path = extensions_path.AppendASCII("good2.crx");
1924  UpdateExtension(good_crx, path, ENABLED);
1925  const Extension* good2 = service_->extensions()->at(0);
1926  ASSERT_EQ("1.0.0.1", good2->version()->GetString());
1927  EXPECT_EQ(good2->location(), Extension::EXTERNAL_PREF);
1928}
1929
1930// Makes sure that LOAD extension types can downgrade.
1931TEST_F(ExtensionServiceTest, LoadExtensionsCanDowngrade) {
1932  InitializeEmptyExtensionService();
1933
1934  ScopedTempDir temp;
1935  ASSERT_TRUE(temp.CreateUniqueTempDir());
1936
1937  // We'll write the extension manifest dynamically to a temporary path
1938  // to make it easier to change the version number.
1939  FilePath extension_path = temp.path();
1940  FilePath manifest_path = extension_path.Append(Extension::kManifestFilename);
1941  ASSERT_FALSE(file_util::PathExists(manifest_path));
1942
1943  // Start with version 2.0.
1944  DictionaryValue manifest;
1945  manifest.SetString("version", "2.0");
1946  manifest.SetString("name", "LOAD Downgrade Test");
1947
1948  JSONFileValueSerializer serializer(manifest_path);
1949  ASSERT_TRUE(serializer.Serialize(manifest));
1950
1951  service_->LoadExtension(extension_path);
1952  loop_.RunAllPending();
1953
1954  EXPECT_EQ(0u, GetErrors().size());
1955  ASSERT_EQ(1u, loaded_.size());
1956  EXPECT_EQ(Extension::LOAD, loaded_[0]->location());
1957  EXPECT_EQ(1u, service_->extensions()->size());
1958  EXPECT_EQ("2.0", loaded_[0]->VersionString());
1959
1960  // Now set the version number to 1.0, reload the extensions and verify that
1961  // the downgrade was accepted.
1962  manifest.SetString("version", "1.0");
1963  ASSERT_TRUE(serializer.Serialize(manifest));
1964
1965  service_->LoadExtension(extension_path);
1966  loop_.RunAllPending();
1967
1968  EXPECT_EQ(0u, GetErrors().size());
1969  ASSERT_EQ(1u, loaded_.size());
1970  EXPECT_EQ(Extension::LOAD, loaded_[0]->location());
1971  EXPECT_EQ(1u, service_->extensions()->size());
1972  EXPECT_EQ("1.0", loaded_[0]->VersionString());
1973}
1974
1975namespace {
1976
1977bool IsExtension(const Extension& extension) {
1978  return extension.GetType() == Extension::TYPE_EXTENSION;
1979}
1980
1981}  // namespace
1982
1983// Test adding a pending extension.
1984TEST_F(ExtensionServiceTest, AddPendingExtensionFromSync) {
1985  InitializeEmptyExtensionService();
1986
1987  const std::string kFakeId("fake-id");
1988  const GURL kFakeUpdateURL("http:://fake.update/url");
1989  const bool kFakeInstallSilently(true);
1990  const Extension::State kFakeInitialState(Extension::ENABLED);
1991  const bool kFakeInitialIncognitoEnabled(false);
1992
1993  service_->AddPendingExtensionFromSync(
1994      kFakeId, kFakeUpdateURL, &IsExtension,
1995      kFakeInstallSilently, kFakeInitialState, kFakeInitialIncognitoEnabled);
1996  PendingExtensionMap::const_iterator it =
1997      service_->pending_extensions().find(kFakeId);
1998  ASSERT_TRUE(it != service_->pending_extensions().end());
1999  EXPECT_EQ(kFakeUpdateURL, it->second.update_url);
2000  EXPECT_EQ(&IsExtension, it->second.should_install_extension);
2001  EXPECT_EQ(kFakeInstallSilently, it->second.install_silently);
2002}
2003
2004namespace {
2005const char kGoodId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
2006const char kGoodUpdateURL[] = "http://good.update/url";
2007const bool kGoodIsFromSync = true;
2008const bool kGoodInstallSilently = true;
2009const Extension::State kGoodInitialState = Extension::DISABLED;
2010const bool kGoodInitialIncognitoEnabled = true;
2011}  // namespace
2012
2013// Test updating a pending extension.
2014TEST_F(ExtensionServiceTest, UpdatePendingExtension) {
2015  InitializeEmptyExtensionService();
2016  service_->AddPendingExtensionFromSync(
2017      kGoodId, GURL(kGoodUpdateURL), &IsExtension,
2018      kGoodInstallSilently, kGoodInitialState,
2019      kGoodInitialIncognitoEnabled);
2020  EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId));
2021
2022  FilePath extensions_path;
2023  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2024  extensions_path = extensions_path.AppendASCII("extensions");
2025  FilePath path = extensions_path.AppendASCII("good.crx");
2026  UpdateExtension(kGoodId, path, INSTALLED);
2027
2028  EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
2029
2030  const Extension* extension = service_->GetExtensionById(kGoodId, true);
2031  ASSERT_TRUE(extension);
2032
2033  bool enabled = service_->GetExtensionById(kGoodId, false);
2034  EXPECT_EQ(kGoodInitialState == Extension::ENABLED, enabled);
2035  EXPECT_EQ(kGoodInitialState,
2036            service_->extension_prefs()->GetExtensionState(extension->id()));
2037  EXPECT_EQ(kGoodInitialIncognitoEnabled,
2038            service_->IsIncognitoEnabled(extension));
2039}
2040
2041namespace {
2042
2043bool IsTheme(const Extension& extension) {
2044  return extension.is_theme();
2045}
2046
2047}  // namespace
2048
2049// Test updating a pending theme.
2050TEST_F(ExtensionServiceTest, UpdatePendingTheme) {
2051  InitializeEmptyExtensionService();
2052  service_->AddPendingExtensionFromSync(
2053      theme_crx, GURL(), &IsTheme,
2054      false, Extension::ENABLED, false);
2055  EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
2056
2057  FilePath extensions_path;
2058  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2059  extensions_path = extensions_path.AppendASCII("extensions");
2060  FilePath path = extensions_path.AppendASCII("theme.crx");
2061  UpdateExtension(theme_crx, path, ENABLED);
2062
2063  EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
2064
2065  const Extension* extension = service_->GetExtensionById(theme_crx, true);
2066  ASSERT_TRUE(extension);
2067
2068  EXPECT_EQ(Extension::ENABLED,
2069            service_->extension_prefs()->GetExtensionState(extension->id()));
2070  EXPECT_FALSE(service_->IsIncognitoEnabled(extension));
2071}
2072
2073// Test updating a pending CRX as if the source is an external extension
2074// with an update URL.  In this case we don't know if the CRX is a theme
2075// or not.
2076TEST_F(ExtensionServiceTest, UpdatePendingExternalCrx) {
2077  InitializeEmptyExtensionService();
2078  service_->AddPendingExtensionFromExternalUpdateUrl(
2079      theme_crx, GURL(), Extension::EXTERNAL_PREF_DOWNLOAD);
2080
2081  EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
2082
2083  FilePath extensions_path;
2084  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2085  extensions_path = extensions_path.AppendASCII("extensions");
2086  FilePath path = extensions_path.AppendASCII("theme.crx");
2087  UpdateExtension(theme_crx, path, ENABLED);
2088
2089  EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
2090
2091  const Extension* extension = service_->GetExtensionById(theme_crx, true);
2092  ASSERT_TRUE(extension);
2093
2094  EXPECT_EQ(Extension::ENABLED,
2095            service_->extension_prefs()->GetExtensionState(extension->id()));
2096  EXPECT_FALSE(service_->IsIncognitoEnabled(extension));
2097}
2098
2099// Test updating a pending CRX as if the source is an external extension
2100// with an update URL.  The external update should overwrite a sync update,
2101// but a sync update should not overwrite a non-sync update.
2102TEST_F(ExtensionServiceTest, UpdatePendingExternalCrxWinsOverSync) {
2103  InitializeEmptyExtensionService();
2104
2105  // Add a crx to be installed from the update mechanism.
2106  service_->AddPendingExtensionFromSync(
2107      kGoodId, GURL(kGoodUpdateURL), &IsExtension,
2108      kGoodInstallSilently, kGoodInitialState,
2109      kGoodInitialIncognitoEnabled);
2110
2111  // Check that there is a pending crx, with is_from_sync set to true.
2112  PendingExtensionMap::const_iterator it;
2113  it = service_->pending_extensions().find(kGoodId);
2114  ASSERT_TRUE(it != service_->pending_extensions().end());
2115  EXPECT_TRUE(it->second.is_from_sync);
2116
2117  // Add a crx to be updated, with the same ID, from a non-sync source.
2118  service_->AddPendingExtensionFromExternalUpdateUrl(
2119      kGoodId, GURL(kGoodUpdateURL), Extension::EXTERNAL_PREF_DOWNLOAD);
2120
2121  // Check that there is a pending crx, with is_from_sync set to false.
2122  it = service_->pending_extensions().find(kGoodId);
2123  ASSERT_TRUE(it != service_->pending_extensions().end());
2124  EXPECT_FALSE(it->second.is_from_sync);
2125
2126  // Add a crx to be installed from the update mechanism.
2127  service_->AddPendingExtensionFromSync(
2128      kGoodId, GURL(kGoodUpdateURL), &IsExtension,
2129      kGoodInstallSilently, kGoodInitialState,
2130      kGoodInitialIncognitoEnabled);
2131
2132  // Check that the external, non-sync update was not overridden.
2133  it = service_->pending_extensions().find(kGoodId);
2134  ASSERT_TRUE(it != service_->pending_extensions().end());
2135  EXPECT_FALSE(it->second.is_from_sync);
2136}
2137
2138// Updating a theme should fail if the updater is explicitly told that
2139// the CRX is not a theme.
2140TEST_F(ExtensionServiceTest, UpdatePendingCrxThemeMismatch) {
2141  InitializeEmptyExtensionService();
2142  service_->AddPendingExtensionFromSync(
2143      theme_crx, GURL(), &IsExtension,
2144      true, Extension::ENABLED, false);
2145
2146  EXPECT_TRUE(ContainsKey(service_->pending_extensions(), theme_crx));
2147
2148  FilePath extensions_path;
2149  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2150  extensions_path = extensions_path.AppendASCII("extensions");
2151  FilePath path = extensions_path.AppendASCII("theme.crx");
2152  UpdateExtension(theme_crx, path, FAILED_SILENTLY);
2153
2154  EXPECT_FALSE(ContainsKey(service_->pending_extensions(), theme_crx));
2155
2156  const Extension* extension = service_->GetExtensionById(theme_crx, true);
2157  ASSERT_FALSE(extension);
2158}
2159
2160// TODO(akalin): Test updating a pending extension non-silently once
2161// we can mock out ExtensionInstallUI and inject our version into
2162// UpdateExtension().
2163
2164// Test updating a pending extension which fails the should-install test.
2165TEST_F(ExtensionServiceTest, UpdatePendingExtensionFailedShouldInstallTest) {
2166  InitializeEmptyExtensionService();
2167  // Add pending extension with a flipped is_theme.
2168  service_->AddPendingExtensionFromSync(
2169      kGoodId, GURL(kGoodUpdateURL), &IsTheme,
2170      kGoodInstallSilently, kGoodInitialState,
2171      kGoodInitialIncognitoEnabled);
2172  EXPECT_TRUE(ContainsKey(service_->pending_extensions(), kGoodId));
2173
2174  FilePath extensions_path;
2175  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2176  extensions_path = extensions_path.AppendASCII("extensions");
2177  FilePath path = extensions_path.AppendASCII("good.crx");
2178  UpdateExtension(kGoodId, path, UPDATED);
2179
2180  // TODO(akalin): Figure out how to check that the extensions
2181  // directory is cleaned up properly in OnExtensionInstalled().
2182
2183  EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
2184}
2185
2186// TODO(akalin): Figure out how to test that installs of pending
2187// unsyncable extensions are blocked.
2188
2189// Test updating a pending extension for one that is not pending.
2190TEST_F(ExtensionServiceTest, UpdatePendingExtensionNotPending) {
2191  InitializeEmptyExtensionService();
2192
2193  FilePath extensions_path;
2194  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2195  extensions_path = extensions_path.AppendASCII("extensions");
2196  FilePath path = extensions_path.AppendASCII("good.crx");
2197  UpdateExtension(kGoodId, path, UPDATED);
2198
2199  EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
2200}
2201
2202// Test updating a pending extension for one that is already
2203// installed.
2204TEST_F(ExtensionServiceTest, UpdatePendingExtensionAlreadyInstalled) {
2205  InitializeEmptyExtensionService();
2206
2207  FilePath extensions_path;
2208  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2209  extensions_path = extensions_path.AppendASCII("extensions");
2210  FilePath path = extensions_path.AppendASCII("good.crx");
2211  InstallExtension(path, true);
2212  ASSERT_EQ(1u, service_->extensions()->size());
2213  const Extension* good = service_->extensions()->at(0);
2214
2215  EXPECT_FALSE(good->is_theme());
2216
2217  // Use AddPendingExtensionInternal() as AddPendingExtension() would
2218  // balk.
2219  service_->AddPendingExtensionInternal(
2220      good->id(), good->update_url(), &IsExtension,
2221      kGoodIsFromSync, kGoodInstallSilently, kGoodInitialState,
2222      kGoodInitialIncognitoEnabled, Extension::INTERNAL);
2223  UpdateExtension(good->id(), path, INSTALLED);
2224
2225  EXPECT_FALSE(ContainsKey(service_->pending_extensions(), kGoodId));
2226}
2227
2228// Test pref settings for blacklist and unblacklist extensions.
2229TEST_F(ExtensionServiceTest, SetUnsetBlacklistInPrefs) {
2230  InitializeEmptyExtensionService();
2231  std::vector<std::string> blacklist;
2232  blacklist.push_back(good0);
2233  blacklist.push_back("invalid_id");  // an invalid id
2234  blacklist.push_back(good1);
2235  service_->UpdateExtensionBlacklist(blacklist);
2236  // Make sure pref is updated
2237  loop_.RunAllPending();
2238
2239  // blacklist is set for good0,1,2
2240  ValidateBooleanPref(good0, "blacklist", true);
2241  ValidateBooleanPref(good1, "blacklist", true);
2242  // invalid_id should not be inserted to pref.
2243  EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist"));
2244
2245  // remove good1, add good2
2246  blacklist.pop_back();
2247  blacklist.push_back(good2);
2248
2249  service_->UpdateExtensionBlacklist(blacklist);
2250  // only good0 and good1 should be set
2251  ValidateBooleanPref(good0, "blacklist", true);
2252  EXPECT_FALSE(IsPrefExist(good1, "blacklist"));
2253  ValidateBooleanPref(good2, "blacklist", true);
2254  EXPECT_FALSE(IsPrefExist("invalid_id", "blacklist"));
2255}
2256
2257// Unload installed extension from blacklist.
2258TEST_F(ExtensionServiceTest, UnloadBlacklistedExtension) {
2259  InitializeEmptyExtensionService();
2260  FilePath extensions_path;
2261  EXPECT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2262  extensions_path = extensions_path.AppendASCII("extensions");
2263
2264  FilePath path = extensions_path.AppendASCII("good.crx");
2265
2266  InstallExtension(path, true);
2267  const Extension* good = service_->extensions()->at(0);
2268  EXPECT_EQ(good_crx, good->id());
2269  UpdateExtension(good_crx, path, FAILED_SILENTLY);
2270
2271  std::vector<std::string> blacklist;
2272  blacklist.push_back(good_crx);
2273  service_->UpdateExtensionBlacklist(blacklist);
2274  // Make sure pref is updated
2275  loop_.RunAllPending();
2276
2277  // Now, the good_crx is blacklisted.
2278  ValidateBooleanPref(good_crx, "blacklist", true);
2279  EXPECT_EQ(0u, service_->extensions()->size());
2280
2281  // Remove good_crx from blacklist
2282  blacklist.pop_back();
2283  service_->UpdateExtensionBlacklist(blacklist);
2284  // Make sure pref is updated
2285  loop_.RunAllPending();
2286  // blacklist value should not be set for good_crx
2287  EXPECT_FALSE(IsPrefExist(good_crx, "blacklist"));
2288}
2289
2290// Unload installed extension from blacklist.
2291TEST_F(ExtensionServiceTest, BlacklistedExtensionWillNotInstall) {
2292  InitializeEmptyExtensionService();
2293  std::vector<std::string> blacklist;
2294  blacklist.push_back(good_crx);
2295  service_->UpdateExtensionBlacklist(blacklist);
2296  // Make sure pref is updated
2297  loop_.RunAllPending();
2298
2299  // Now, the good_crx is blacklisted.
2300  ValidateBooleanPref(good_crx, "blacklist", true);
2301
2302  // We can not install good_crx.
2303  FilePath extensions_path;
2304  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2305  extensions_path = extensions_path.AppendASCII("extensions");
2306  FilePath path = extensions_path.AppendASCII("good.crx");
2307  service_->InstallExtension(path);
2308  loop_.RunAllPending();
2309  EXPECT_EQ(0u, service_->extensions()->size());
2310  ValidateBooleanPref(good_crx, "blacklist", true);
2311}
2312
2313// Test loading extensions from the profile directory, except
2314// blacklisted ones.
2315TEST_F(ExtensionServiceTest, WillNotLoadBlacklistedExtensionsFromDirectory) {
2316  // Initialize the test dir with a good Preferences/extensions.
2317  FilePath source_install_dir;
2318  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
2319  source_install_dir = source_install_dir
2320      .AppendASCII("extensions")
2321      .AppendASCII("good")
2322      .AppendASCII("Extensions");
2323  FilePath pref_path = source_install_dir
2324      .DirName()
2325      .AppendASCII("Preferences");
2326  InitializeInstalledExtensionService(pref_path, source_install_dir);
2327
2328  // Blacklist good1.
2329  std::vector<std::string> blacklist;
2330  blacklist.push_back(good1);
2331  service_->UpdateExtensionBlacklist(blacklist);
2332  // Make sure pref is updated
2333  loop_.RunAllPending();
2334
2335  ValidateBooleanPref(good1, "blacklist", true);
2336
2337  // Load extensions.
2338  service_->Init();
2339  loop_.RunAllPending();
2340
2341  std::vector<std::string> errors = GetErrors();
2342  for (std::vector<std::string>::iterator err = errors.begin();
2343    err != errors.end(); ++err) {
2344    LOG(ERROR) << *err;
2345  }
2346  ASSERT_EQ(2u, loaded_.size());
2347
2348  EXPECT_NE(std::string(good1), loaded_[0]->id());
2349  EXPECT_NE(std::string(good1), loaded_[1]->id());
2350}
2351
2352#if defined(OS_CHROMEOS)
2353// Test loading extensions from the profile directory, except
2354// ones with a plugin.
2355TEST_F(ExtensionServiceTest, WillNotLoadPluginExtensionsFromDirectory) {
2356  // Initialize the test dir with a good Preferences/extensions.
2357  FilePath source_install_dir;
2358  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
2359  source_install_dir = source_install_dir
2360      .AppendASCII("extensions")
2361      .AppendASCII("good")
2362      .AppendASCII("Extensions");
2363  FilePath pref_path = source_install_dir
2364      .DirName()
2365      .AppendASCII("Preferences");
2366  InitializeInstalledExtensionService(pref_path, source_install_dir);
2367
2368  // good1 contains a plugin.
2369  // Load extensions.
2370  service_->Init();
2371  loop_.RunAllPending();
2372
2373  std::vector<std::string> errors = GetErrors();
2374  for (std::vector<std::string>::iterator err = errors.begin();
2375    err != errors.end(); ++err) {
2376    LOG(ERROR) << *err;
2377  }
2378  ASSERT_EQ(2u, loaded_.size());
2379
2380  EXPECT_NE(std::string(good1), loaded_[0]->id());
2381  EXPECT_NE(std::string(good1), loaded_[1]->id());
2382}
2383#endif
2384
2385// Will not install extension blacklisted by policy.
2386TEST_F(ExtensionServiceTest, BlacklistedByPolicyWillNotInstall) {
2387  InitializeEmptyExtensionService();
2388
2389  ListValue* whitelist =
2390      profile_->GetPrefs()->GetMutableList(prefs::kExtensionInstallAllowList);
2391  ListValue* blacklist =
2392      profile_->GetPrefs()->GetMutableList(prefs::kExtensionInstallDenyList);
2393  ASSERT_TRUE(whitelist != NULL && blacklist != NULL);
2394
2395  // Blacklist everything.
2396  blacklist->Append(Value::CreateStringValue("*"));
2397
2398  // Blacklist prevents us from installing good_crx.
2399  FilePath extensions_path;
2400  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2401  extensions_path = extensions_path.AppendASCII("extensions");
2402  FilePath path = extensions_path.AppendASCII("good.crx");
2403  service_->InstallExtension(path);
2404  loop_.RunAllPending();
2405  EXPECT_EQ(0u, service_->extensions()->size());
2406
2407  // Now whitelist this particular extension.
2408  whitelist->Append(Value::CreateStringValue(good_crx));
2409
2410  // Ensure we can now install good_crx.
2411  service_->InstallExtension(path);
2412  loop_.RunAllPending();
2413  EXPECT_EQ(1u, service_->extensions()->size());
2414}
2415
2416// Extension blacklisted by policy get unloaded after installing.
2417TEST_F(ExtensionServiceTest, BlacklistedByPolicyRemovedIfRunning) {
2418  InitializeEmptyExtensionService();
2419
2420  // Install good_crx.
2421  FilePath extensions_path;
2422  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2423  extensions_path = extensions_path.AppendASCII("extensions");
2424  FilePath path = extensions_path.AppendASCII("good.crx");
2425  service_->InstallExtension(path);
2426  loop_.RunAllPending();
2427  EXPECT_EQ(1u, service_->extensions()->size());
2428
2429  { // Scope for pref update notification.
2430    PrefService* prefs = profile_->GetPrefs();
2431    ScopedPrefUpdate pref_update(prefs, prefs::kExtensionInstallDenyList);
2432    ListValue* blacklist =
2433        prefs->GetMutableList(prefs::kExtensionInstallDenyList);
2434    ASSERT_TRUE(blacklist != NULL);
2435
2436    // Blacklist this extension.
2437    blacklist->Append(Value::CreateStringValue(good_crx));
2438    prefs->ScheduleSavePersistentPrefs();
2439  }
2440
2441  // Extension should not be running now.
2442  loop_.RunAllPending();
2443  EXPECT_EQ(0u, service_->extensions()->size());
2444}
2445
2446// Tests disabling extensions
2447TEST_F(ExtensionServiceTest, DisableExtension) {
2448  InitializeEmptyExtensionService();
2449  FilePath extensions_path;
2450  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2451  extensions_path = extensions_path.AppendASCII("extensions");
2452
2453  // A simple extension that should install without error.
2454  FilePath path = extensions_path.AppendASCII("good.crx");
2455  InstallExtension(path, true);
2456
2457  const char* extension_id = good_crx;
2458  EXPECT_FALSE(service_->extensions()->empty());
2459  EXPECT_TRUE(service_->GetExtensionById(extension_id, true) != NULL);
2460  EXPECT_TRUE(service_->GetExtensionById(extension_id, false) != NULL);
2461  EXPECT_TRUE(service_->disabled_extensions()->empty());
2462
2463  // Disable it.
2464  service_->DisableExtension(extension_id);
2465
2466  EXPECT_TRUE(service_->extensions()->empty());
2467  EXPECT_TRUE(service_->GetExtensionById(extension_id, true) != NULL);
2468  EXPECT_FALSE(service_->GetExtensionById(extension_id, false) != NULL);
2469  EXPECT_FALSE(service_->disabled_extensions()->empty());
2470}
2471
2472// Tests disabling all extensions (simulating --disable-extensions flag).
2473TEST_F(ExtensionServiceTest, DisableAllExtensions) {
2474  InitializeEmptyExtensionService();
2475
2476  FilePath extensions_path;
2477  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2478  extensions_path = extensions_path.AppendASCII("extensions");
2479
2480  FilePath path = extensions_path.AppendASCII("good.crx");
2481  InstallExtension(path, true);
2482
2483  EXPECT_EQ(1u, service_->extensions()->size());
2484  EXPECT_EQ(0u, service_->disabled_extensions()->size());
2485
2486  // Disable extensions.
2487  service_->set_extensions_enabled(false);
2488  service_->ReloadExtensions();
2489
2490  // There shouldn't be extensions in either list.
2491  EXPECT_EQ(0u, service_->extensions()->size());
2492  EXPECT_EQ(0u, service_->disabled_extensions()->size());
2493
2494  // This shouldn't do anything when all extensions are disabled.
2495  service_->EnableExtension(good_crx);
2496  service_->ReloadExtensions();
2497
2498  // There still shouldn't be extensions in either list.
2499  EXPECT_EQ(0u, service_->extensions()->size());
2500  EXPECT_EQ(0u, service_->disabled_extensions()->size());
2501
2502  // And then re-enable the extensions.
2503  service_->set_extensions_enabled(true);
2504  service_->ReloadExtensions();
2505
2506  EXPECT_EQ(1u, service_->extensions()->size());
2507  EXPECT_EQ(0u, service_->disabled_extensions()->size());
2508}
2509
2510// Tests reloading extensions
2511TEST_F(ExtensionServiceTest, ReloadExtensions) {
2512  InitializeEmptyExtensionService();
2513  FilePath extensions_path;
2514  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2515  extensions_path = extensions_path.AppendASCII("extensions");
2516
2517  // Simple extension that should install without error.
2518  FilePath path = extensions_path.AppendASCII("good.crx");
2519  InstallExtension(path, true);
2520  const char* extension_id = good_crx;
2521  service_->DisableExtension(extension_id);
2522
2523  EXPECT_EQ(0u, service_->extensions()->size());
2524  EXPECT_EQ(1u, service_->disabled_extensions()->size());
2525
2526  service_->ReloadExtensions();
2527
2528  // Extension counts shouldn't change.
2529  EXPECT_EQ(0u, service_->extensions()->size());
2530  EXPECT_EQ(1u, service_->disabled_extensions()->size());
2531
2532  service_->EnableExtension(extension_id);
2533
2534  EXPECT_EQ(1u, service_->extensions()->size());
2535  EXPECT_EQ(0u, service_->disabled_extensions()->size());
2536
2537  // Need to clear |loaded_| manually before reloading as the
2538  // EnableExtension() call above inserted into it and
2539  // UnloadAllExtensions() doesn't send out notifications.
2540  loaded_.clear();
2541  service_->ReloadExtensions();
2542
2543  // Extension counts shouldn't change.
2544  EXPECT_EQ(1u, service_->extensions()->size());
2545  EXPECT_EQ(0u, service_->disabled_extensions()->size());
2546}
2547
2548// Tests uninstalling normal extensions
2549TEST_F(ExtensionServiceTest, UninstallExtension) {
2550  InitializeEmptyExtensionService();
2551  FilePath extensions_path;
2552  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2553  extensions_path = extensions_path.AppendASCII("extensions");
2554
2555  // A simple extension that should install without error.
2556  FilePath path = extensions_path.AppendASCII("good.crx");
2557  InstallExtension(path, true);
2558
2559  // The directory should be there now.
2560  const char* extension_id = good_crx;
2561  FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id);
2562  EXPECT_TRUE(file_util::PathExists(extension_path));
2563
2564  ValidatePrefKeyCount(1);
2565  ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
2566  ValidateIntegerPref(good_crx, "location", Extension::INTERNAL);
2567
2568  // Uninstall it.
2569  service_->UninstallExtension(extension_id, false);
2570  total_successes_ = 0;
2571
2572  // We should get an unload notification.
2573  ASSERT_TRUE(unloaded_id_.length());
2574  EXPECT_EQ(extension_id, unloaded_id_);
2575
2576  ValidatePrefKeyCount(0);
2577
2578  // The extension should not be in the service anymore.
2579  ASSERT_FALSE(service_->GetExtensionById(extension_id, false));
2580  loop_.RunAllPending();
2581
2582  // The directory should be gone.
2583  EXPECT_FALSE(file_util::PathExists(extension_path));
2584}
2585
2586// Tests the uninstaller helper.
2587TEST_F(ExtensionServiceTest, UninstallExtensionHelper) {
2588  InitializeEmptyExtensionService();
2589  FilePath extensions_path;
2590  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2591  extensions_path = extensions_path.AppendASCII("extensions");
2592
2593  // A simple extension that should install without error.
2594  FilePath path = extensions_path.AppendASCII("good.crx");
2595  InstallExtension(path, true);
2596
2597  // The directory should be there now.
2598  const char* extension_id = good_crx;
2599  FilePath extension_path = extensions_install_dir_.AppendASCII(extension_id);
2600  EXPECT_TRUE(file_util::PathExists(extension_path));
2601
2602  bool result = ExtensionService::UninstallExtensionHelper(service_,
2603                                                            extension_id);
2604  total_successes_ = 0;
2605
2606  EXPECT_TRUE(result);
2607
2608  // We should get an unload notification.
2609  ASSERT_TRUE(unloaded_id_.length());
2610  EXPECT_EQ(extension_id, unloaded_id_);
2611
2612  ValidatePrefKeyCount(0);
2613
2614  // The extension should not be in the service anymore.
2615  ASSERT_FALSE(service_->GetExtensionById(extension_id, false));
2616  loop_.RunAllPending();
2617
2618  // The directory should be gone.
2619  EXPECT_FALSE(file_util::PathExists(extension_path));
2620
2621  // Attempt to uninstall again. This should fail as we just removed the
2622  // extension.
2623  result = ExtensionService::UninstallExtensionHelper(service_, extension_id);
2624  EXPECT_FALSE(result);
2625}
2626
2627// Verifies extension state is removed upon uninstall
2628TEST_F(ExtensionServiceTest, ClearExtensionData) {
2629  InitializeEmptyExtensionService();
2630
2631  // Load a test extension.
2632  FilePath path;
2633  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
2634  path = path.AppendASCII("extensions");
2635  path = path.AppendASCII("good.crx");
2636  InstallExtension(path, true);
2637  const Extension* extension = service_->GetExtensionById(good_crx, false);
2638  ASSERT_TRUE(extension);
2639  GURL ext_url(extension->url());
2640  string16 origin_id =
2641      webkit_database::DatabaseUtil::GetOriginIdentifier(ext_url);
2642
2643  // Set a cookie for the extension.
2644  net::CookieMonster* cookie_monster = profile_
2645      ->GetRequestContextForExtensions()->GetCookieStore()->GetCookieMonster();
2646  ASSERT_TRUE(cookie_monster);
2647  net::CookieOptions options;
2648  cookie_monster->SetCookieWithOptions(ext_url, "dummy=value", options);
2649  net::CookieList list = cookie_monster->GetAllCookiesForURL(ext_url);
2650  EXPECT_EQ(1U, list.size());
2651
2652  // Open a database.
2653  webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker();
2654  string16 db_name = UTF8ToUTF16("db");
2655  string16 description = UTF8ToUTF16("db_description");
2656  int64 size;
2657  int64 available;
2658  db_tracker->DatabaseOpened(origin_id, db_name, description, 1, &size,
2659                             &available);
2660  db_tracker->DatabaseClosed(origin_id, db_name);
2661  std::vector<webkit_database::OriginInfo> origins;
2662  db_tracker->GetAllOriginsInfo(&origins);
2663  EXPECT_EQ(1U, origins.size());
2664  EXPECT_EQ(origin_id, origins[0].GetOrigin());
2665
2666  // Create local storage. We only simulate this by creating the backing file
2667  // since webkit is not initialized.
2668  DOMStorageContext* context =
2669      profile_->GetWebKitContext()->dom_storage_context();
2670  FilePath lso_path = context->GetLocalStorageFilePath(origin_id);
2671  EXPECT_TRUE(file_util::CreateDirectory(lso_path.DirName()));
2672  EXPECT_EQ(0, file_util::WriteFile(lso_path, NULL, 0));
2673  EXPECT_TRUE(file_util::PathExists(lso_path));
2674
2675  // Create indexed db. Again, it is enough to only simulate this by creating
2676  // the file on the disk.
2677  IndexedDBContext* idb_context =
2678      profile_->GetWebKitContext()->indexed_db_context();
2679  FilePath idb_path = idb_context->GetIndexedDBFilePath(origin_id);
2680  EXPECT_TRUE(file_util::CreateDirectory(idb_path.DirName()));
2681  EXPECT_EQ(0, file_util::WriteFile(idb_path, NULL, 0));
2682  EXPECT_TRUE(file_util::PathExists(idb_path));
2683
2684  // Uninstall the extension.
2685  service_->UninstallExtension(good_crx, false);
2686  loop_.RunAllPending();
2687
2688  // Check that the cookie is gone.
2689  list = cookie_monster->GetAllCookiesForURL(ext_url);
2690  EXPECT_EQ(0U, list.size());
2691
2692  // The database should have vanished as well.
2693  origins.clear();
2694  db_tracker->GetAllOriginsInfo(&origins);
2695  EXPECT_EQ(0U, origins.size());
2696
2697  // Check that the LSO file has been removed.
2698  EXPECT_FALSE(file_util::PathExists(lso_path));
2699
2700  // Check if the indexed db has disappeared too.
2701  EXPECT_FALSE(file_util::PathExists(idb_path));
2702}
2703
2704// Tests loading single extensions (like --load-extension)
2705TEST_F(ExtensionServiceTest, LoadExtension) {
2706  InitializeEmptyExtensionService();
2707  FilePath extensions_path;
2708  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2709  extensions_path = extensions_path.AppendASCII("extensions");
2710
2711  FilePath ext1 = extensions_path
2712      .AppendASCII("good")
2713      .AppendASCII("Extensions")
2714      .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
2715      .AppendASCII("1.0.0.0");
2716  service_->LoadExtension(ext1);
2717  loop_.RunAllPending();
2718  EXPECT_EQ(0u, GetErrors().size());
2719  ASSERT_EQ(1u, loaded_.size());
2720  EXPECT_EQ(Extension::LOAD, loaded_[0]->location());
2721  EXPECT_EQ(1u, service_->extensions()->size());
2722
2723  ValidatePrefKeyCount(1);
2724
2725  FilePath no_manifest = extensions_path
2726      .AppendASCII("bad")
2727      // .AppendASCII("Extensions")
2728      .AppendASCII("cccccccccccccccccccccccccccccccc")
2729      .AppendASCII("1");
2730  service_->LoadExtension(no_manifest);
2731  loop_.RunAllPending();
2732  EXPECT_EQ(1u, GetErrors().size());
2733  ASSERT_EQ(1u, loaded_.size());
2734  EXPECT_EQ(1u, service_->extensions()->size());
2735
2736  // Test uninstall.
2737  std::string id = loaded_[0]->id();
2738  EXPECT_FALSE(unloaded_id_.length());
2739  service_->UninstallExtension(id, false);
2740  loop_.RunAllPending();
2741  EXPECT_EQ(id, unloaded_id_);
2742  ASSERT_EQ(0u, loaded_.size());
2743  EXPECT_EQ(0u, service_->extensions()->size());
2744}
2745
2746// Tests that we generate IDs when they are not specified in the manifest for
2747// --load-extension.
2748TEST_F(ExtensionServiceTest, GenerateID) {
2749  InitializeEmptyExtensionService();
2750
2751  FilePath extensions_path;
2752  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
2753  extensions_path = extensions_path.AppendASCII("extensions");
2754
2755  FilePath no_id_ext = extensions_path.AppendASCII("no_id");
2756  service_->LoadExtension(no_id_ext);
2757  loop_.RunAllPending();
2758  EXPECT_EQ(0u, GetErrors().size());
2759  ASSERT_EQ(1u, loaded_.size());
2760  ASSERT_TRUE(Extension::IdIsValid(loaded_[0]->id()));
2761  EXPECT_EQ(loaded_[0]->location(), Extension::LOAD);
2762
2763  ValidatePrefKeyCount(1);
2764
2765  std::string previous_id = loaded_[0]->id();
2766
2767  // If we reload the same path, we should get the same extension ID.
2768  service_->LoadExtension(no_id_ext);
2769  loop_.RunAllPending();
2770  ASSERT_EQ(1u, loaded_.size());
2771  ASSERT_EQ(previous_id, loaded_[0]->id());
2772}
2773
2774void ExtensionServiceTest::TestExternalProvider(
2775    MockExtensionProvider* provider, Extension::Location location) {
2776  // Verify that starting with no providers loads no extensions.
2777  service_->Init();
2778  loop_.RunAllPending();
2779  ASSERT_EQ(0u, loaded_.size());
2780
2781  provider->set_visit_count(0);
2782
2783  // Register a test extension externally using the mock registry provider.
2784  FilePath source_path;
2785  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_path));
2786  source_path = source_path.AppendASCII("extensions").AppendASCII("good.crx");
2787
2788  // Add the extension.
2789  provider->UpdateOrAddExtension(good_crx, "1.0.0.0", source_path);
2790
2791  // Reloading extensions should find our externally registered extension
2792  // and install it.
2793  service_->CheckForExternalUpdates();
2794  loop_.RunAllPending();
2795
2796  ASSERT_EQ(0u, GetErrors().size());
2797  ASSERT_EQ(1u, loaded_.size());
2798  ASSERT_EQ(location, loaded_[0]->location());
2799  ASSERT_EQ("1.0.0.0", loaded_[0]->version()->GetString());
2800  ValidatePrefKeyCount(1);
2801  ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
2802  ValidateIntegerPref(good_crx, "location", location);
2803
2804  // Reload extensions without changing anything. The extension should be
2805  // loaded again.
2806  loaded_.clear();
2807  service_->ReloadExtensions();
2808  loop_.RunAllPending();
2809  ASSERT_EQ(0u, GetErrors().size());
2810  ASSERT_EQ(1u, loaded_.size());
2811  ValidatePrefKeyCount(1);
2812  ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
2813  ValidateIntegerPref(good_crx, "location", location);
2814
2815  // Now update the extension with a new version. We should get upgraded.
2816  source_path = source_path.DirName().AppendASCII("good2.crx");
2817  provider->UpdateOrAddExtension(good_crx, "1.0.0.1", source_path);
2818
2819  loaded_.clear();
2820  service_->CheckForExternalUpdates();
2821  loop_.RunAllPending();
2822  ASSERT_EQ(0u, GetErrors().size());
2823  ASSERT_EQ(1u, loaded_.size());
2824  ASSERT_EQ("1.0.0.1", loaded_[0]->version()->GetString());
2825  ValidatePrefKeyCount(1);
2826  ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
2827  ValidateIntegerPref(good_crx, "location", location);
2828
2829  // Uninstall the extension and reload. Nothing should happen because the
2830  // preference should prevent us from reinstalling.
2831  std::string id = loaded_[0]->id();
2832  service_->UninstallExtension(id, false);
2833  loop_.RunAllPending();
2834
2835  // The extension should also be gone from the install directory.
2836  FilePath install_path = extensions_install_dir_.AppendASCII(id);
2837  ASSERT_FALSE(file_util::PathExists(install_path));
2838
2839  loaded_.clear();
2840  service_->CheckForExternalUpdates();
2841  loop_.RunAllPending();
2842  ASSERT_EQ(0u, loaded_.size());
2843  ValidatePrefKeyCount(1);
2844  ValidateIntegerPref(good_crx, "state", Extension::KILLBIT);
2845  ValidateIntegerPref(good_crx, "location", location);
2846
2847  // Now clear the preference and reinstall.
2848  SetPrefInteg(good_crx, "state", Extension::ENABLED);
2849  profile_->GetPrefs()->ScheduleSavePersistentPrefs();
2850
2851  loaded_.clear();
2852  service_->CheckForExternalUpdates();
2853  loop_.RunAllPending();
2854  ASSERT_EQ(1u, loaded_.size());
2855  ValidatePrefKeyCount(1);
2856  ValidateIntegerPref(good_crx, "state", Extension::ENABLED);
2857  ValidateIntegerPref(good_crx, "location", location);
2858
2859  // Now test an externally triggered uninstall (deleting the registry key or
2860  // the pref entry).
2861  provider->RemoveExtension(good_crx);
2862
2863  loaded_.clear();
2864  service_->UnloadAllExtensions();
2865  service_->LoadAllExtensions();
2866  loop_.RunAllPending();
2867  ASSERT_EQ(0u, loaded_.size());
2868  ValidatePrefKeyCount(0);
2869
2870  // The extension should also be gone from the install directory.
2871  ASSERT_FALSE(file_util::PathExists(install_path));
2872
2873  // Now test the case where user uninstalls and then the extension is removed
2874  // from the external provider.
2875
2876  provider->UpdateOrAddExtension(good_crx, "1.0", source_path);
2877  service_->CheckForExternalUpdates();
2878  loop_.RunAllPending();
2879
2880  ASSERT_EQ(1u, loaded_.size());
2881  ASSERT_EQ(0u, GetErrors().size());
2882
2883  // User uninstalls.
2884  loaded_.clear();
2885  service_->UninstallExtension(id, false);
2886  loop_.RunAllPending();
2887  ASSERT_EQ(0u, loaded_.size());
2888
2889  // Then remove the extension from the extension provider.
2890  provider->RemoveExtension(good_crx);
2891
2892  // Should still be at 0.
2893  loaded_.clear();
2894  service_->LoadAllExtensions();
2895  loop_.RunAllPending();
2896  ASSERT_EQ(0u, loaded_.size());
2897  ValidatePrefKeyCount(1);
2898
2899  EXPECT_EQ(5, provider->visit_count());
2900}
2901
2902// Tests the external installation feature
2903#if defined(OS_WIN)
2904TEST_F(ExtensionServiceTest, ExternalInstallRegistry) {
2905  // This should all work, even when normal extension installation is disabled.
2906  InitializeEmptyExtensionService();
2907  set_extensions_enabled(false);
2908
2909  // Now add providers. Extension system takes ownership of the objects.
2910  MockExtensionProvider* reg_provider =
2911      new MockExtensionProvider(Extension::EXTERNAL_REGISTRY);
2912  AddMockExternalProvider(reg_provider);
2913  TestExternalProvider(reg_provider, Extension::EXTERNAL_REGISTRY);
2914}
2915#endif
2916
2917TEST_F(ExtensionServiceTest, ExternalInstallPref) {
2918  InitializeEmptyExtensionService();
2919
2920  // Now add providers. Extension system takes ownership of the objects.
2921  MockExtensionProvider* pref_provider =
2922      new MockExtensionProvider(Extension::EXTERNAL_PREF);
2923
2924  AddMockExternalProvider(pref_provider);
2925  TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF);
2926}
2927
2928TEST_F(ExtensionServiceTest, ExternalInstallPrefUpdateUrl) {
2929  // This should all work, even when normal extension installation is disabled.
2930  InitializeEmptyExtensionService();
2931  set_extensions_enabled(false);
2932
2933  // TODO(skerner): The mock provider is not a good model of a provider
2934  // that works with update URLs, because it adds file and version info.
2935  // Extend the mock to work with update URLs.  This test checks the
2936  // behavior that is common to all external extension visitors.  The
2937  // browser test ExtensionManagementTest.ExternalUrlUpdate tests that
2938  // what the visitor does results in an extension being downloaded and
2939  // installed.
2940  MockExtensionProvider* pref_provider =
2941      new MockExtensionProvider(Extension::EXTERNAL_PREF_DOWNLOAD);
2942  AddMockExternalProvider(pref_provider);
2943  TestExternalProvider(pref_provider, Extension::EXTERNAL_PREF_DOWNLOAD);
2944}
2945
2946// Tests that external extensions get uninstalled when the external extension
2947// providers can't account for them.
2948TEST_F(ExtensionServiceTest, ExternalUninstall) {
2949  // Start the extensions service with one external extension already installed.
2950  FilePath source_install_dir;
2951  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
2952  source_install_dir = source_install_dir
2953      .AppendASCII("extensions")
2954      .AppendASCII("good")
2955      .AppendASCII("Extensions");
2956  FilePath pref_path = source_install_dir
2957      .DirName()
2958      .AppendASCII("PreferencesExternal");
2959
2960  // This initializes the extensions service with no ExternalExtensionProviders.
2961  InitializeInstalledExtensionService(pref_path, source_install_dir);
2962  set_extensions_enabled(false);
2963
2964  service_->Init();
2965  loop_.RunAllPending();
2966
2967  ASSERT_EQ(0u, GetErrors().size());
2968  ASSERT_EQ(0u, loaded_.size());
2969
2970  // Verify that it's not the disabled extensions flag causing it not to load.
2971  set_extensions_enabled(true);
2972  service_->ReloadExtensions();
2973  loop_.RunAllPending();
2974
2975  ASSERT_EQ(0u, GetErrors().size());
2976  ASSERT_EQ(0u, loaded_.size());
2977}
2978
2979TEST_F(ExtensionServiceTest, ExternalPrefProvider) {
2980  InitializeEmptyExtensionService();
2981  std::string json_data =
2982      "{"
2983      "  \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {"
2984      "    \"external_crx\": \"RandomExtension.crx\","
2985      "    \"external_version\": \"1.0\""
2986      "  },"
2987      "  \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\": {"
2988      "    \"external_crx\": \"RandomExtension2.crx\","
2989      "    \"external_version\": \"2.0\""
2990      "  },"
2991      "  \"cccccccccccccccccccccccccccccccc\": {"
2992      "    \"external_update_url\": \"http:\\\\foo.com/update\""
2993      "  }"
2994      "}";
2995
2996  MockProviderVisitor visitor;
2997
2998  // Simulate an external_extensions.json file that contains seven invalid
2999  // extensions:
3000  // - One that is missing the 'external_crx' key.
3001  // - One that is missing the 'external_version' key.
3002  // - One that is specifying .. in the path.
3003  // - One that specifies both a file and update URL.
3004  // - One that specifies no file or update URL.
3005  // - One that has an update URL that is not well formed.
3006  // - One that contains a malformed version.
3007  // The final extension is valid, and we check that it is read to make sure
3008  // failures don't stop valid records from being read.
3009  json_data =
3010      "{"
3011      "  \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\": {"
3012      "    \"external_version\": \"1.0\""
3013      "  },"
3014      "  \"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\": {"
3015      "    \"external_crx\": \"RandomExtension.crx\""
3016      "  },"
3017      "  \"cccccccccccccccccccccccccccccccc\": {"
3018      "    \"external_crx\": \"..\\\\foo\\\\RandomExtension2.crx\","
3019      "    \"external_version\": \"2.0\""
3020      "  },"
3021      "  \"dddddddddddddddddddddddddddddddd\": {"
3022      "    \"external_crx\": \"RandomExtension2.crx\","
3023      "    \"external_version\": \"2.0\","
3024      "    \"external_update_url\": \"http:\\\\foo.com/update\""
3025      "  },"
3026      "  \"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\": {"
3027      "  },"
3028      "  \"ffffffffffffffffffffffffffffffff\": {"
3029      "    \"external_update_url\": \"This string is not a valid URL\""
3030      "  },"
3031      "  \"gggggggggggggggggggggggggggggggg\": {"
3032      "    \"external_crx\": \"RandomExtension3.crx\","
3033      "    \"external_version\": \"This is not a valid version!\""
3034      "  },"
3035      "  \"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\": {"
3036      "    \"external_crx\": \"RandomValidExtension.crx\","
3037      "    \"external_version\": \"1.0\""
3038      "  }"
3039      "}";
3040  EXPECT_EQ(1, visitor.Visit(json_data));
3041}
3042
3043// Test loading good extensions from the profile directory.
3044TEST_F(ExtensionServiceTest, LoadAndRelocalizeExtensions) {
3045  // Initialize the test dir with a good Preferences/extensions.
3046  FilePath source_install_dir;
3047  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &source_install_dir));
3048  source_install_dir = source_install_dir
3049      .AppendASCII("extensions")
3050      .AppendASCII("l10n");
3051  FilePath pref_path = source_install_dir.AppendASCII("Preferences");
3052  InitializeInstalledExtensionService(pref_path, source_install_dir);
3053
3054  service_->Init();
3055  loop_.RunAllPending();
3056
3057  ASSERT_EQ(3u, loaded_.size());
3058
3059  // This was equal to "sr" on load.
3060  ValidateStringPref(loaded_[0]->id(), keys::kCurrentLocale, "en");
3061
3062  // These are untouched by re-localization.
3063  ValidateStringPref(loaded_[1]->id(), keys::kCurrentLocale, "en");
3064  EXPECT_FALSE(IsPrefExist(loaded_[1]->id(), keys::kCurrentLocale));
3065
3066  // This one starts with Serbian name, and gets re-localized into English.
3067  EXPECT_EQ("My name is simple.", loaded_[0]->name());
3068
3069  // These are untouched by re-localization.
3070  EXPECT_EQ("My name is simple.", loaded_[1]->name());
3071  EXPECT_EQ("no l10n", loaded_[2]->name());
3072}
3073
3074class ExtensionsReadyRecorder : public NotificationObserver {
3075 public:
3076  ExtensionsReadyRecorder() : ready_(false) {
3077    registrar_.Add(this, NotificationType::EXTENSIONS_READY,
3078                   NotificationService::AllSources());
3079  }
3080
3081  void set_ready(bool value) { ready_ = value; }
3082  bool ready() { return ready_; }
3083
3084 private:
3085  virtual void Observe(NotificationType type,
3086                       const NotificationSource& source,
3087                       const NotificationDetails& details) {
3088    switch (type.value) {
3089      case NotificationType::EXTENSIONS_READY:
3090        ready_ = true;
3091        break;
3092      default:
3093        NOTREACHED();
3094    }
3095  }
3096
3097  NotificationRegistrar registrar_;
3098  bool ready_;
3099};
3100
3101// Test that we get enabled/disabled correctly for all the pref/command-line
3102// combinations. We don't want to derive from the ExtensionServiceTest class
3103// for this test, so we use ExtensionServiceTestSimple.
3104//
3105// Also tests that we always fire EXTENSIONS_READY, no matter whether we are
3106// enabled or not.
3107TEST(ExtensionServiceTestSimple, Enabledness) {
3108  ExtensionsReadyRecorder recorder;
3109  scoped_ptr<TestingProfile> profile(new TestingProfile());
3110  MessageLoop loop;
3111  BrowserThread ui_thread(BrowserThread::UI, &loop);
3112  BrowserThread file_thread(BrowserThread::FILE, &loop);
3113  scoped_ptr<CommandLine> command_line;
3114  scoped_refptr<ExtensionService> service;
3115  FilePath install_dir = profile->GetPath()
3116      .AppendASCII(ExtensionService::kInstallDirectoryName);
3117
3118  // By default, we are enabled.
3119  command_line.reset(new CommandLine(CommandLine::NO_PROGRAM));
3120  service = profile->CreateExtensionService(command_line.get(),
3121                                             install_dir);
3122  EXPECT_TRUE(service->extensions_enabled());
3123  service->Init();
3124  loop.RunAllPending();
3125  EXPECT_TRUE(recorder.ready());
3126
3127  // If either the command line or pref is set, we are disabled.
3128  recorder.set_ready(false);
3129  profile.reset(new TestingProfile());
3130  command_line->AppendSwitch(switches::kDisableExtensions);
3131  service = profile->CreateExtensionService(command_line.get(),
3132                                             install_dir);
3133  EXPECT_FALSE(service->extensions_enabled());
3134  service->Init();
3135  loop.RunAllPending();
3136  EXPECT_TRUE(recorder.ready());
3137
3138  recorder.set_ready(false);
3139  profile.reset(new TestingProfile());
3140  profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true);
3141  service = profile->CreateExtensionService(command_line.get(),
3142                                             install_dir);
3143  EXPECT_FALSE(service->extensions_enabled());
3144  service->Init();
3145  loop.RunAllPending();
3146  EXPECT_TRUE(recorder.ready());
3147
3148  recorder.set_ready(false);
3149  profile.reset(new TestingProfile());
3150  profile->GetPrefs()->SetBoolean(prefs::kDisableExtensions, true);
3151  command_line.reset(new CommandLine(CommandLine::NO_PROGRAM));
3152  service = profile->CreateExtensionService(command_line.get(),
3153                                             install_dir);
3154  EXPECT_FALSE(service->extensions_enabled());
3155  service->Init();
3156  loop.RunAllPending();
3157  EXPECT_TRUE(recorder.ready());
3158
3159  // Explicitly delete all the resources used in this test.
3160  profile.reset();
3161  service = NULL;
3162}
3163
3164// Test loading extensions that require limited and unlimited storage quotas.
3165TEST_F(ExtensionServiceTest, StorageQuota) {
3166  InitializeEmptyExtensionService();
3167
3168  FilePath extensions_path;
3169  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &extensions_path));
3170  extensions_path = extensions_path.AppendASCII("extensions")
3171      .AppendASCII("storage_quota");
3172
3173  FilePath limited_quota_ext = extensions_path.AppendASCII("limited_quota")
3174      .AppendASCII("1.0");
3175
3176  // The old permission name for unlimited quota was "unlimited_storage", but
3177  // we changed it to "unlimitedStorage". This tests both versions.
3178  FilePath unlimited_quota_ext = extensions_path.AppendASCII("unlimited_quota")
3179      .AppendASCII("1.0");
3180  FilePath unlimited_quota_ext2 = extensions_path.AppendASCII("unlimited_quota")
3181      .AppendASCII("2.0");
3182  service_->LoadExtension(limited_quota_ext);
3183  service_->LoadExtension(unlimited_quota_ext);
3184  service_->LoadExtension(unlimited_quota_ext2);
3185  loop_.RunAllPending();
3186
3187  ASSERT_EQ(3u, loaded_.size());
3188  EXPECT_TRUE(profile_.get());
3189  EXPECT_FALSE(profile_->IsOffTheRecord());
3190
3191  // Open the database from each origin to make the tracker aware
3192  // of the existence of these origins and to get their quotas.
3193  int64 limited_quota = -1;
3194  int64 unlimited_quota = -1;
3195  string16 limited_quota_identifier =
3196      webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[0]->url());
3197  string16 unlimited_quota_identifier =
3198      webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[1]->url());
3199  string16 unlimited_quota_identifier2 =
3200      webkit_database::DatabaseUtil::GetOriginIdentifier(loaded_[2]->url());
3201  string16 db_name = UTF8ToUTF16("db");
3202  string16 description = UTF8ToUTF16("db_description");
3203  int64 database_size;
3204  webkit_database::DatabaseTracker* db_tracker = profile_->GetDatabaseTracker();
3205
3206  // First check the normal limited quota extension.
3207  db_tracker->DatabaseOpened(limited_quota_identifier, db_name, description,
3208                             1, &database_size, &limited_quota);
3209  db_tracker->DatabaseClosed(limited_quota_identifier, db_name);
3210  EXPECT_EQ(profile_->GetDatabaseTracker()->GetDefaultQuota(), limited_quota);
3211
3212  // Now check the two unlimited quota ones.
3213  db_tracker->DatabaseOpened(unlimited_quota_identifier, db_name, description,
3214                             1, &database_size, &unlimited_quota);
3215  db_tracker->DatabaseClosed(unlimited_quota_identifier, db_name);
3216  EXPECT_EQ(kint64max, unlimited_quota);
3217  db_tracker->DatabaseOpened(unlimited_quota_identifier2, db_name, description,
3218                             1, &database_size, &unlimited_quota);
3219  db_tracker->DatabaseClosed(unlimited_quota_identifier2, db_name);
3220
3221  EXPECT_EQ(kint64max, unlimited_quota);
3222}
3223
3224// Tests ExtensionService::register_component_extension().
3225TEST_F(ExtensionServiceTest, ComponentExtensions) {
3226  InitializeEmptyExtensionService();
3227
3228  // Component extensions should work even when extensions are disabled.
3229  set_extensions_enabled(false);
3230
3231  FilePath path;
3232  ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &path));
3233  path = path.AppendASCII("extensions")
3234      .AppendASCII("good")
3235      .AppendASCII("Extensions")
3236      .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
3237      .AppendASCII("1.0.0.0");
3238
3239  std::string manifest;
3240  ASSERT_TRUE(file_util::ReadFileToString(
3241      path.Append(Extension::kManifestFilename), &manifest));
3242
3243  service_->register_component_extension(
3244      ExtensionService::ComponentExtensionInfo(manifest, path));
3245  service_->Init();
3246
3247  // Note that we do not pump messages -- the extension should be loaded
3248  // immediately.
3249
3250  EXPECT_EQ(0u, GetErrors().size());
3251  ASSERT_EQ(1u, loaded_.size());
3252  EXPECT_EQ(Extension::COMPONENT, loaded_[0]->location());
3253  EXPECT_EQ(1u, service_->extensions()->size());
3254
3255  // Component extensions shouldn't get recourded in the prefs.
3256  ValidatePrefKeyCount(0);
3257
3258  // Reload all extensions, and make sure it comes back.
3259  std::string extension_id = service_->extensions()->at(0)->id();
3260  loaded_.clear();
3261  service_->ReloadExtensions();
3262  ASSERT_EQ(1u, service_->extensions()->size());
3263  EXPECT_EQ(extension_id, service_->extensions()->at(0)->id());
3264}
3265