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.
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/webstore_private/webstore_private_api.h"
13 #include "chrome/browser/extensions/bundle_installer.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_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 "extensions/browser/api/management/management_api.h"
29 #include "extensions/browser/extension_dialog_auto_confirm.h"
30 #include "extensions/browser/extension_system.h"
31 #include "extensions/browser/install/extension_install_ui.h"
32 #include "gpu/config/gpu_feature_type.h"
33 #include "gpu/config/gpu_info.h"
34 #include "net/dns/mock_host_resolver.h"
35 #include "ui/app_list/app_list_switches.h"
36 #include "ui/gl/gl_switches.h"
38 using gpu::GpuFeatureType
;
40 namespace utils
= extension_function_test_utils
;
42 namespace extensions
{
46 class WebstoreInstallListener
: public WebstoreInstaller::Delegate
{
48 WebstoreInstallListener()
49 : received_failure_(false), received_success_(false), waiting_(false) {}
51 void OnExtensionInstallSuccess(const std::string
& id
) override
{
52 received_success_
= true;
57 base::MessageLoopForUI::current()->Quit();
61 void OnExtensionInstallFailure(
62 const std::string
& id
,
63 const std::string
& error
,
64 WebstoreInstaller::FailureReason reason
) override
{
65 received_failure_
= true;
71 base::MessageLoopForUI::current()->Quit();
76 if (received_success_
|| received_failure_
)
80 content::RunMessageLoop();
82 bool received_success() const { return received_success_
; }
83 const std::string
& id() const { return id_
; }
86 bool received_failure_
;
87 bool received_success_
;
95 // A base class for tests below.
96 class ExtensionWebstorePrivateApiTest
: public ExtensionApiTest
{
98 ExtensionWebstorePrivateApiTest() {}
99 ~ExtensionWebstorePrivateApiTest() override
{}
101 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
102 ExtensionApiTest::SetUpCommandLine(command_line
);
103 command_line
->AppendSwitchASCII(
104 switches::kAppsGalleryURL
,
105 "http://www.example.com/files/extensions/api_test");
108 void SetUpInProcessBrowserTestFixture() override
{
109 ExtensionApiTest::SetUpInProcessBrowserTestFixture();
111 // Start up the test server and get us ready for calling the install
113 host_resolver()->AddRule("www.example.com", "127.0.0.1");
114 ASSERT_TRUE(StartSpawnedTestServer());
115 extensions::ExtensionInstallUI::set_disable_failure_ui_for_tests();
118 void SetUpOnMainThread() override
{
119 ExtensionApiTest::SetUpOnMainThread();
121 auto_confirm_install_
.reset(
122 new ScopedTestDialogAutoConfirm(ScopedTestDialogAutoConfirm::ACCEPT
));
124 ASSERT_TRUE(webstore_install_dir_
.CreateUniqueTempDir());
125 webstore_install_dir_copy_
= webstore_install_dir_
.path();
126 WebstoreInstaller::SetDownloadDirectoryForTests(
127 &webstore_install_dir_copy_
);
131 // Returns a test server URL, but with host 'www.example.com' so it matches
132 // the web store app's extent that we set up via command line flags.
133 GURL
DoGetTestServerURL(const std::string
& path
) {
134 GURL url
= test_server()->GetURL(path
);
136 // Replace the host with 'www.example.com' so it matches the web store
138 GURL::Replacements replace_host
;
139 replace_host
.SetHostStr("www.example.com");
141 return url
.ReplaceComponents(replace_host
);
144 virtual GURL
GetTestServerURL(const std::string
& path
) {
145 return DoGetTestServerURL(
146 std::string("files/extensions/api_test/webstore_private/") + path
);
149 // Navigates to |page| and runs the Extension API test there. Any downloads
150 // of extensions will return the contents of |crx_file|.
151 bool RunInstallTest(const std::string
& page
, const std::string
& crx_file
) {
152 #if defined(OS_WIN) && !defined(NDEBUG)
153 // See http://crbug.com/177163 for details.
156 GURL crx_url
= GetTestServerURL(crx_file
);
157 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
158 switches::kAppsGalleryUpdateURL
, crx_url
.spec());
160 GURL page_url
= GetTestServerURL(page
);
161 return RunPageTest(page_url
.spec());
165 content::WebContents
* GetWebContents() {
166 return browser()->tab_strip_model()->GetActiveWebContents();
169 ExtensionService
* service() {
170 return ExtensionSystem::Get(browser()->profile())->extension_service();
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_
;
179 scoped_ptr
<ScopedTestDialogAutoConfirm
> auto_confirm_install_
;
181 DISALLOW_COPY_AND_ASSIGN(ExtensionWebstorePrivateApiTest
);
184 // Test cases for webstore origin frame blocking.
185 // TODO(mkwst): Disabled until new X-Frame-Options behavior rolls into
186 // Chromium, see crbug.com/226018.
187 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
,
188 DISABLED_FrameWebstorePageBlocked
) {
189 base::string16 expected_title
= base::UTF8ToUTF16("PASS: about:blank");
190 base::string16 failure_title
= base::UTF8ToUTF16("FAIL");
191 content::TitleWatcher
watcher(GetWebContents(), expected_title
);
192 watcher
.AlsoWaitForTitle(failure_title
);
193 GURL url
= test_server()->GetURL(
194 "files/extensions/api_test/webstore_private/noframe.html");
195 ui_test_utils::NavigateToURL(browser(), url
);
196 base::string16 final_title
= watcher
.WaitAndGetTitle();
197 EXPECT_EQ(expected_title
, final_title
);
200 // TODO(mkwst): Disabled until new X-Frame-Options behavior rolls into
201 // Chromium, see crbug.com/226018.
202 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
,
203 DISABLED_FrameErrorPageBlocked
) {
204 base::string16 expected_title
= base::UTF8ToUTF16("PASS: about:blank");
205 base::string16 failure_title
= base::UTF8ToUTF16("FAIL");
206 content::TitleWatcher
watcher(GetWebContents(), expected_title
);
207 watcher
.AlsoWaitForTitle(failure_title
);
208 GURL url
= test_server()->GetURL(
209 "files/extensions/api_test/webstore_private/noframe2.html");
210 ui_test_utils::NavigateToURL(browser(), url
);
211 base::string16 final_title
= watcher
.WaitAndGetTitle();
212 EXPECT_EQ(expected_title
, final_title
);
215 // Test cases where the user accepts the install confirmation dialog.
216 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, InstallAccepted
) {
217 ASSERT_TRUE(RunInstallTest("accepted.html", "extension.crx"));
220 // Test having the default download directory missing.
221 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, MissingDownloadDir
) {
222 // Set a non-existent directory as the download path.
223 base::ScopedTempDir temp_dir
;
224 EXPECT_TRUE(temp_dir
.CreateUniqueTempDir());
225 base::FilePath missing_directory
= temp_dir
.Take();
226 EXPECT_TRUE(base::DeleteFile(missing_directory
, true));
227 WebstoreInstaller::SetDownloadDirectoryForTests(&missing_directory
);
229 // Now run the install test, which should succeed.
230 ASSERT_TRUE(RunInstallTest("accepted.html", "extension.crx"));
233 if (base::DirectoryExists(missing_directory
))
234 EXPECT_TRUE(base::DeleteFile(missing_directory
, true));
237 // Tests passing a localized name.
238 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, InstallLocalized
) {
239 ASSERT_TRUE(RunInstallTest("localized.html", "localized_extension.crx"));
242 // Now test the case where the user cancels the confirmation dialog.
243 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, InstallCancelled
) {
244 ScopedTestDialogAutoConfirm
auto_cancel(ScopedTestDialogAutoConfirm::CANCEL
);
245 ASSERT_TRUE(RunInstallTest("cancelled.html", "extension.crx"));
248 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, IncorrectManifest1
) {
249 ASSERT_TRUE(RunInstallTest("incorrect_manifest1.html", "extension.crx"));
252 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, IncorrectManifest2
) {
253 ASSERT_TRUE(RunInstallTest("incorrect_manifest2.html", "extension.crx"));
256 // Disabled: http://crbug.com/174399 and http://crbug.com/177163
257 #if defined(OS_WIN) && (defined(USE_AURA) || !defined(NDEBUG))
258 #define MAYBE_AppInstallBubble DISABLED_AppInstallBubble
260 #define MAYBE_AppInstallBubble AppInstallBubble
263 // Tests that we can request an app installed bubble (instead of the default
264 // UI when an app is installed).
265 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
,
266 MAYBE_AppInstallBubble
) {
267 WebstoreInstallListener listener
;
268 WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener
);
269 ASSERT_TRUE(RunInstallTest("app_install_bubble.html", "app.crx"));
271 ASSERT_TRUE(listener
.received_success());
272 ASSERT_EQ("iladmdjkfniedhfhcfoefgojhgaiaccc", listener
.id());
275 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, IsInIncognitoMode
) {
276 GURL page_url
= GetTestServerURL("incognito.html");
278 RunPageTest(page_url
.spec(), ExtensionApiTest::kFlagUseIncognito
));
281 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, IsNotInIncognitoMode
) {
282 GURL page_url
= GetTestServerURL("not_incognito.html");
283 ASSERT_TRUE(RunPageTest(page_url
.spec()));
286 // Fails often on Windows dbg bots. http://crbug.com/177163.
288 #define MAYBE_IconUrl DISABLED_IconUrl
290 #define MAYBE_IconUrl IconUrl
291 #endif // defined(OS_WIN)
292 // Tests using the iconUrl parameter to the install function.
293 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, MAYBE_IconUrl
) {
294 ASSERT_TRUE(RunInstallTest("icon_url.html", "extension.crx"));
297 // http://crbug.com/177163
298 #if defined(OS_WIN) && !defined(NDEBUG)
299 #define MAYBE_BeginInstall DISABLED_BeginInstall
301 #define MAYBE_BeginInstall BeginInstall
303 // Tests that the Approvals are properly created in beginInstall.
304 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, MAYBE_BeginInstall
) {
305 std::string appId
= "iladmdjkfniedhfhcfoefgojhgaiaccc";
306 std::string extensionId
= "enfkhcelefdadlmkffamgdlgplcionje";
307 ASSERT_TRUE(RunInstallTest("begin_install.html", "extension.crx"));
309 scoped_ptr
<WebstoreInstaller::Approval
> approval
=
310 WebstorePrivateApi::PopApprovalForTesting(browser()->profile(), appId
);
311 EXPECT_EQ(appId
, approval
->extension_id
);
312 EXPECT_TRUE(approval
->use_app_installed_bubble
);
313 EXPECT_FALSE(approval
->skip_post_install_ui
);
314 EXPECT_EQ("2", approval
->authuser
);
315 EXPECT_EQ(browser()->profile(), approval
->profile
);
317 approval
= WebstorePrivateApi::PopApprovalForTesting(
318 browser()->profile(), extensionId
);
319 EXPECT_EQ(extensionId
, approval
->extension_id
);
320 EXPECT_FALSE(approval
->use_app_installed_bubble
);
321 EXPECT_FALSE(approval
->skip_post_install_ui
);
322 EXPECT_TRUE(approval
->authuser
.empty());
323 EXPECT_EQ(browser()->profile(), approval
->profile
);
326 // http://crbug.com/177163
327 #if defined(OS_WIN) && !defined(NDEBUG)
328 #define MAYBE_InstallTheme DISABLED_InstallTheme
330 #define MAYBE_InstallTheme InstallTheme
332 // Tests that themes are installed without an install prompt.
333 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, MAYBE_InstallTheme
) {
334 WebstoreInstallListener listener
;
335 WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(&listener
);
336 ASSERT_TRUE(RunInstallTest("theme.html", "../../theme.crx"));
338 ASSERT_TRUE(listener
.received_success());
339 ASSERT_EQ("iamefpfkojoapidjnbafmgkgncegbkad", listener
.id());
342 // Tests that an error is properly reported when an empty crx is returned.
343 IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest
, EmptyCrx
) {
344 ASSERT_TRUE(RunInstallTest("empty.html", "empty.crx"));
347 class ExtensionWebstoreGetWebGLStatusTest
: public InProcessBrowserTest
{
349 void RunTest(bool webgl_allowed
) {
350 // If Gpu access is disallowed then WebGL will not be available.
351 if (!content::GpuDataManager::GetInstance()->GpuAccessAllowed(NULL
))
352 webgl_allowed
= false;
354 static const char kEmptyArgs
[] = "[]";
355 static const char kWebGLStatusAllowed
[] = "webgl_allowed";
356 static const char kWebGLStatusBlocked
[] = "webgl_blocked";
357 scoped_refptr
<WebstorePrivateGetWebGLStatusFunction
> function
=
358 new WebstorePrivateGetWebGLStatusFunction();
359 scoped_ptr
<base::Value
> result(utils::RunFunctionAndReturnSingleResult(
360 function
.get(), kEmptyArgs
, browser()));
362 EXPECT_EQ(base::Value::TYPE_STRING
, result
->GetType());
363 std::string webgl_status
;
364 EXPECT_TRUE(result
->GetAsString(&webgl_status
));
365 EXPECT_STREQ(webgl_allowed
? kWebGLStatusAllowed
: kWebGLStatusBlocked
,
366 webgl_status
.c_str());
370 // Tests getWebGLStatus function when WebGL is allowed.
371 IN_PROC_BROWSER_TEST_F(ExtensionWebstoreGetWebGLStatusTest
, Allowed
) {
372 bool webgl_allowed
= true;
373 RunTest(webgl_allowed
);
376 // Tests getWebGLStatus function when WebGL is blacklisted.
377 IN_PROC_BROWSER_TEST_F(ExtensionWebstoreGetWebGLStatusTest
, Blocked
) {
378 static const std::string json_blacklist
=
380 " \"name\": \"gpu blacklist\",\n"
381 " \"version\": \"1.0\",\n"
391 gpu::GPUInfo gpu_info
;
392 content::GpuDataManager::GetInstance()->InitializeForTesting(
393 json_blacklist
, gpu_info
);
394 EXPECT_TRUE(content::GpuDataManager::GetInstance()->IsFeatureBlacklisted(
395 gpu::GPU_FEATURE_TYPE_WEBGL
));
397 bool webgl_allowed
= false;
398 RunTest(webgl_allowed
);
401 class EphemeralAppWebstorePrivateApiTest
402 : public ExtensionWebstorePrivateApiTest
{
404 void SetUpInProcessBrowserTestFixture() override
{
405 ExtensionWebstorePrivateApiTest::SetUpInProcessBrowserTestFixture();
407 net::HostPortPair host_port
= test_server()->host_port_pair();
408 std::string test_gallery_url
= base::StringPrintf(
409 "http://www.example.com:%d/files/extensions/platform_apps/"
410 "ephemeral_launcher",
412 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
413 switches::kAppsGalleryURL
, test_gallery_url
);
416 GURL
GetTestServerURL(const std::string
& path
) override
{
417 return DoGetTestServerURL(
418 std::string("files/extensions/platform_apps/ephemeral_launcher/") +
423 // Run tests when the --enable-ephemeral-apps switch is not enabled.
424 IN_PROC_BROWSER_TEST_F(EphemeralAppWebstorePrivateApiTest
,
425 EphemeralAppsFeatureDisabled
) {
426 base::CommandLine::ForCurrentProcess()->AppendSwitch(
427 app_list::switches::kDisableExperimentalAppList
);
428 ASSERT_TRUE(RunInstallTest("webstore_launch_disabled.html", "app.crx"));
431 // Run tests when the --enable-ephemeral-apps switch is enabled.
432 IN_PROC_BROWSER_TEST_F(EphemeralAppWebstorePrivateApiTest
, LaunchEphemeralApp
) {
433 base::CommandLine::ForCurrentProcess()->AppendSwitch(
434 switches::kEnableEphemeralAppsInWebstore
);
435 base::CommandLine::ForCurrentProcess()->AppendSwitch(
436 app_list::switches::kEnableExperimentalAppList
);
437 ASSERT_TRUE(RunInstallTest("webstore_launch_app.html", "app.crx"));
440 class BundleWebstorePrivateApiTest
441 : public ExtensionWebstorePrivateApiTest
{
443 void SetUpInProcessBrowserTestFixture() override
{
444 ExtensionWebstorePrivateApiTest::SetUpInProcessBrowserTestFixture();
446 test_data_dir_
= test_data_dir_
.AppendASCII("webstore_private/bundle");
448 // The test server needs to have already started, so setup the switch here
449 // rather than in SetUpCommandLine.
450 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
451 switches::kAppsGalleryDownloadURL
,
452 GetTestServerURL("bundle/%s.crx").spec());
456 // Tests successfully installing a bundle of 2 apps and 2 extensions.
457 IN_PROC_BROWSER_TEST_F(BundleWebstorePrivateApiTest
, InstallBundle
) {
458 extensions::BundleInstaller::SetAutoApproveForTesting(true);
459 ASSERT_TRUE(RunPageTest(GetTestServerURL("install_bundle.html").spec()));
462 // Tests that bundles can be installed from incognito windows.
463 IN_PROC_BROWSER_TEST_F(BundleWebstorePrivateApiTest
, InstallBundleIncognito
) {
464 extensions::BundleInstaller::SetAutoApproveForTesting(true);
466 ASSERT_TRUE(RunPageTest(GetTestServerURL("install_bundle.html").spec(),
467 ExtensionApiTest::kFlagUseIncognito
));
470 // Tests the user canceling the bundle install prompt.
471 IN_PROC_BROWSER_TEST_F(BundleWebstorePrivateApiTest
, InstallBundleCancel
) {
472 // We don't need to create the CRX files since we are aborting the install.
473 extensions::BundleInstaller::SetAutoApproveForTesting(false);
476 RunPageTest(GetTestServerURL("install_bundle_cancel.html").spec()));
479 // Tests partially installing a bundle (1 succeeds, 1 fails due to an invalid
480 // CRX, 1 fails due to the manifests not matching, and 1 fails due to a missing
482 IN_PROC_BROWSER_TEST_F(BundleWebstorePrivateApiTest
, InstallBundleInvalid
) {
483 extensions::BundleInstaller::SetAutoApproveForTesting(true);
486 RunPageTest(GetTestServerURL("install_bundle_invalid.html").spec()));
489 } // namespace extensions