// 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 #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& 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() {} TestObserver(const TestObserver&) = delete; TestObserver& operator=(const TestObserver&) = delete; 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_; }; TEST_F(ExtensionRegistryTest, FillAndClearRegistry) { ExtensionRegistry registry(NULL); scoped_refptr extension1 = ExtensionBuilder("one").Build(); scoped_refptr extension2 = ExtensionBuilder("two").Build(); scoped_refptr extension3 = ExtensionBuilder("three").Build(); scoped_refptr 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 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 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 enabled = ExtensionBuilder("enabled").Build(); scoped_refptr disabled = ExtensionBuilder("disabled").Build(); scoped_refptr terminated = ExtensionBuilder("terminated").Build(); scoped_refptr blocklisted = ExtensionBuilder("blocklisted").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 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 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