1 // Copyright 2014 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 "base/memory/ref_counted.h" 6 #include "chrome/browser/extensions/extension_error_controller.h" 7 #include "chrome/browser/extensions/extension_error_ui.h" 8 #include "chrome/browser/extensions/extension_service.h" 9 #include "chrome/browser/extensions/extension_service_test_base.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/test/base/testing_profile.h" 12 #include "extensions/browser/extension_prefs.h" 13 #include "extensions/browser/extension_registry.h" 14 #include "extensions/common/extension.h" 15 #include "extensions/common/extension_builder.h" 16 #include "extensions/common/value_builder.h" 17 18 namespace extensions { 19 20 namespace { 21 22 // Create a mock for the UI component of the error alert that is shown for 23 // blacklisted extensions. This allows us to test which extensions the alert 24 // is showing, and also eliminates the UI component (since this is a unit 25 // test). 26 class MockExtensionErrorUI : public ExtensionErrorUI { 27 public: 28 explicit MockExtensionErrorUI(ExtensionErrorUI::Delegate* delegate); 29 virtual ~MockExtensionErrorUI(); 30 31 // Wrappers around the similar methods in ExtensionErrorUI. 32 void CloseUI(); 33 void Accept(); 34 void Details(); 35 36 ExtensionErrorUI::Delegate* delegate() { return delegate_; } 37 38 private: 39 // ExtensionErrorUI implementation. 40 virtual bool ShowErrorInBubbleView() OVERRIDE; 41 virtual void ShowExtensions() OVERRIDE; 42 virtual void Close() OVERRIDE; 43 44 // Keep a copy of the delegate around for ourselves. 45 ExtensionErrorUI::Delegate* delegate_; 46 }; 47 48 // We use this as a slight hack to get the created Error UI, if any. We should 49 // only ever have one (since this is a single-profile test), and this avoids 50 // the need for any kind of accessor to the ErrorController from 51 // ExtensionService. 52 MockExtensionErrorUI* g_error_ui = NULL; 53 54 MockExtensionErrorUI::MockExtensionErrorUI( 55 ExtensionErrorUI::Delegate* delegate) 56 : ExtensionErrorUI(delegate), 57 delegate_(delegate) { 58 // We should never make more than one of these in a test. 59 DCHECK(!g_error_ui); 60 g_error_ui = this; 61 } 62 63 MockExtensionErrorUI::~MockExtensionErrorUI() { 64 g_error_ui = NULL; 65 } 66 67 void MockExtensionErrorUI::CloseUI() { 68 BubbleViewDidClose(); 69 } 70 71 void MockExtensionErrorUI::Accept() { 72 BubbleViewAcceptButtonPressed(); 73 } 74 75 void MockExtensionErrorUI::Details() { 76 BubbleViewCancelButtonPressed(); 77 } 78 79 bool MockExtensionErrorUI::ShowErrorInBubbleView() { 80 return true; 81 } 82 83 void MockExtensionErrorUI::ShowExtensions() {} 84 85 void MockExtensionErrorUI::Close() { 86 CloseUI(); 87 } 88 89 ExtensionErrorUI* CreateMockUI(ExtensionErrorUI::Delegate* delegate) { 90 return new MockExtensionErrorUI(delegate); 91 } 92 93 // Builds and returns a simple extension. 94 scoped_refptr<const Extension> BuildExtension() { 95 return ExtensionBuilder() 96 .SetManifest(DictionaryBuilder().Set("name", "My Wonderful Extension") 97 .Set("version", "0.1.1.0") 98 .Set("manifest_version", 2) 99 .Build()) 100 .Build(); 101 } 102 103 } // namespace 104 105 class ExtensionErrorControllerUnitTest : public ExtensionServiceTestBase { 106 protected: 107 virtual void SetUp() OVERRIDE; 108 109 // Add an extension to chrome, and mark it as blacklisted in the prefs. 110 testing::AssertionResult AddBlacklistedExtension(const Extension* extension); 111 112 // Return the ExtensionPrefs associated with the test. 113 ExtensionPrefs* GetPrefs(); 114 115 Profile* profile() { return profile_.get(); } 116 }; 117 118 void ExtensionErrorControllerUnitTest::SetUp() { 119 ExtensionServiceTestBase::SetUp(); 120 // Make sure we use the mock UI instead of the real UI. 121 ExtensionErrorController::SetUICreateMethodForTesting(CreateMockUI); 122 123 // We don't want a first-run ExtensionService, since we ignore warnings 124 // for new profiles. 125 ExtensionServiceInitParams params = CreateDefaultInitParams(); 126 params.is_first_run = false; 127 InitializeExtensionService(params); 128 } 129 130 testing::AssertionResult 131 ExtensionErrorControllerUnitTest::AddBlacklistedExtension( 132 const Extension* extension) { 133 GetPrefs()->SetExtensionBlacklisted(extension->id(), true); 134 service_->AddExtension(extension); 135 136 // Make sure the extension is added to the blacklisted set. 137 if (!ExtensionRegistry::Get(profile())->blacklisted_extensions() 138 .Contains(extension->id())) { 139 return testing::AssertionFailure() 140 << "Failed to add blacklisted extension."; 141 } 142 143 return testing::AssertionSuccess(); 144 } 145 146 ExtensionPrefs* ExtensionErrorControllerUnitTest::GetPrefs() { 147 return ExtensionPrefs::Get(profile()); 148 } 149 150 // Test that closing the extension alert for blacklisted extensions counts 151 // as acknowledging them in the prefs. 152 TEST_F(ExtensionErrorControllerUnitTest, ClosingAcknowledgesBlacklisted) { 153 // Add a blacklisted extension. 154 scoped_refptr<const Extension> extension = BuildExtension(); 155 ASSERT_TRUE(AddBlacklistedExtension(extension.get())); 156 157 service_->Init(); 158 159 // Make sure that we created an error "ui" to warn about the blacklisted 160 // extension. 161 ASSERT_TRUE(g_error_ui); 162 ExtensionErrorUI::Delegate* delegate = g_error_ui->delegate(); 163 ASSERT_TRUE(delegate); 164 165 // Make sure that the blacklisted extension is reported (and that no other 166 // extensions are). 167 const ExtensionSet& delegate_blacklisted_extensions = 168 delegate->GetBlacklistedExtensions(); 169 EXPECT_EQ(1u, delegate_blacklisted_extensions.size()); 170 EXPECT_TRUE(delegate_blacklisted_extensions.Contains(extension->id())); 171 172 // Close, and verify that the extension ids now acknowledged. 173 g_error_ui->CloseUI(); 174 EXPECT_TRUE(GetPrefs()->IsBlacklistedExtensionAcknowledged(extension->id())); 175 // Verify we cleaned up after ourselves. 176 EXPECT_FALSE(g_error_ui); 177 } 178 179 // Test that clicking "accept" on the extension alert counts as acknowledging 180 // blacklisted extensions. 181 TEST_F(ExtensionErrorControllerUnitTest, AcceptingAcknowledgesBlacklisted) { 182 // Add a blacklisted extension. 183 scoped_refptr<const Extension> extension = BuildExtension(); 184 ASSERT_TRUE(AddBlacklistedExtension(extension.get())); 185 186 service_->Init(); 187 188 // Make sure that we created an error "ui" to warn about the blacklisted 189 // extension. 190 ASSERT_TRUE(g_error_ui); 191 192 // Accept, and verify that the extension ids now acknowledged. 193 g_error_ui->Accept(); 194 EXPECT_TRUE(GetPrefs()->IsBlacklistedExtensionAcknowledged(extension->id())); 195 // Verify we cleaned up after ourselves. 196 EXPECT_FALSE(g_error_ui); 197 } 198 199 // Test that we don't warn for extensions which are blacklisted, but have 200 // already been acknowledged. 201 TEST_F(ExtensionErrorControllerUnitTest, DontWarnForAcknowledgedBlacklisted) { 202 scoped_refptr<const Extension> extension = BuildExtension(); 203 ASSERT_TRUE(AddBlacklistedExtension(extension.get())); 204 205 GetPrefs()->AcknowledgeBlacklistedExtension(extension->id()); 206 207 service_->Init(); 208 209 // We should never have made an alert, because the extension should already 210 // be acknowledged. 211 ASSERT_FALSE(g_error_ui); 212 } 213 214 } // namespace extensions 215