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 <vector> 6 7 #include "base/files/file_path.h" 8 #include "base/files/file_util.h" 9 #include "base/strings/stringprintf.h" 10 #include "base/strings/utf_string_conversions.h" 11 #include "chrome/browser/chrome_notification_types.h" 12 #include "chrome/browser/extensions/api/management/management_api.h" 13 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" 14 #include "chrome/browser/extensions/extension_apitest.h" 15 #include "chrome/browser/extensions/extension_function_test_utils.h" 16 #include "chrome/browser/extensions/extension_install_prompt.h" 17 #include "chrome/browser/extensions/extension_install_ui.h" 18 #include "chrome/browser/extensions/extension_service.h" 19 #include "chrome/browser/extensions/webstore_installer.h" 20 #include "chrome/browser/profiles/profile.h" 21 #include "chrome/browser/ui/browser.h" 22 #include "chrome/browser/ui/tabs/tab_strip_model.h" 23 #include "chrome/common/chrome_switches.h" 24 #include "chrome/test/base/ui_test_utils.h" 25 #include "content/public/browser/gpu_data_manager.h" 26 #include "content/public/browser/notification_observer.h" 27 #include "content/public/browser/notification_registrar.h" 28 #include "content/public/test/browser_test_utils.h" 29 #include "extensions/browser/extension_system.h" 30 #include "gpu/config/gpu_feature_type.h" 31 #include "gpu/config/gpu_info.h" 32 #include "net/dns/mock_host_resolver.h" 33 #include "ui/gl/gl_switches.h" 34 35 using gpu::GpuFeatureType; 36 37 namespace utils = extension_function_test_utils; 38 39 namespace extensions { 40 41 namespace { 42 43 class WebstoreInstallListener : public WebstoreInstaller::Delegate { 44 public: 45 WebstoreInstallListener() 46 : received_failure_(false), received_success_(false), waiting_(false) {} 47 48 virtual void OnExtensionInstallSuccess(const std::string& id) OVERRIDE { 49 received_success_ = true; 50 id_ = id; 51 52 if (waiting_) { 53 waiting_ = false; 54 base::MessageLoopForUI::current()->Quit(); 55 } 56 } 57 58 virtual void OnExtensionInstallFailure( 59 const std::string& id, 60 const std::string& error, 61 WebstoreInstaller::FailureReason reason) OVERRIDE { 62 received_failure_ = true; 63 id_ = id; 64 error_ = error; 65 66 if (waiting_) { 67 waiting_ = false; 68 base::MessageLoopForUI::current()->Quit(); 69 } 70 } 71 72 void Wait() { 73 if (received_success_ || received_failure_) 74 return; 75 76 waiting_ = true; 77 content::RunMessageLoop(); 78 } 79 bool received_success() const { return received_success_; } 80 const std::string& id() const { return id_; } 81 82 private: 83 bool received_failure_; 84 bool received_success_; 85 bool waiting_; 86 std::string id_; 87 std::string error_; 88 }; 89 90 } // namespace 91 92 // A base class for tests below. 93 class ExtensionWebstorePrivateApiTest : public ExtensionApiTest { 94 public: 95 ExtensionWebstorePrivateApiTest() {} 96 virtual ~ExtensionWebstorePrivateApiTest() {} 97 98 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 99 ExtensionApiTest::SetUpCommandLine(command_line); 100 command_line->AppendSwitchASCII( 101 switches::kAppsGalleryURL, 102 "http://www.example.com/files/extensions/api_test"); 103 } 104 105 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 106 ExtensionApiTest::SetUpInProcessBrowserTestFixture(); 107 108 // Start up the test server and get us ready for calling the install 109 // API functions. 110 host_resolver()->AddRule("www.example.com", "127.0.0.1"); 111 ASSERT_TRUE(StartSpawnedTestServer()); 112 ExtensionInstallUI::set_disable_failure_ui_for_tests(); 113 } 114 115 virtual void SetUpOnMainThread() OVERRIDE { 116 ExtensionApiTest::SetUpOnMainThread(); 117 118 ExtensionInstallPrompt::g_auto_confirm_for_tests = 119 ExtensionInstallPrompt::ACCEPT; 120 121 ASSERT_TRUE(webstore_install_dir_.CreateUniqueTempDir()); 122 webstore_install_dir_copy_ = webstore_install_dir_.path(); 123 WebstoreInstaller::SetDownloadDirectoryForTests( 124 &webstore_install_dir_copy_); 125 } 126 127 protected: 128 // Returns a test server URL, but with host 'www.example.com' so it matches 129 // the web store app's extent that we set up via command line flags. 130 GURL DoGetTestServerURL(const std::string& path) { 131 GURL url = test_server()->GetURL(path); 132 133 // Replace the host with 'www.example.com' so it matches the web store 134 // app's extent. 135 GURL::Replacements replace_host; 136 std::string host_str("www.example.com"); 137 replace_host.SetHostStr(host_str); 138 139 return url.ReplaceComponents(replace_host); 140 } 141 142 virtual GURL GetTestServerURL(const std::string& path) { 143 return DoGetTestServerURL( 144 std::string("files/extensions/api_test/webstore_private/") + path); 145 } 146 147 // Navigates to |page| and runs the Extension API test there. Any downloads 148 // of extensions will return the contents of |crx_file|. 149 bool RunInstallTest(const std::string& page, const std::string& crx_file) { 150 // Auto-confirm the uninstallation dialog. 151 ManagementUninstallFunction::SetAutoConfirmForTest(true); 152 #if defined(OS_WIN) && !defined(NDEBUG) 153 // See http://crbug.com/177163 for details. 154 return true; 155 #else 156 GURL crx_url = GetTestServerURL(crx_file); 157 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 158 switches::kAppsGalleryUpdateURL, crx_url.spec()); 159 160 GURL page_url = GetTestServerURL(page); 161 return RunPageTest(page_url.spec()); 162 #endif 163 } 164 165 content::WebContents* GetWebContents() { 166 return browser()->tab_strip_model()->GetActiveWebContents(); 167 } 168 169 ExtensionService* service() { 170 return ExtensionSystem::Get(browser()->profile())->extension_service(); 171 } 172 173 private: 174 base::ScopedTempDir webstore_install_dir_; 175 // WebstoreInstaller needs a reference to a FilePath when setting the download 176 // directory for testing. 177 base::FilePath webstore_install_dir_copy_; 178 }; 179 180 // Test cases for webstore origin frame blocking. 181 // TODO(mkwst): Disabled until new X-Frame-Options behavior rolls into 182 // Chromium, see crbug.com/226018. 183 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, 184 DISABLED_FrameWebstorePageBlocked) { 185 base::string16 expected_title = base::UTF8ToUTF16("PASS: about:blank"); 186 base::string16 failure_title = base::UTF8ToUTF16("FAIL"); 187 content::TitleWatcher watcher(GetWebContents(), expected_title); 188 watcher.AlsoWaitForTitle(failure_title); 189 GURL url = test_server()->GetURL( 190 "files/extensions/api_test/webstore_private/noframe.html"); 191 ui_test_utils::NavigateToURL(browser(), url); 192 base::string16 final_title = watcher.WaitAndGetTitle(); 193 EXPECT_EQ(expected_title, final_title); 194 } 195 196 // TODO(mkwst): Disabled until new X-Frame-Options behavior rolls into 197 // Chromium, see crbug.com/226018. 198 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, 199 DISABLED_FrameErrorPageBlocked) { 200 base::string16 expected_title = base::UTF8ToUTF16("PASS: about:blank"); 201 base::string16 failure_title = base::UTF8ToUTF16("FAIL"); 202 content::TitleWatcher watcher(GetWebContents(), expected_title); 203 watcher.AlsoWaitForTitle(failure_title); 204 GURL url = test_server()->GetURL( 205 "files/extensions/api_test/webstore_private/noframe2.html"); 206 ui_test_utils::NavigateToURL(browser(), url); 207 base::string16 final_title = watcher.WaitAndGetTitle(); 208 EXPECT_EQ(expected_title, final_title); 209 } 210 211 // Test cases where the user accepts the install confirmation dialog. 212 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallAccepted) { 213 ASSERT_TRUE(RunInstallTest("accepted.html", "extension.crx")); 214 } 215 216 // Test having the default download directory missing. 217 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, MissingDownloadDir) { 218 // Set a non-existent directory as the download path. 219 base::ScopedTempDir temp_dir; 220 EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); 221 base::FilePath missing_directory = temp_dir.Take(); 222 EXPECT_TRUE(base::DeleteFile(missing_directory, true)); 223 WebstoreInstaller::SetDownloadDirectoryForTests(&missing_directory); 224 225 // Now run the install test, which should succeed. 226 ASSERT_TRUE(RunInstallTest("accepted.html", "extension.crx")); 227 228 // Cleanup. 229 if (base::DirectoryExists(missing_directory)) 230 EXPECT_TRUE(base::DeleteFile(missing_directory, true)); 231 } 232 233 // Tests passing a localized name. 234 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallLocalized) { 235 ASSERT_TRUE(RunInstallTest("localized.html", "localized_extension.crx")); 236 } 237 238 // Now test the case where the user cancels the confirmation dialog. 239 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, InstallCancelled) { 240 ExtensionInstallPrompt::g_auto_confirm_for_tests = 241 ExtensionInstallPrompt::CANCEL; 242 ASSERT_TRUE(RunInstallTest("cancelled.html", "extension.crx")); 243 } 244 245 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IncorrectManifest1) { 246 ASSERT_TRUE(RunInstallTest("incorrect_manifest1.html", "extension.crx")); 247 } 248 249 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IncorrectManifest2) { 250 ASSERT_TRUE(RunInstallTest("incorrect_manifest2.html", "extension.crx")); 251 } 252 253 // Disabled: http://crbug.com/174399 and http://crbug.com/177163 254 #if defined(OS_WIN) && (defined(USE_AURA) || !defined(NDEBUG)) 255 #define MAYBE_AppInstallBubble DISABLED_AppInstallBubble 256 #else 257 #define MAYBE_AppInstallBubble AppInstallBubble 258 #endif 259 260 // Tests that we can request an app installed bubble (instead of the default 261 // UI when an app is installed). 262 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, 263 MAYBE_AppInstallBubble) { 264 WebstoreInstallListener listener; 265 WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener); 266 ASSERT_TRUE(RunInstallTest("app_install_bubble.html", "app.crx")); 267 listener.Wait(); 268 ASSERT_TRUE(listener.received_success()); 269 ASSERT_EQ("iladmdjkfniedhfhcfoefgojhgaiaccc", listener.id()); 270 } 271 272 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IsInIncognitoMode) { 273 GURL page_url = GetTestServerURL("incognito.html"); 274 ASSERT_TRUE( 275 RunPageTest(page_url.spec(), ExtensionApiTest::kFlagUseIncognito)); 276 } 277 278 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, IsNotInIncognitoMode) { 279 GURL page_url = GetTestServerURL("not_incognito.html"); 280 ASSERT_TRUE(RunPageTest(page_url.spec())); 281 } 282 283 // Fails often on Windows dbg bots. http://crbug.com/177163. 284 #if defined(OS_WIN) 285 #define MAYBE_IconUrl DISABLED_IconUrl 286 #else 287 #define MAYBE_IconUrl IconUrl 288 #endif // defined(OS_WIN) 289 // Tests using the iconUrl parameter to the install function. 290 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, MAYBE_IconUrl) { 291 ASSERT_TRUE(RunInstallTest("icon_url.html", "extension.crx")); 292 } 293 294 // http://crbug.com/177163 295 #if defined(OS_WIN) && !defined(NDEBUG) 296 #define MAYBE_BeginInstall DISABLED_BeginInstall 297 #else 298 #define MAYBE_BeginInstall BeginInstall 299 #endif 300 // Tests that the Approvals are properly created in beginInstall. 301 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, MAYBE_BeginInstall) { 302 std::string appId = "iladmdjkfniedhfhcfoefgojhgaiaccc"; 303 std::string extensionId = "enfkhcelefdadlmkffamgdlgplcionje"; 304 ASSERT_TRUE(RunInstallTest("begin_install.html", "extension.crx")); 305 306 scoped_ptr<WebstoreInstaller::Approval> approval = 307 WebstorePrivateApi::PopApprovalForTesting(browser()->profile(), appId); 308 EXPECT_EQ(appId, approval->extension_id); 309 EXPECT_TRUE(approval->use_app_installed_bubble); 310 EXPECT_FALSE(approval->skip_post_install_ui); 311 EXPECT_EQ("2", approval->authuser); 312 EXPECT_EQ(browser()->profile(), approval->profile); 313 314 approval = WebstorePrivateApi::PopApprovalForTesting( 315 browser()->profile(), extensionId); 316 EXPECT_EQ(extensionId, approval->extension_id); 317 EXPECT_FALSE(approval->use_app_installed_bubble); 318 EXPECT_FALSE(approval->skip_post_install_ui); 319 EXPECT_TRUE(approval->authuser.empty()); 320 EXPECT_EQ(browser()->profile(), approval->profile); 321 } 322 323 // http://crbug.com/177163 324 #if defined(OS_WIN) && !defined(NDEBUG) 325 #define MAYBE_InstallTheme DISABLED_InstallTheme 326 #else 327 #define MAYBE_InstallTheme InstallTheme 328 #endif 329 // Tests that themes are installed without an install prompt. 330 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, MAYBE_InstallTheme) { 331 WebstoreInstallListener listener; 332 WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener); 333 ASSERT_TRUE(RunInstallTest("theme.html", "../../theme.crx")); 334 listener.Wait(); 335 ASSERT_TRUE(listener.received_success()); 336 ASSERT_EQ("iamefpfkojoapidjnbafmgkgncegbkad", listener.id()); 337 } 338 339 // Tests that an error is properly reported when an empty crx is returned. 340 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, EmptyCrx) { 341 ASSERT_TRUE(RunInstallTest("empty.html", "empty.crx")); 342 } 343 344 class ExtensionWebstoreGetWebGLStatusTest : public InProcessBrowserTest { 345 protected: 346 void RunTest(bool webgl_allowed) { 347 // If Gpu access is disallowed then WebGL will not be available. 348 if (!content::GpuDataManager::GetInstance()->GpuAccessAllowed(NULL)) 349 webgl_allowed = false; 350 351 static const char kEmptyArgs[] = "[]"; 352 static const char kWebGLStatusAllowed[] = "webgl_allowed"; 353 static const char kWebGLStatusBlocked[] = "webgl_blocked"; 354 scoped_refptr<WebstorePrivateGetWebGLStatusFunction> function = 355 new WebstorePrivateGetWebGLStatusFunction(); 356 scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult( 357 function.get(), kEmptyArgs, browser())); 358 ASSERT_TRUE(result); 359 EXPECT_EQ(base::Value::TYPE_STRING, result->GetType()); 360 std::string webgl_status; 361 EXPECT_TRUE(result->GetAsString(&webgl_status)); 362 EXPECT_STREQ(webgl_allowed ? kWebGLStatusAllowed : kWebGLStatusBlocked, 363 webgl_status.c_str()); 364 } 365 }; 366 367 // Tests getWebGLStatus function when WebGL is allowed. 368 IN_PROC_BROWSER_TEST_F(ExtensionWebstoreGetWebGLStatusTest, Allowed) { 369 bool webgl_allowed = true; 370 RunTest(webgl_allowed); 371 } 372 373 // Tests getWebGLStatus function when WebGL is blacklisted. 374 IN_PROC_BROWSER_TEST_F(ExtensionWebstoreGetWebGLStatusTest, Blocked) { 375 static const std::string json_blacklist = 376 "{\n" 377 " \"name\": \"gpu blacklist\",\n" 378 " \"version\": \"1.0\",\n" 379 " \"entries\": [\n" 380 " {\n" 381 " \"id\": 1,\n" 382 " \"features\": [\n" 383 " \"webgl\"\n" 384 " ]\n" 385 " }\n" 386 " ]\n" 387 "}"; 388 gpu::GPUInfo gpu_info; 389 content::GpuDataManager::GetInstance()->InitializeForTesting( 390 json_blacklist, gpu_info); 391 EXPECT_TRUE(content::GpuDataManager::GetInstance()->IsFeatureBlacklisted( 392 gpu::GPU_FEATURE_TYPE_WEBGL)); 393 394 bool webgl_allowed = false; 395 RunTest(webgl_allowed); 396 } 397 398 class EphemeralAppWebstorePrivateApiTest 399 : public ExtensionWebstorePrivateApiTest { 400 public: 401 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 402 ExtensionWebstorePrivateApiTest::SetUpInProcessBrowserTestFixture(); 403 404 net::HostPortPair host_port = test_server()->host_port_pair(); 405 std::string test_gallery_url = base::StringPrintf( 406 "http://www.example.com:%d/files/extensions/platform_apps/" 407 "ephemeral_launcher", 408 host_port.port()); 409 CommandLine::ForCurrentProcess()->AppendSwitchASCII( 410 switches::kAppsGalleryURL, test_gallery_url); 411 } 412 413 virtual GURL GetTestServerURL(const std::string& path) OVERRIDE { 414 return DoGetTestServerURL( 415 std::string("files/extensions/platform_apps/ephemeral_launcher/") + 416 path); 417 } 418 }; 419 420 // Run tests when the --enable-ephemeral-apps switch is not enabled. 421 IN_PROC_BROWSER_TEST_F(EphemeralAppWebstorePrivateApiTest, 422 EphemeralAppsFeatureDisabled) { 423 ASSERT_TRUE(RunInstallTest("webstore_launch_disabled.html", "app.crx")); 424 } 425 426 // Run tests when the --enable-ephemeral-apps switch is enabled. 427 IN_PROC_BROWSER_TEST_F(EphemeralAppWebstorePrivateApiTest, LaunchEphemeralApp) { 428 CommandLine::ForCurrentProcess()->AppendSwitch( 429 switches::kEnableEphemeralApps); 430 ASSERT_TRUE(RunInstallTest("webstore_launch_app.html", "app.crx")); 431 } 432 433 } // namespace extensions 434