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 TEST_F(ManagementApiUnitTest
, ManagementUninstall
) {
150 // We need to be on the UI thread for this.
151 ResetThreadBundle(content::TestBrowserThreadBundle::DEFAULT
);
152 scoped_refptr
<const Extension
> extension
= test_util::CreateEmptyExtension();
153 service()->AddExtension(extension
.get());
154 std::string extension_id
= extension
->id();
156 base::ListValue uninstall_args
;
157 uninstall_args
.AppendString(extension
->id());
159 // Auto-accept any uninstalls.
161 ScopedTestDialogAutoConfirm
auto_confirm(
162 ScopedTestDialogAutoConfirm::ACCEPT
);
164 // Uninstall requires a user gesture, so this should fail.
165 scoped_refptr
<UIThreadExtensionFunction
> function(
166 new ManagementUninstallFunction());
167 EXPECT_FALSE(RunFunction(function
, uninstall_args
));
168 EXPECT_EQ(std::string(constants::kGestureNeededForUninstallError
),
169 function
->GetError());
171 ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture
;
173 function
= new ManagementUninstallFunction();
174 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
175 EXPECT_TRUE(RunFunction(function
, uninstall_args
)) << function
->GetError();
176 // The extension should be uninstalled.
177 EXPECT_FALSE(registry()->GetExtensionById(extension_id
,
178 ExtensionRegistry::EVERYTHING
));
181 // Install the extension again, and try uninstalling, auto-canceling the
184 ScopedTestDialogAutoConfirm
auto_confirm(
185 ScopedTestDialogAutoConfirm::CANCEL
);
186 ExtensionFunction::ScopedUserGestureForTests scoped_user_gesture
;
188 service()->AddExtension(extension
.get());
189 scoped_refptr
<UIThreadExtensionFunction
> function
=
190 new ManagementUninstallFunction();
191 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
192 EXPECT_FALSE(RunFunction(function
, uninstall_args
));
193 // The uninstall should have failed.
194 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
195 EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUninstallCanceledError
,
197 function
->GetError());
199 // Try again, using showConfirmDialog: false.
200 scoped_ptr
<base::DictionaryValue
> options(new base::DictionaryValue());
201 options
->SetBoolean("showConfirmDialog", false);
202 uninstall_args
.Append(options
.release());
203 function
= new ManagementUninstallFunction();
204 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
205 EXPECT_FALSE(RunFunction(function
, uninstall_args
));
206 // This should still fail, since extensions can only suppress the dialog for
207 // uninstalling themselves.
208 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
209 EXPECT_EQ(ErrorUtils::FormatErrorMessage(constants::kUninstallCanceledError
,
211 function
->GetError());
213 // If we try uninstall the extension itself, the uninstall should succeed
214 // (even though we auto-cancel any dialog), because the dialog is never
216 uninstall_args
.Remove(0u, nullptr);
217 function
= new ManagementUninstallSelfFunction();
218 function
->set_extension(extension
);
219 EXPECT_TRUE(registry()->enabled_extensions().Contains(extension_id
));
220 EXPECT_TRUE(RunFunction(function
, uninstall_args
)) << function
->GetError();
221 EXPECT_FALSE(registry()->GetExtensionById(extension_id
,
222 ExtensionRegistry::EVERYTHING
));
226 } // namespace extensions