Home | History | Annotate | Download | only in extensions
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/component_loader.h"
      6 
      7 #include <string>
      8 
      9 #include "base/file_util.h"
     10 #include "base/path_service.h"
     11 #include "base/prefs/pref_registry_simple.h"
     12 #include "chrome/browser/extensions/test_extension_service.h"
     13 #include "chrome/common/chrome_paths.h"
     14 #include "chrome/common/extensions/background_info.h"
     15 #include "chrome/common/extensions/extension.h"
     16 #include "chrome/common/extensions/extension_set.h"
     17 #include "chrome/common/pref_names.h"
     18 #include "chrome/test/base/testing_pref_service_syncable.h"
     19 #include "components/user_prefs/pref_registry_syncable.h"
     20 #include "extensions/common/constants.h"
     21 #include "testing/gtest/include/gtest/gtest.h"
     22 
     23 namespace extensions {
     24 
     25 namespace {
     26 
     27 class MockExtensionService : public TestExtensionService {
     28  private:
     29   bool ready_;
     30   size_t unloaded_count_;
     31   ExtensionSet extension_set_;
     32 
     33  public:
     34   MockExtensionService() : ready_(false), unloaded_count_(0) {
     35   }
     36 
     37   virtual void AddComponentExtension(const Extension* extension) OVERRIDE {
     38     EXPECT_FALSE(extension_set_.Contains(extension->id()));
     39     // ExtensionService must become the owner of the extension object.
     40     extension_set_.Insert(extension);
     41   }
     42 
     43   virtual void UnloadExtension(
     44       const std::string& extension_id,
     45       extension_misc::UnloadedExtensionReason reason) OVERRIDE {
     46     ASSERT_TRUE(extension_set_.Contains(extension_id));
     47     // Remove the extension with the matching id.
     48     extension_set_.Remove(extension_id);
     49     unloaded_count_++;
     50   }
     51 
     52   virtual bool is_ready() OVERRIDE {
     53     return ready_;
     54   }
     55 
     56   virtual const ExtensionSet* extensions() const OVERRIDE {
     57     return &extension_set_;
     58   }
     59 
     60   void set_ready(bool ready) {
     61     ready_ = ready;
     62   }
     63 
     64   size_t unloaded_count() const {
     65     return unloaded_count_;
     66   }
     67 
     68   void clear_extensions() {
     69     extension_set_.Clear();
     70   }
     71 };
     72 
     73 }  // namespace
     74 
     75 class ComponentLoaderTest : public testing::Test {
     76  public:
     77   ComponentLoaderTest()
     78       // Note: we pass the same pref service here, to stand in for both
     79       // user prefs and local state.
     80       : component_loader_(&extension_service_, &prefs_, &local_state_) {
     81   }
     82 
     83   virtual void SetUp() OVERRIDE {
     84     extension_path_ =
     85         GetBasePath().AppendASCII("good")
     86                      .AppendASCII("Extensions")
     87                      .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
     88                      .AppendASCII("1.0.0.0");
     89 
     90     // Read in the extension manifest.
     91     ASSERT_TRUE(file_util::ReadFileToString(
     92         extension_path_.Append(kManifestFilename),
     93         &manifest_contents_));
     94 
     95     // Register the local state prefs.
     96 #if defined(OS_CHROMEOS)
     97     local_state_.registry()->RegisterBooleanPref(
     98         prefs::kSpokenFeedbackEnabled, false);
     99 #endif
    100   }
    101 
    102  protected:
    103   MockExtensionService extension_service_;
    104   TestingPrefServiceSyncable prefs_;
    105   TestingPrefServiceSimple local_state_;
    106   ComponentLoader component_loader_;
    107 
    108   // The root directory of the text extension.
    109   base::FilePath extension_path_;
    110 
    111   // The contents of the text extension's manifest file.
    112   std::string manifest_contents_;
    113 
    114   base::FilePath GetBasePath() {
    115     base::FilePath test_data_dir;
    116     PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
    117     return test_data_dir.AppendASCII("extensions");
    118   }
    119 };
    120 
    121 TEST_F(ComponentLoaderTest, ParseManifest) {
    122   scoped_ptr<DictionaryValue> manifest;
    123 
    124   // Test invalid JSON.
    125   manifest.reset(
    126       component_loader_.ParseManifest("{ 'test': 3 } invalid"));
    127   EXPECT_FALSE(manifest.get());
    128 
    129   // Test manifests that are valid JSON, but don't have an object literal
    130   // at the root. ParseManifest() should always return NULL.
    131 
    132   manifest.reset(component_loader_.ParseManifest(std::string()));
    133   EXPECT_FALSE(manifest.get());
    134 
    135   manifest.reset(component_loader_.ParseManifest("[{ \"foo\": 3 }]"));
    136   EXPECT_FALSE(manifest.get());
    137 
    138   manifest.reset(component_loader_.ParseManifest("\"Test\""));
    139   EXPECT_FALSE(manifest.get());
    140 
    141   manifest.reset(component_loader_.ParseManifest("42"));
    142   EXPECT_FALSE(manifest.get());
    143 
    144   manifest.reset(component_loader_.ParseManifest("true"));
    145   EXPECT_FALSE(manifest.get());
    146 
    147   manifest.reset(component_loader_.ParseManifest("false"));
    148   EXPECT_FALSE(manifest.get());
    149 
    150   manifest.reset(component_loader_.ParseManifest("null"));
    151   EXPECT_FALSE(manifest.get());
    152 
    153   // Test parsing valid JSON.
    154 
    155   int value = 0;
    156   manifest.reset(component_loader_.ParseManifest(
    157       "{ \"test\": { \"one\": 1 }, \"two\": 2 }"));
    158   ASSERT_TRUE(manifest.get());
    159   EXPECT_TRUE(manifest->GetInteger("test.one", &value));
    160   EXPECT_EQ(1, value);
    161   ASSERT_TRUE(manifest->GetInteger("two", &value));
    162   EXPECT_EQ(2, value);
    163 
    164   std::string string_value;
    165   manifest.reset(component_loader_.ParseManifest(manifest_contents_));
    166   ASSERT_TRUE(manifest->GetString("background.page", &string_value));
    167   EXPECT_EQ("backgroundpage.html", string_value);
    168 }
    169 
    170 // Test that the extension isn't loaded if the extension service isn't ready.
    171 TEST_F(ComponentLoaderTest, AddWhenNotReady) {
    172   extension_service_.set_ready(false);
    173   std::string extension_id =
    174       component_loader_.Add(manifest_contents_, extension_path_);
    175   EXPECT_NE("", extension_id);
    176   EXPECT_EQ(0u, extension_service_.extensions()->size());
    177 }
    178 
    179 // Test that it *is* loaded when the extension service *is* ready.
    180 TEST_F(ComponentLoaderTest, AddWhenReady) {
    181   extension_service_.set_ready(true);
    182   std::string extension_id =
    183       component_loader_.Add(manifest_contents_, extension_path_);
    184   EXPECT_NE("", extension_id);
    185   EXPECT_EQ(1u, extension_service_.extensions()->size());
    186   EXPECT_TRUE(extension_service_.extensions()->GetByID(extension_id));
    187 }
    188 
    189 TEST_F(ComponentLoaderTest, Remove) {
    190   extension_service_.set_ready(false);
    191 
    192   // Removing an extension that was never added should be ok.
    193   component_loader_.Remove(extension_path_);
    194   EXPECT_EQ(0u, extension_service_.extensions()->size());
    195 
    196   // Try adding and removing before LoadAll() is called.
    197   component_loader_.Add(manifest_contents_, extension_path_);
    198   component_loader_.Remove(extension_path_);
    199   component_loader_.LoadAll();
    200   EXPECT_EQ(0u, extension_service_.extensions()->size());
    201 
    202   // Load an extension, and check that it's unloaded when Remove() is called.
    203   extension_service_.set_ready(true);
    204   std::string extension_id =
    205       component_loader_.Add(manifest_contents_, extension_path_);
    206   EXPECT_EQ(1u, extension_service_.extensions()->size());
    207   component_loader_.Remove(extension_path_);
    208   EXPECT_EQ(0u, extension_service_.extensions()->size());
    209 
    210   // And after calling LoadAll(), it shouldn't get loaded.
    211   component_loader_.LoadAll();
    212   EXPECT_EQ(0u, extension_service_.extensions()->size());
    213 }
    214 
    215 TEST_F(ComponentLoaderTest, LoadAll) {
    216   extension_service_.set_ready(false);
    217 
    218   // No extensions should be loaded if none were added.
    219   component_loader_.LoadAll();
    220   EXPECT_EQ(0u, extension_service_.extensions()->size());
    221 
    222   // Use LoadAll() to load the default extensions.
    223   component_loader_.AddDefaultComponentExtensions(false);
    224   component_loader_.LoadAll();
    225   unsigned int default_count = extension_service_.extensions()->size();
    226 
    227   // Clear the list of loaded extensions, and reload with one more.
    228   extension_service_.clear_extensions();
    229   component_loader_.Add(manifest_contents_, extension_path_);
    230   component_loader_.LoadAll();
    231 
    232   EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
    233 }
    234 
    235 TEST_F(ComponentLoaderTest, RemoveAll) {
    236   extension_service_.set_ready(true);
    237   EXPECT_EQ(0u, extension_service_.extensions()->size());
    238   // Add all the default extensions. Since the extension service is ready, they
    239   // will be loaded immediately.
    240   component_loader_.AddDefaultComponentExtensions(false);
    241   unsigned int default_count = extension_service_.extensions()->size();
    242 
    243   // And add one more just to make sure there is anything in there in case
    244   // there are no defaults for this platform.
    245   component_loader_.Add(manifest_contents_, extension_path_);
    246   EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
    247 
    248   // Remove all default extensions.
    249   component_loader_.RemoveAll();
    250   EXPECT_EQ(0u, extension_service_.extensions()->size());
    251 }
    252 
    253 TEST_F(ComponentLoaderTest, AddOrReplace) {
    254   EXPECT_EQ(0u, component_loader_.registered_extensions_count());
    255   component_loader_.AddDefaultComponentExtensions(false);
    256   size_t const default_count = component_loader_.registered_extensions_count();
    257   base::FilePath known_extension = GetBasePath()
    258       .AppendASCII("override_component_extension");
    259   base::FilePath unknow_extension = extension_path_;
    260   base::FilePath invalid_extension = GetBasePath().AppendASCII("bad");
    261 
    262   // Replace a default component extension.
    263   component_loader_.AddOrReplace(known_extension);
    264   EXPECT_EQ(default_count,
    265             component_loader_.registered_extensions_count());
    266 
    267   // Add a new component extension.
    268   component_loader_.AddOrReplace(unknow_extension);
    269   EXPECT_EQ(default_count + 1,
    270             component_loader_.registered_extensions_count());
    271 
    272   extension_service_.set_ready(true);
    273   component_loader_.LoadAll();
    274 
    275   EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
    276   EXPECT_EQ(0u, extension_service_.unloaded_count());
    277 
    278   // replace loaded component extension.
    279   component_loader_.AddOrReplace(known_extension);
    280   EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
    281   EXPECT_EQ(1u, extension_service_.unloaded_count());
    282 
    283   // Add an invalid component extension.
    284   std::string extension_id = component_loader_.AddOrReplace(invalid_extension);
    285   EXPECT_TRUE(extension_id.empty());
    286 }
    287 
    288 }  // namespace extensions
    289