| // Copyright 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "extensions/browser/extension_registry.h" |
| |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "extensions/browser/extension_registry_observer.h" |
| #include "extensions/browser/uninstall_reason.h" |
| #include "extensions/browser/unloaded_extension_reason.h" |
| #include "extensions/common/extension_builder.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace extensions { |
| namespace { |
| |
| typedef testing::Test ExtensionRegistryTest; |
| |
| testing::AssertionResult HasSingleExtension( |
| const ExtensionList& list, |
| const scoped_refptr<const Extension>& extension) { |
| if (list.empty()) |
| return testing::AssertionFailure() << "No extensions in list"; |
| if (list.size() > 1) { |
| return testing::AssertionFailure() << list.size() |
| << " extensions, expected 1"; |
| } |
| const Extension* did_load = list[0].get(); |
| if (did_load != extension.get()) { |
| return testing::AssertionFailure() << "Expected " << extension->id() |
| << " found " << did_load->id(); |
| } |
| return testing::AssertionSuccess(); |
| } |
| |
| class TestObserver : public ExtensionRegistryObserver { |
| public: |
| TestObserver() {} |
| |
| void Reset() { |
| loaded_.clear(); |
| unloaded_.clear(); |
| installed_.clear(); |
| uninstalled_.clear(); |
| } |
| |
| const ExtensionList& loaded() { return loaded_; } |
| const ExtensionList& unloaded() { return unloaded_; } |
| const ExtensionList& installed() { return installed_; } |
| const ExtensionList& uninstalled() { return uninstalled_; } |
| |
| private: |
| void OnExtensionLoaded(content::BrowserContext* browser_context, |
| const Extension* extension) override { |
| loaded_.push_back(extension); |
| } |
| |
| void OnExtensionUnloaded(content::BrowserContext* browser_context, |
| const Extension* extension, |
| UnloadedExtensionReason reason) override { |
| unloaded_.push_back(extension); |
| } |
| |
| void OnExtensionWillBeInstalled(content::BrowserContext* browser_context, |
| const Extension* extension, |
| bool is_update, |
| const std::string& old_name) override { |
| installed_.push_back(extension); |
| } |
| |
| void OnExtensionUninstalled(content::BrowserContext* browser_context, |
| const Extension* extension, |
| UninstallReason reason) override { |
| uninstalled_.push_back(extension); |
| } |
| |
| void OnShutdown(ExtensionRegistry* registry) override { Reset(); } |
| |
| ExtensionList loaded_; |
| ExtensionList unloaded_; |
| ExtensionList installed_; |
| ExtensionList uninstalled_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestObserver); |
| }; |
| |
| TEST_F(ExtensionRegistryTest, FillAndClearRegistry) { |
| ExtensionRegistry registry(NULL); |
| scoped_refptr<const Extension> extension1 = ExtensionBuilder("one").Build(); |
| scoped_refptr<const Extension> extension2 = ExtensionBuilder("two").Build(); |
| scoped_refptr<const Extension> extension3 = ExtensionBuilder("three").Build(); |
| scoped_refptr<const Extension> extension4 = ExtensionBuilder("four").Build(); |
| |
| // All the sets start empty. |
| EXPECT_EQ(0u, registry.enabled_extensions().size()); |
| EXPECT_EQ(0u, registry.disabled_extensions().size()); |
| EXPECT_EQ(0u, registry.terminated_extensions().size()); |
| EXPECT_EQ(0u, registry.blocklisted_extensions().size()); |
| |
| // Extensions can be added to each set. |
| registry.AddEnabled(extension1); |
| registry.AddDisabled(extension2); |
| registry.AddTerminated(extension3); |
| registry.AddBlocklisted(extension4); |
| |
| EXPECT_EQ(1u, registry.enabled_extensions().size()); |
| EXPECT_EQ(1u, registry.disabled_extensions().size()); |
| EXPECT_EQ(1u, registry.terminated_extensions().size()); |
| EXPECT_EQ(1u, registry.blocklisted_extensions().size()); |
| |
| // Clearing the registry clears all sets. |
| registry.ClearAll(); |
| |
| EXPECT_EQ(0u, registry.enabled_extensions().size()); |
| EXPECT_EQ(0u, registry.disabled_extensions().size()); |
| EXPECT_EQ(0u, registry.terminated_extensions().size()); |
| EXPECT_EQ(0u, registry.blocklisted_extensions().size()); |
| } |
| |
| // A simple test of adding and removing things from sets. |
| TEST_F(ExtensionRegistryTest, AddAndRemoveExtensionFromRegistry) { |
| ExtensionRegistry registry(NULL); |
| |
| // Adding an extension works. |
| scoped_refptr<const Extension> extension = ExtensionBuilder("Test").Build(); |
| EXPECT_TRUE(registry.AddEnabled(extension)); |
| EXPECT_EQ(1u, registry.enabled_extensions().size()); |
| |
| // The extension was only added to one set. |
| EXPECT_EQ(0u, registry.disabled_extensions().size()); |
| EXPECT_EQ(0u, registry.terminated_extensions().size()); |
| EXPECT_EQ(0u, registry.blocklisted_extensions().size()); |
| |
| // Removing an extension works. |
| EXPECT_TRUE(registry.RemoveEnabled(extension->id())); |
| EXPECT_EQ(0u, registry.enabled_extensions().size()); |
| |
| // Trying to remove an extension that isn't in the set fails cleanly. |
| EXPECT_FALSE(registry.RemoveEnabled(extension->id())); |
| } |
| |
| TEST_F(ExtensionRegistryTest, AddExtensionToRegistryTwice) { |
| ExtensionRegistry registry(NULL); |
| scoped_refptr<const Extension> extension = ExtensionBuilder("Test").Build(); |
| |
| // An extension can exist in two sets at once. It would be nice to eliminate |
| // this functionality, but some users of ExtensionRegistry need it. |
| EXPECT_TRUE(registry.AddEnabled(extension)); |
| EXPECT_TRUE(registry.AddDisabled(extension)); |
| |
| EXPECT_EQ(1u, registry.enabled_extensions().size()); |
| EXPECT_EQ(1u, registry.disabled_extensions().size()); |
| EXPECT_EQ(0u, registry.terminated_extensions().size()); |
| EXPECT_EQ(0u, registry.blocklisted_extensions().size()); |
| } |
| |
| TEST_F(ExtensionRegistryTest, GetExtensionById) { |
| ExtensionRegistry registry(NULL); |
| |
| // Trying to get an extension fails cleanly when the sets are empty. |
| EXPECT_FALSE( |
| registry.GetExtensionById("id", ExtensionRegistry::EVERYTHING)); |
| |
| scoped_refptr<const Extension> enabled = ExtensionBuilder("enabled").Build(); |
| scoped_refptr<const Extension> disabled = |
| ExtensionBuilder("disabled").Build(); |
| scoped_refptr<const Extension> terminated = |
| ExtensionBuilder("terminated").Build(); |
| scoped_refptr<const Extension> blocklisted = |
| ExtensionBuilder("blacklisted").Build(); |
| |
| // Add an extension to each set. |
| registry.AddEnabled(enabled); |
| registry.AddDisabled(disabled); |
| registry.AddTerminated(terminated); |
| registry.AddBlocklisted(blocklisted); |
| |
| // Enabled is part of everything and the enabled list. |
| EXPECT_TRUE( |
| registry.GetExtensionById(enabled->id(), ExtensionRegistry::EVERYTHING)); |
| EXPECT_TRUE( |
| registry.GetExtensionById(enabled->id(), ExtensionRegistry::ENABLED)); |
| EXPECT_FALSE( |
| registry.GetExtensionById(enabled->id(), ExtensionRegistry::DISABLED)); |
| EXPECT_FALSE( |
| registry.GetExtensionById(enabled->id(), ExtensionRegistry::TERMINATED)); |
| EXPECT_FALSE( |
| registry.GetExtensionById(enabled->id(), ExtensionRegistry::BLOCKLISTED)); |
| |
| // Disabled is part of everything and the disabled list. |
| EXPECT_TRUE( |
| registry.GetExtensionById(disabled->id(), ExtensionRegistry::EVERYTHING)); |
| EXPECT_FALSE( |
| registry.GetExtensionById(disabled->id(), ExtensionRegistry::ENABLED)); |
| EXPECT_TRUE( |
| registry.GetExtensionById(disabled->id(), ExtensionRegistry::DISABLED)); |
| EXPECT_FALSE( |
| registry.GetExtensionById(disabled->id(), ExtensionRegistry::TERMINATED)); |
| EXPECT_FALSE(registry.GetExtensionById(disabled->id(), |
| ExtensionRegistry::BLOCKLISTED)); |
| |
| // Terminated is part of everything and the terminated list. |
| EXPECT_TRUE(registry.GetExtensionById(terminated->id(), |
| ExtensionRegistry::EVERYTHING)); |
| EXPECT_FALSE( |
| registry.GetExtensionById(terminated->id(), ExtensionRegistry::ENABLED)); |
| EXPECT_FALSE( |
| registry.GetExtensionById(terminated->id(), ExtensionRegistry::DISABLED)); |
| EXPECT_TRUE(registry.GetExtensionById(terminated->id(), |
| ExtensionRegistry::TERMINATED)); |
| EXPECT_FALSE(registry.GetExtensionById(terminated->id(), |
| ExtensionRegistry::BLOCKLISTED)); |
| |
| // Blocklisted is part of everything and the blocklisted list. |
| EXPECT_TRUE(registry.GetExtensionById(blocklisted->id(), |
| ExtensionRegistry::EVERYTHING)); |
| EXPECT_FALSE( |
| registry.GetExtensionById(blocklisted->id(), ExtensionRegistry::ENABLED)); |
| EXPECT_FALSE(registry.GetExtensionById(blocklisted->id(), |
| ExtensionRegistry::DISABLED)); |
| EXPECT_FALSE(registry.GetExtensionById(blocklisted->id(), |
| ExtensionRegistry::TERMINATED)); |
| EXPECT_TRUE(registry.GetExtensionById(blocklisted->id(), |
| ExtensionRegistry::BLOCKLISTED)); |
| |
| // Enabled can be found with multiple flags set. |
| EXPECT_TRUE(registry.GetExtensionById( |
| enabled->id(), |
| ExtensionRegistry::ENABLED | ExtensionRegistry::TERMINATED)); |
| |
| // Enabled isn't found if the wrong flags are set. |
| EXPECT_FALSE(registry.GetExtensionById( |
| enabled->id(), |
| ExtensionRegistry::DISABLED | ExtensionRegistry::BLOCKLISTED)); |
| } |
| |
| TEST_F(ExtensionRegistryTest, Observer) { |
| ExtensionRegistry registry(NULL); |
| TestObserver observer; |
| registry.AddObserver(&observer); |
| |
| EXPECT_TRUE(observer.loaded().empty()); |
| EXPECT_TRUE(observer.unloaded().empty()); |
| EXPECT_TRUE(observer.installed().empty()); |
| |
| scoped_refptr<const Extension> extension = ExtensionBuilder("Test").Build(); |
| |
| registry.TriggerOnWillBeInstalled(extension.get(), false, std::string()); |
| EXPECT_TRUE(HasSingleExtension(observer.installed(), extension.get())); |
| |
| registry.AddEnabled(extension); |
| registry.TriggerOnLoaded(extension.get()); |
| |
| registry.TriggerOnWillBeInstalled(extension.get(), true, "foo"); |
| |
| EXPECT_TRUE(HasSingleExtension(observer.loaded(), extension.get())); |
| EXPECT_TRUE(observer.unloaded().empty()); |
| registry.Shutdown(); |
| |
| registry.RemoveEnabled(extension->id()); |
| registry.TriggerOnUnloaded(extension.get(), UnloadedExtensionReason::DISABLE); |
| |
| EXPECT_TRUE(observer.loaded().empty()); |
| EXPECT_TRUE(HasSingleExtension(observer.unloaded(), extension.get())); |
| registry.Shutdown(); |
| |
| registry.TriggerOnUninstalled(extension.get(), UNINSTALL_REASON_FOR_TESTING); |
| EXPECT_TRUE(observer.installed().empty()); |
| EXPECT_TRUE(HasSingleExtension(observer.uninstalled(), extension.get())); |
| |
| registry.RemoveObserver(&observer); |
| } |
| |
| // Regression test for https://crbug.com/724563. |
| TEST_F(ExtensionRegistryTest, TerminatedExtensionStoredVersion) { |
| const std::string kVersionString = "1.2.3.4"; |
| ExtensionRegistry registry(nullptr); |
| scoped_refptr<const Extension> extension = |
| ExtensionBuilder() |
| .SetManifest(DictionaryBuilder() |
| .Set("name", "Test") |
| .Set("version", kVersionString) |
| .Set("manifest_version", 2) |
| .Build()) |
| .Build(); |
| const ExtensionId extension_id = extension->id(); |
| |
| EXPECT_TRUE(registry.AddEnabled(extension)); |
| EXPECT_FALSE( |
| registry.GetExtensionById(extension_id, ExtensionRegistry::TERMINATED)); |
| { |
| base::Version version = registry.GetStoredVersion(extension_id); |
| ASSERT_TRUE(version.IsValid()); |
| EXPECT_EQ(kVersionString, |
| registry.GetStoredVersion(extension_id).GetString()); |
| } |
| |
| // Simulate terminating |extension|. |
| EXPECT_TRUE(registry.RemoveEnabled(extension_id)); |
| EXPECT_TRUE(registry.AddTerminated(extension)); |
| EXPECT_TRUE( |
| registry.GetExtensionById(extension_id, ExtensionRegistry::TERMINATED)); |
| { |
| base::Version version = registry.GetStoredVersion(extension_id); |
| ASSERT_TRUE(version.IsValid()); |
| EXPECT_EQ(kVersionString, |
| registry.GetStoredVersion(extension_id).GetString()); |
| } |
| } |
| |
| } // namespace |
| } // namespace extensions |