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/extension_set.h"
     15 #include "chrome/common/pref_names.h"
     16 #include "chrome/test/base/testing_pref_service_syncable.h"
     17 #include "components/user_prefs/pref_registry_syncable.h"
     18 #include "extensions/common/constants.h"
     19 #include "extensions/common/extension.h"
     20 #include "extensions/common/manifest_handlers/background_info.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       UnloadedExtensionInfo::Reason 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 void RemoveComponentExtension(const std::string & extension_id)
     53       OVERRIDE {
     54     UnloadExtension(extension_id, UnloadedExtensionInfo::REASON_DISABLE);
     55   }
     56 
     57   virtual bool is_ready() OVERRIDE {
     58     return ready_;
     59   }
     60 
     61   virtual const ExtensionSet* extensions() const OVERRIDE {
     62     return &extension_set_;
     63   }
     64 
     65   void set_ready(bool ready) {
     66     ready_ = ready;
     67   }
     68 
     69   size_t unloaded_count() const {
     70     return unloaded_count_;
     71   }
     72 
     73   void clear_extensions() {
     74     extension_set_.Clear();
     75   }
     76 };
     77 
     78 }  // namespace
     79 
     80 class ComponentLoaderTest : public testing::Test {
     81  public:
     82   ComponentLoaderTest()
     83       // Note: we pass the same pref service here, to stand in for both
     84       // user prefs and local state.
     85       : component_loader_(&extension_service_, &prefs_, &local_state_) {
     86   }
     87 
     88   virtual void SetUp() OVERRIDE {
     89     extension_path_ =
     90         GetBasePath().AppendASCII("good")
     91                      .AppendASCII("Extensions")
     92                      .AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
     93                      .AppendASCII("1.0.0.0");
     94 
     95     // Read in the extension manifest.
     96     ASSERT_TRUE(base::ReadFileToString(
     97         extension_path_.Append(kManifestFilename),
     98         &manifest_contents_));
     99 
    100     // Register the local state prefs.
    101 #if defined(OS_CHROMEOS)
    102     local_state_.registry()->RegisterBooleanPref(
    103         prefs::kSpokenFeedbackEnabled, false);
    104 #endif
    105   }
    106 
    107  protected:
    108   MockExtensionService extension_service_;
    109   TestingPrefServiceSyncable prefs_;
    110   TestingPrefServiceSimple local_state_;
    111   ComponentLoader component_loader_;
    112 
    113   // The root directory of the text extension.
    114   base::FilePath extension_path_;
    115 
    116   // The contents of the text extension's manifest file.
    117   std::string manifest_contents_;
    118 
    119   base::FilePath GetBasePath() {
    120     base::FilePath test_data_dir;
    121     PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir);
    122     return test_data_dir.AppendASCII("extensions");
    123   }
    124 };
    125 
    126 TEST_F(ComponentLoaderTest, ParseManifest) {
    127   scoped_ptr<DictionaryValue> manifest;
    128 
    129   // Test invalid JSON.
    130   manifest.reset(
    131       component_loader_.ParseManifest("{ 'test': 3 } invalid"));
    132   EXPECT_FALSE(manifest.get());
    133 
    134   // Test manifests that are valid JSON, but don't have an object literal
    135   // at the root. ParseManifest() should always return NULL.
    136 
    137   manifest.reset(component_loader_.ParseManifest(std::string()));
    138   EXPECT_FALSE(manifest.get());
    139 
    140   manifest.reset(component_loader_.ParseManifest("[{ \"foo\": 3 }]"));
    141   EXPECT_FALSE(manifest.get());
    142 
    143   manifest.reset(component_loader_.ParseManifest("\"Test\""));
    144   EXPECT_FALSE(manifest.get());
    145 
    146   manifest.reset(component_loader_.ParseManifest("42"));
    147   EXPECT_FALSE(manifest.get());
    148 
    149   manifest.reset(component_loader_.ParseManifest("true"));
    150   EXPECT_FALSE(manifest.get());
    151 
    152   manifest.reset(component_loader_.ParseManifest("false"));
    153   EXPECT_FALSE(manifest.get());
    154 
    155   manifest.reset(component_loader_.ParseManifest("null"));
    156   EXPECT_FALSE(manifest.get());
    157 
    158   // Test parsing valid JSON.
    159 
    160   int value = 0;
    161   manifest.reset(component_loader_.ParseManifest(
    162       "{ \"test\": { \"one\": 1 }, \"two\": 2 }"));
    163   ASSERT_TRUE(manifest.get());
    164   EXPECT_TRUE(manifest->GetInteger("test.one", &value));
    165   EXPECT_EQ(1, value);
    166   ASSERT_TRUE(manifest->GetInteger("two", &value));
    167   EXPECT_EQ(2, value);
    168 
    169   std::string string_value;
    170   manifest.reset(component_loader_.ParseManifest(manifest_contents_));
    171   ASSERT_TRUE(manifest->GetString("background.page", &string_value));
    172   EXPECT_EQ("backgroundpage.html", string_value);
    173 }
    174 
    175 // Test that the extension isn't loaded if the extension service isn't ready.
    176 TEST_F(ComponentLoaderTest, AddWhenNotReady) {
    177   extension_service_.set_ready(false);
    178   std::string extension_id =
    179       component_loader_.Add(manifest_contents_, extension_path_);
    180   EXPECT_NE("", extension_id);
    181   EXPECT_EQ(0u, extension_service_.extensions()->size());
    182 }
    183 
    184 // Test that it *is* loaded when the extension service *is* ready.
    185 TEST_F(ComponentLoaderTest, AddWhenReady) {
    186   extension_service_.set_ready(true);
    187   std::string extension_id =
    188       component_loader_.Add(manifest_contents_, extension_path_);
    189   EXPECT_NE("", extension_id);
    190   EXPECT_EQ(1u, extension_service_.extensions()->size());
    191   EXPECT_TRUE(extension_service_.extensions()->GetByID(extension_id));
    192 }
    193 
    194 TEST_F(ComponentLoaderTest, Remove) {
    195   extension_service_.set_ready(false);
    196 
    197   // Removing an extension that was never added should be ok.
    198   component_loader_.Remove(extension_path_);
    199   EXPECT_EQ(0u, extension_service_.extensions()->size());
    200 
    201   // Try adding and removing before LoadAll() is called.
    202   component_loader_.Add(manifest_contents_, extension_path_);
    203   component_loader_.Remove(extension_path_);
    204   component_loader_.LoadAll();
    205   EXPECT_EQ(0u, extension_service_.extensions()->size());
    206 
    207   // Load an extension, and check that it's unloaded when Remove() is called.
    208   extension_service_.set_ready(true);
    209   std::string extension_id =
    210       component_loader_.Add(manifest_contents_, extension_path_);
    211   EXPECT_EQ(1u, extension_service_.extensions()->size());
    212   component_loader_.Remove(extension_path_);
    213   EXPECT_EQ(0u, extension_service_.extensions()->size());
    214 
    215   // And after calling LoadAll(), it shouldn't get loaded.
    216   component_loader_.LoadAll();
    217   EXPECT_EQ(0u, extension_service_.extensions()->size());
    218 }
    219 
    220 TEST_F(ComponentLoaderTest, LoadAll) {
    221   extension_service_.set_ready(false);
    222 
    223   // No extensions should be loaded if none were added.
    224   component_loader_.LoadAll();
    225   EXPECT_EQ(0u, extension_service_.extensions()->size());
    226 
    227   // Use LoadAll() to load the default extensions.
    228   component_loader_.AddDefaultComponentExtensions(false);
    229   component_loader_.LoadAll();
    230   unsigned int default_count = extension_service_.extensions()->size();
    231 
    232   // Clear the list of loaded extensions, and reload with one more.
    233   extension_service_.clear_extensions();
    234   component_loader_.Add(manifest_contents_, extension_path_);
    235   component_loader_.LoadAll();
    236 
    237   EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
    238 }
    239 
    240 TEST_F(ComponentLoaderTest, AddOrReplace) {
    241   EXPECT_EQ(0u, component_loader_.registered_extensions_count());
    242   component_loader_.AddDefaultComponentExtensions(false);
    243   size_t const default_count = component_loader_.registered_extensions_count();
    244   base::FilePath known_extension = GetBasePath()
    245       .AppendASCII("override_component_extension");
    246   base::FilePath unknow_extension = extension_path_;
    247   base::FilePath invalid_extension = GetBasePath().AppendASCII("bad");
    248 
    249   // Replace a default component extension.
    250   component_loader_.AddOrReplace(known_extension);
    251   EXPECT_EQ(default_count,
    252             component_loader_.registered_extensions_count());
    253 
    254   // Add a new component extension.
    255   component_loader_.AddOrReplace(unknow_extension);
    256   EXPECT_EQ(default_count + 1,
    257             component_loader_.registered_extensions_count());
    258 
    259   extension_service_.set_ready(true);
    260   component_loader_.LoadAll();
    261 
    262   EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
    263   EXPECT_EQ(0u, extension_service_.unloaded_count());
    264 
    265   // replace loaded component extension.
    266   component_loader_.AddOrReplace(known_extension);
    267   EXPECT_EQ(default_count + 1, extension_service_.extensions()->size());
    268   EXPECT_EQ(1u, extension_service_.unloaded_count());
    269 
    270   // Add an invalid component extension.
    271   std::string extension_id = component_loader_.AddOrReplace(invalid_extension);
    272   EXPECT_TRUE(extension_id.empty());
    273 }
    274 
    275 }  // namespace extensions
    276