1// Copyright (c) 2012 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 <map>
6
7#include "chrome/browser/chrome_notification_types.h"
8#include "chrome/browser/extensions/api/management/management_api.h"
9#include "chrome/browser/extensions/extension_apitest.h"
10#include "chrome/browser/extensions/extension_service.h"
11#include "chrome/browser/extensions/launch_util.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/ui/browser.h"
14#include "chrome/browser/ui/browser_commands.h"
15#include "chrome/browser/ui/browser_finder.h"
16#include "chrome/browser/ui/browser_iterator.h"
17#include "chrome/browser/ui/tabs/tab_strip_model.h"
18#include "chrome/common/chrome_switches.h"
19#include "chrome/common/extensions/extension_constants.h"
20#include "content/public/test/test_utils.h"
21#include "extensions/browser/extension_system.h"
22#include "extensions/browser/test_management_policy.h"
23#include "extensions/common/manifest.h"
24#include "extensions/test/extension_test_message_listener.h"
25
26using extensions::Extension;
27using extensions::Manifest;
28
29namespace {
30
31// Find a browser other than |browser|.
32Browser* FindOtherBrowser(Browser* browser) {
33  Browser* found = NULL;
34  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
35    if (*it == browser)
36      continue;
37    found = *it;
38  }
39  return found;
40}
41
42}  // namespace
43
44class ExtensionManagementApiTest : public ExtensionApiTest {
45 public:
46  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
47    ExtensionApiTest::SetUpCommandLine(command_line);
48    command_line->AppendSwitch(switches::kEnablePanels);
49  }
50
51  virtual void LoadExtensions() {
52    base::FilePath basedir = test_data_dir_.AppendASCII("management");
53
54    // Load 5 enabled items.
55    LoadNamedExtension(basedir, "enabled_extension");
56    LoadNamedExtension(basedir, "enabled_app");
57    LoadNamedExtension(basedir, "description");
58    LoadNamedExtension(basedir, "permissions");
59    LoadNamedExtension(basedir, "short_name");
60
61    // Load 2 disabled items.
62    LoadNamedExtension(basedir, "disabled_extension");
63    DisableExtension(extension_ids_["disabled_extension"]);
64    LoadNamedExtension(basedir, "disabled_app");
65    DisableExtension(extension_ids_["disabled_app"]);
66  }
67
68  // Load an app, and wait for a message from app "management/launch_on_install"
69  // indicating that the new app has been launched.
70  void LoadAndWaitForLaunch(const std::string& app_path,
71                            std::string* out_app_id) {
72    ExtensionTestMessageListener launched_app("launched app", false);
73    ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(app_path)));
74
75    if (out_app_id)
76      *out_app_id = last_loaded_extension_id();
77
78    ASSERT_TRUE(launched_app.WaitUntilSatisfied());
79  }
80
81 protected:
82  void LoadNamedExtension(const base::FilePath& path,
83                          const std::string& name) {
84    const Extension* extension = LoadExtension(path.AppendASCII(name));
85    ASSERT_TRUE(extension);
86    extension_ids_[name] = extension->id();
87  }
88
89  void InstallNamedExtension(const base::FilePath& path,
90                             const std::string& name,
91                             Manifest::Location install_source) {
92    const Extension* extension = InstallExtension(path.AppendASCII(name), 1,
93                                                  install_source);
94    ASSERT_TRUE(extension);
95    extension_ids_[name] = extension->id();
96  }
97
98  // Maps installed extension names to their IDs.
99  std::map<std::string, std::string> extension_ids_;
100};
101
102IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, Basics) {
103  LoadExtensions();
104
105  base::FilePath basedir = test_data_dir_.AppendASCII("management");
106  InstallNamedExtension(basedir, "internal_extension", Manifest::INTERNAL);
107  InstallNamedExtension(basedir, "external_extension",
108                        Manifest::EXTERNAL_PREF);
109  InstallNamedExtension(basedir, "admin_extension",
110                        Manifest::EXTERNAL_POLICY_DOWNLOAD);
111
112  ASSERT_TRUE(RunExtensionSubtest("management/test", "basics.html"));
113}
114
115IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, NoPermission) {
116  LoadExtensions();
117  ASSERT_TRUE(RunExtensionSubtest("management/no_permission", "test.html"));
118}
119
120// Disabled: http://crbug.com/174411
121#if defined(OS_WIN)
122#define MAYBE_Uninstall DISABLED_Uninstall
123#else
124#define MAYBE_Uninstall Uninstall
125#endif
126
127IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, MAYBE_Uninstall) {
128  LoadExtensions();
129  // Confirmation dialog will be shown for uninstallations except for self.
130  extensions::ManagementUninstallFunction::SetAutoConfirmForTest(true);
131  ASSERT_TRUE(RunExtensionSubtest("management/test", "uninstall.html"));
132}
133
134IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, CreateAppShortcut) {
135  LoadExtensions();
136  base::FilePath basedir = test_data_dir_.AppendASCII("management");
137  LoadNamedExtension(basedir, "packaged_app");
138
139  extensions::ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(true);
140  ASSERT_TRUE(RunExtensionSubtest("management/test",
141                                  "createAppShortcut.html"));
142}
143
144IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, GenerateAppForLink) {
145  LoadExtensions();
146  ASSERT_TRUE(RunExtensionSubtest("management/test",
147                                  "generateAppForLink.html"));
148}
149
150// Fails often on Windows dbg bots. http://crbug.com/177163
151#if defined(OS_WIN)
152#define MAYBE_ManagementPolicyAllowed DISABLED_ManagementPolicyAllowed
153#else
154#define MAYBE_ManagementPolicyAllowed ManagementPolicyAllowed
155#endif  // defined(OS_WIN)
156// Tests actions on extensions when no management policy is in place.
157IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,
158                       MAYBE_ManagementPolicyAllowed) {
159  LoadExtensions();
160  extensions::ManagementUninstallFunction::SetAutoConfirmForTest(true);
161  ExtensionService* service = extensions::ExtensionSystem::Get(
162      browser()->profile())->extension_service();
163  EXPECT_TRUE(service->GetExtensionById(extension_ids_["enabled_extension"],
164                                        false));
165
166  // Ensure that all actions are allowed.
167  extensions::ExtensionSystem::Get(
168      browser()->profile())->management_policy()->UnregisterAllProviders();
169
170  ASSERT_TRUE(RunExtensionSubtest("management/management_policy",
171                                  "allowed.html"));
172  // The last thing the test does is uninstall the "enabled_extension".
173  EXPECT_FALSE(service->GetExtensionById(extension_ids_["enabled_extension"],
174                                         true));
175}
176
177// Fails often on Windows dbg bots. http://crbug.com/177163
178#if defined(OS_WIN)
179#define MAYBE_ManagementPolicyProhibited DISABLED_ManagementPolicyProhibited
180#else
181#define MAYBE_ManagementPolicyProhibited ManagementPolicyProhibited
182#endif  // defined(OS_WIN)
183// Tests actions on extensions when management policy prohibits those actions.
184IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,
185                       MAYBE_ManagementPolicyProhibited) {
186  LoadExtensions();
187  ExtensionService* service = extensions::ExtensionSystem::Get(
188      browser()->profile())->extension_service();
189  EXPECT_TRUE(service->GetExtensionById(extension_ids_["enabled_extension"],
190                                        false));
191
192  // Prohibit status changes.
193  extensions::ManagementPolicy* policy = extensions::ExtensionSystem::Get(
194      browser()->profile())->management_policy();
195  policy->UnregisterAllProviders();
196  extensions::TestManagementPolicyProvider provider(
197    extensions::TestManagementPolicyProvider::PROHIBIT_MODIFY_STATUS);
198  policy->RegisterProvider(&provider);
199  ASSERT_TRUE(RunExtensionSubtest("management/management_policy",
200                                  "prohibited.html"));
201}
202
203// Disabled. See http://crbug.com/176023
204IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, DISABLED_LaunchPanelApp) {
205  ExtensionService* service = extensions::ExtensionSystem::Get(
206      browser()->profile())->extension_service();
207
208  // Load an extension that calls launchApp() on any app that gets
209  // installed.
210  ExtensionTestMessageListener launcher_loaded("launcher loaded", false);
211  ASSERT_TRUE(LoadExtension(
212      test_data_dir_.AppendASCII("management/launch_on_install")));
213  ASSERT_TRUE(launcher_loaded.WaitUntilSatisfied());
214
215  // Load an app with app.launch.container = "panel".
216  std::string app_id;
217  LoadAndWaitForLaunch("management/launch_app_panel", &app_id);
218  ASSERT_FALSE(HasFatalFailure());  // Stop the test if any ASSERT failed.
219
220  // Find the app's browser.  Check that it is a popup.
221  ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile(),
222                                        browser()->host_desktop_type()));
223  Browser* app_browser = FindOtherBrowser(browser());
224  ASSERT_TRUE(app_browser->is_type_popup());
225  ASSERT_TRUE(app_browser->is_app());
226
227  // Close the app panel.
228  content::WindowedNotificationObserver signal(
229      chrome::NOTIFICATION_BROWSER_CLOSED,
230      content::Source<Browser>(app_browser));
231
232  chrome::CloseWindow(app_browser);
233  signal.Wait();
234
235  // Unload the extension.
236  UninstallExtension(app_id);
237  ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
238                                        browser()->host_desktop_type()));
239  ASSERT_FALSE(service->GetExtensionById(app_id, true));
240
241  // Set a pref indicating that the user wants to launch in a regular tab.
242  // This should be ignored, because panel apps always load in a popup.
243  extensions::SetLaunchType(service, app_id, extensions::LAUNCH_TYPE_REGULAR);
244
245  // Load the extension again.
246  std::string app_id_new;
247  LoadAndWaitForLaunch("management/launch_app_panel", &app_id_new);
248  ASSERT_FALSE(HasFatalFailure());
249
250  // If the ID changed, then the pref will not apply to the app.
251  ASSERT_EQ(app_id, app_id_new);
252
253  // Find the app's browser.  Apps that should load in a panel ignore
254  // prefs, so we should still see the launch in a popup.
255  ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile(),
256                                        browser()->host_desktop_type()));
257  app_browser = FindOtherBrowser(browser());
258  ASSERT_TRUE(app_browser->is_type_popup());
259  ASSERT_TRUE(app_browser->is_app());
260}
261
262// Disabled: http://crbug.com/230165
263#if defined(OS_WIN)
264#define MAYBE_LaunchTabApp DISABLED_LaunchTabApp
265#else
266#define MAYBE_LaunchTabApp LaunchTabApp
267#endif
268IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, MAYBE_LaunchTabApp) {
269  ExtensionService* service = extensions::ExtensionSystem::Get(
270      browser()->profile())->extension_service();
271
272  // Load an extension that calls launchApp() on any app that gets
273  // installed.
274  ExtensionTestMessageListener launcher_loaded("launcher loaded", false);
275  ASSERT_TRUE(LoadExtension(
276      test_data_dir_.AppendASCII("management/launch_on_install")));
277  ASSERT_TRUE(launcher_loaded.WaitUntilSatisfied());
278
279  // Code below assumes that the test starts with a single browser window
280  // hosting one tab.
281  ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
282                                        browser()->host_desktop_type()));
283  ASSERT_EQ(1, browser()->tab_strip_model()->count());
284
285  // Load an app with app.launch.container = "tab".
286  std::string app_id;
287  LoadAndWaitForLaunch("management/launch_app_tab", &app_id);
288  ASSERT_FALSE(HasFatalFailure());
289
290  // Check that the app opened in a new tab of the existing browser.
291  ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
292                                        browser()->host_desktop_type()));
293  ASSERT_EQ(2, browser()->tab_strip_model()->count());
294
295  // Unload the extension.
296  UninstallExtension(app_id);
297  ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
298                                        browser()->host_desktop_type()));
299  ASSERT_FALSE(service->GetExtensionById(app_id, true));
300
301  // Set a pref indicating that the user wants to launch in a window.
302  extensions::SetLaunchType(service, app_id, extensions::LAUNCH_TYPE_WINDOW);
303
304  std::string app_id_new;
305  LoadAndWaitForLaunch("management/launch_app_tab", &app_id_new);
306  ASSERT_FALSE(HasFatalFailure());
307
308  // If the ID changed, then the pref will not apply to the app.
309  ASSERT_EQ(app_id, app_id_new);
310
311#if defined(OS_MACOSX)
312  // App windows are not yet implemented on mac os.  We should fall back
313  // to a normal tab.
314  ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile(),
315                                        browser()->host_desktop_type()));
316  ASSERT_EQ(2, browser()->tab_strip_model()->count());
317#else
318  // Find the app's browser.  Opening in a new window will create
319  // a new browser.
320  ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile(),
321                                        browser()->host_desktop_type()));
322  Browser* app_browser = FindOtherBrowser(browser());
323  ASSERT_TRUE(app_browser->is_app());
324#endif
325}
326
327IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, LaunchType) {
328  LoadExtensions();
329  base::FilePath basedir = test_data_dir_.AppendASCII("management");
330  LoadNamedExtension(basedir, "packaged_app");
331
332  ASSERT_TRUE(RunExtensionSubtest("management/test", "launchType.html"));
333}
334
335class ExtensionManagementApiStreamlinedAppsTest
336    : public ExtensionManagementApiTest {
337 public:
338  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
339    ExtensionManagementApiTest::SetUpCommandLine(command_line);
340    command_line->AppendSwitch(switches::kEnableStreamlinedHostedApps);
341  }
342};
343
344IN_PROC_BROWSER_TEST_F(ExtensionManagementApiStreamlinedAppsTest, LaunchType) {
345  LoadExtensions();
346  base::FilePath basedir = test_data_dir_.AppendASCII("management");
347  LoadNamedExtension(basedir, "packaged_app");
348
349  ASSERT_TRUE(RunExtensionSubtest("management/test",
350                                  "launchType.html?streamlined-hosted-apps"));
351}
352