// Copyright 2014 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 "base/memory/ref_counted.h" #include "chrome/browser/extensions/extension_error_controller.h" #include "chrome/browser/extensions/extension_error_ui.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service_test_base.h" #include "chrome/browser/profiles/profile.h" #include "chrome/test/base/testing_profile.h" #include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/common/extension.h" #include "extensions/common/extension_builder.h" #include "extensions/common/value_builder.h" namespace extensions { namespace { // Create a mock for the UI component of the error alert that is shown for // blacklisted extensions. This allows us to test which extensions the alert // is showing, and also eliminates the UI component (since this is a unit // test). class MockExtensionErrorUI : public ExtensionErrorUI { public: explicit MockExtensionErrorUI(ExtensionErrorUI::Delegate* delegate); virtual ~MockExtensionErrorUI(); // Wrappers around the similar methods in ExtensionErrorUI. void CloseUI(); void Accept(); void Details(); ExtensionErrorUI::Delegate* delegate() { return delegate_; } private: // ExtensionErrorUI implementation. virtual bool ShowErrorInBubbleView() OVERRIDE; virtual void ShowExtensions() OVERRIDE; virtual void Close() OVERRIDE; // Keep a copy of the delegate around for ourselves. ExtensionErrorUI::Delegate* delegate_; }; // We use this as a slight hack to get the created Error UI, if any. We should // only ever have one (since this is a single-profile test), and this avoids // the need for any kind of accessor to the ErrorController from // ExtensionService. MockExtensionErrorUI* g_error_ui = NULL; MockExtensionErrorUI::MockExtensionErrorUI( ExtensionErrorUI::Delegate* delegate) : ExtensionErrorUI(delegate), delegate_(delegate) { // We should never make more than one of these in a test. DCHECK(!g_error_ui); g_error_ui = this; } MockExtensionErrorUI::~MockExtensionErrorUI() { g_error_ui = NULL; } void MockExtensionErrorUI::CloseUI() { BubbleViewDidClose(); } void MockExtensionErrorUI::Accept() { BubbleViewAcceptButtonPressed(); } void MockExtensionErrorUI::Details() { BubbleViewCancelButtonPressed(); } bool MockExtensionErrorUI::ShowErrorInBubbleView() { return true; } void MockExtensionErrorUI::ShowExtensions() {} void MockExtensionErrorUI::Close() { CloseUI(); } ExtensionErrorUI* CreateMockUI(ExtensionErrorUI::Delegate* delegate) { return new MockExtensionErrorUI(delegate); } // Builds and returns a simple extension. scoped_refptr BuildExtension() { return ExtensionBuilder() .SetManifest(DictionaryBuilder().Set("name", "My Wonderful Extension") .Set("version", "0.1.1.0") .Set("manifest_version", 2) .Build()) .Build(); } } // namespace class ExtensionErrorControllerUnitTest : public ExtensionServiceTestBase { protected: virtual void SetUp() OVERRIDE; // Add an extension to chrome, and mark it as blacklisted in the prefs. testing::AssertionResult AddBlacklistedExtension(const Extension* extension); // Return the ExtensionPrefs associated with the test. ExtensionPrefs* GetPrefs(); Profile* profile() { return profile_.get(); } }; void ExtensionErrorControllerUnitTest::SetUp() { ExtensionServiceTestBase::SetUp(); // Make sure we use the mock UI instead of the real UI. ExtensionErrorController::SetUICreateMethodForTesting(CreateMockUI); // We don't want a first-run ExtensionService, since we ignore warnings // for new profiles. ExtensionServiceInitParams params = CreateDefaultInitParams(); params.is_first_run = false; InitializeExtensionService(params); } testing::AssertionResult ExtensionErrorControllerUnitTest::AddBlacklistedExtension( const Extension* extension) { GetPrefs()->SetExtensionBlacklisted(extension->id(), true); service_->AddExtension(extension); // Make sure the extension is added to the blacklisted set. if (!ExtensionRegistry::Get(profile())->blacklisted_extensions() .Contains(extension->id())) { return testing::AssertionFailure() << "Failed to add blacklisted extension."; } return testing::AssertionSuccess(); } ExtensionPrefs* ExtensionErrorControllerUnitTest::GetPrefs() { return ExtensionPrefs::Get(profile()); } // Test that closing the extension alert for blacklisted extensions counts // as acknowledging them in the prefs. TEST_F(ExtensionErrorControllerUnitTest, ClosingAcknowledgesBlacklisted) { // Add a blacklisted extension. scoped_refptr extension = BuildExtension(); ASSERT_TRUE(AddBlacklistedExtension(extension.get())); service_->Init(); // Make sure that we created an error "ui" to warn about the blacklisted // extension. ASSERT_TRUE(g_error_ui); ExtensionErrorUI::Delegate* delegate = g_error_ui->delegate(); ASSERT_TRUE(delegate); // Make sure that the blacklisted extension is reported (and that no other // extensions are). const ExtensionSet& delegate_blacklisted_extensions = delegate->GetBlacklistedExtensions(); EXPECT_EQ(1u, delegate_blacklisted_extensions.size()); EXPECT_TRUE(delegate_blacklisted_extensions.Contains(extension->id())); // Close, and verify that the extension ids now acknowledged. g_error_ui->CloseUI(); EXPECT_TRUE(GetPrefs()->IsBlacklistedExtensionAcknowledged(extension->id())); // Verify we cleaned up after ourselves. EXPECT_FALSE(g_error_ui); } // Test that clicking "accept" on the extension alert counts as acknowledging // blacklisted extensions. TEST_F(ExtensionErrorControllerUnitTest, AcceptingAcknowledgesBlacklisted) { // Add a blacklisted extension. scoped_refptr extension = BuildExtension(); ASSERT_TRUE(AddBlacklistedExtension(extension.get())); service_->Init(); // Make sure that we created an error "ui" to warn about the blacklisted // extension. ASSERT_TRUE(g_error_ui); // Accept, and verify that the extension ids now acknowledged. g_error_ui->Accept(); EXPECT_TRUE(GetPrefs()->IsBlacklistedExtensionAcknowledged(extension->id())); // Verify we cleaned up after ourselves. EXPECT_FALSE(g_error_ui); } // Test that we don't warn for extensions which are blacklisted, but have // already been acknowledged. TEST_F(ExtensionErrorControllerUnitTest, DontWarnForAcknowledgedBlacklisted) { scoped_refptr extension = BuildExtension(); ASSERT_TRUE(AddBlacklistedExtension(extension.get())); GetPrefs()->AcknowledgeBlacklistedExtension(extension->id()); service_->Init(); // We should never have made an alert, because the extension should already // be acknowledged. ASSERT_FALSE(g_error_ui); } } // namespace extensions