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