1 // Copyright 2015 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.
5 #include "base/memory/scoped_ptr.h"
6 #include "chrome/browser/extensions/extension_function_test_utils.h"
7 #include "chrome/browser/extensions/extension_service.h"
8 #include "chrome/browser/extensions/extension_service_test_base.h"
9 #include "chrome/browser/extensions/test_extension_system.h"
10 #include "chrome/browser/ui/browser.h"
11 #include "chrome/browser/ui/host_desktop.h"
12 #include "chrome/test/base/test_browser_window.h"
13 #include "extensions/browser/api/management/management_api.h"
14 #include "extensions/browser/api/management/management_api_constants.h"
15 #include "extensions/browser/event_router_factory.h"
16 #include "extensions/browser/extension_dialog_auto_confirm.h"
17 #include "extensions/browser/extension_prefs.h"
18 #include "extensions/browser/extension_registry.h"
19 #include "extensions/browser/extension_system.h"
20 #include "extensions/browser/management_policy.h"
21 #include "extensions/browser/test_management_policy.h"
22 #include "extensions/common/error_utils.h"
23 #include "extensions/common/extension.h"
24 #include "extensions/common/extension_set.h"
25 #include "extensions/common/test_util.h"
27 namespace extensions
{
31 scoped_ptr
<KeyedService
> BuildManagementApi(content::BrowserContext
* context
) {
32 return make_scoped_ptr(new ManagementAPI(context
));
35 scoped_ptr
<KeyedService
> BuildEventRouter(content::BrowserContext
* profile
) {
36 return make_scoped_ptr(
37 new extensions::EventRouter(profile
, ExtensionPrefs::Get(profile
)));
42 namespace constants
= extension_management_api_constants
;
44 // TODO(devlin): Unittests are awesome. Test more with unittests and less with
45 // heavy api/browser tests.
46 class ManagementApiUnitTest
: public ExtensionServiceTestBase
{
48 ManagementApiUnitTest() {}
49 ~ManagementApiUnitTest() override
{}
51 // A wrapper around extension_function_test_utils::RunFunction that runs with
52 // the associated browser, no flags, and can take stack-allocated arguments.
53 bool RunFunction(const scoped_refptr
<UIThreadExtensionFunction
>& function
,
54 const base::ListValue
& args
);
56 Browser
* browser() { return browser_
.get(); }
59 // ExtensionServiceTestBase:
60 void SetUp() override
;
61 void TearDown() override
;
63 // The browser (and accompanying window).
64 scoped_ptr
<TestBrowserWindow
> browser_window_
;
65 scoped_ptr
<Browser
> browser_
;
67 DISALLOW_COPY_AND_ASSIGN(ManagementApiUnitTest
);
70 bool ManagementApiUnitTest::RunFunction(
71 const scoped_refptr
<UIThreadExtensionFunction
>& function
,
72 const base::ListValue
& args
) {
73 return extension_function_test_utils::RunFunction(
75 make_scoped_ptr(args
.DeepCopy()),
77 extension_function_test_utils::NONE
);
80 void ManagementApiUnitTest::SetUp() {
81 ExtensionServiceTestBase::SetUp();
82 InitializeEmptyExtensionService();
83 ManagementAPI::GetFactoryInstance()->SetTestingFactory(profile(),
86 EventRouterFactory::GetInstance()->SetTestingFactory(profile(),
89 browser_window_
.reset(new TestBrowserWindow());
90 Browser::CreateParams
params(profile(), chrome::HOST_DESKTOP_TYPE_NATIVE
);
91 params
.type
= Browser::TYPE_TABBED
;
92 params
.window
= browser_window_
.get();
93 browser_
.reset(new Browser(params
));
96 void ManagementApiUnitTest::TearDown() {
98 browser_window_
.reset();
99 ExtensionServiceTestBase::TearDown();
102 // Test the basic parts of management.setEnabled.
103 TEST_F(ManagementApiUnitTest
, ManagementSetEnabled
) {
104 scoped_refptr
<const Extension
> extension
= test_util::CreateEmptyExtension();
105 service()->AddExtension(extension
.get());
106 std::string extension_id
= extension
->id();
107 scoped_refptr
<ManagementSetEnabledFunction
> function(
108 new ManagementSetEnabledFunction());
110 base::ListValue disable_args
;
111 disable_args
.AppendString(extension_id
);
112 disable_args
.AppendBoolean(false);
114 // Test disabling an (enabled) extension.
115 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
116 EXPECT_TRUE(RunFunction(function
, disable_args
)) << function
->GetError();
117 EXPECT_TRUE(registry()->disabled_extensions().Contains(extension_id
));
119 base::ListValue enable_args
;
120 enable_args
.AppendString(extension_id
);
121 enable_args
.AppendBoolean(true);
123 // Test re-enabling it.
124 function
= new ManagementSetEnabledFunction();
125 EXPECT_TRUE(RunFunction(function
, enable_args
)) << function
->GetError();
126 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
128 // Test that the enable function checks management policy, so that we can't
129 // disable an extension that is required.
130 TestManagementPolicyProvider
provider(
131 TestManagementPolicyProvider::PROHIBIT_MODIFY_STATUS
);
132 ManagementPolicy
* policy
=
133 ExtensionSystem::Get(profile())->management_policy();
134 policy
->RegisterProvider(&provider
);
136 function
= new ManagementSetEnabledFunction();
137 EXPECT_FALSE(RunFunction(function
, disable_args
));
138 EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUserCantModifyError
,
140 function
->GetError());
141 policy
->UnregisterProvider(&provider
);
143 // TODO(devlin): We should also test enabling an extenion that has escalated
144 // permissions, but that needs a web contents (which is a bit of a pain in a
148 // Tests management.uninstall.
149 // http://crbug.com/527228 flaky
150 TEST_F(ManagementApiUnitTest
, DISABLED_ManagementUninstall
) {
151 // We need to be on the UI thread for this.
152 ResetThreadBundle(content::TestBrowserThreadBundle::DEFAULT
);
153 scoped_refptr
<const Extension
> extension
= test_util::CreateEmptyExtension();
154 service()->AddExtension(extension
.get());
155 std::string extension_id
= extension
->id();
157 base::ListValue uninstall_args
;
158 uninstall_args
.AppendString(extension
->id());
160 // Auto-accept any uninstalls.
162 ScopedTestDialogAutoConfirm
auto_confirm(
163 ScopedTestDialogAutoConfirm::ACCEPT
);
165 // Uninstall requires a user gesture, so this should fail.
166 scoped_refptr
<UIThreadExtensionFunction
> function(
167 new ManagementUninstallFunction());
168 EXPECT_FALSE(RunFunction(function
, uninstall_args
));
169 EXPECT_EQ(std::string(constants::kGestureNeededForUninstallError
),
170 function
->GetError());
172 ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture
;
174 function
= new ManagementUninstallFunction();
175 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
176 EXPECT_TRUE(RunFunction(function
, uninstall_args
)) << function
->GetError();
177 // The extension should be uninstalled.
178 EXPECT_FALSE(registry()->GetExtensionById(extension_id
,
179 ExtensionRegistry::EVERYTHING
));
182 // Install the extension again, and try uninstalling, auto-canceling the
185 ScopedTestDialogAutoConfirm
auto_confirm(
186 ScopedTestDialogAutoConfirm::CANCEL
);
187 ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture
;
189 service()->AddExtension(extension
.get());
190 scoped_refptr
<UIThreadExtensionFunction
> function
=
191 new ManagementUninstallFunction();
192 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
193 EXPECT_FALSE(RunFunction(function
, uninstall_args
));
194 // The uninstall should have failed.
195 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
196 EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUninstallCanceledError
,
198 function
->GetError());
200 // Try again, using showConfirmDialog: false.
201 scoped_ptr
<base::DictionaryValue
> options(new base::DictionaryValue());
202 options
->SetBoolean("showConfirmDialog", false);
203 uninstall_args
.Append(options
.release());
204 function
= new ManagementUninstallFunction();
205 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
206 EXPECT_FALSE(RunFunction(function
, uninstall_args
));
207 // This should still fail, since extensions can only suppress the dialog for
208 // uninstalling themselves.
209 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
210 EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUninstallCanceledError
,
212 function
->GetError());
214 // If we try uninstall the extension itself, the uninstall should succeed
215 // (even though we auto-cancel any dialog), because the dialog is never
217 uninstall_args
.Remove(0u, nullptr);
218 function
= new ManagementUninstallSelfFunction();
219 function
->set_extension(extension
);
220 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
221 EXPECT_TRUE(RunFunction(function
, uninstall_args
)) << function
->GetError();
222 EXPECT_FALSE(registry()->GetExtensionById(extension_id
,
223 ExtensionRegistry::EVERYTHING
));
227 } // namespace extensions