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 26 using extensions::Extension; 27 using extensions::Manifest; 28 29 namespace { 30 31 // Find a browser other than |browser|. 32 Browser* 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 44 class 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 102 IN_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 115 IN_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 127 IN_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 134 IN_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 144 IN_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. 157 IN_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. 184 IN_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 204 IN_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 268 IN_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 327 IN_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 335 class 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 344 IN_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