Disable accessible touch exploration by default.
[chromium-blink-merge.git] / chrome / browser / apps / ephemeral_app_launcher_browsertest.cc
blob0b9a779b52a7c575cb8a5494f89e6f95f0f2143e
1 // Copyright 2014 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.
5 #include "base/message_loop/message_loop_proxy.h"
6 #include "chrome/browser/apps/ephemeral_app_launcher.h"
7 #include "chrome/browser/extensions/extension_install_checker.h"
8 #include "chrome/browser/extensions/extension_service.h"
9 #include "chrome/browser/extensions/extension_test_message_listener.h"
10 #include "chrome/browser/extensions/install_tracker.h"
11 #include "chrome/browser/extensions/test_blacklist.h"
12 #include "chrome/browser/extensions/webstore_installer_test.h"
13 #include "chrome/browser/ui/browser_finder.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "content/public/browser/web_contents.h"
17 #include "content/public/test/test_utils.h"
18 #include "extensions/browser/extension_prefs.h"
19 #include "extensions/browser/extension_registry.h"
20 #include "extensions/browser/extension_system.h"
21 #include "extensions/browser/extension_util.h"
22 #include "extensions/browser/management_policy.h"
24 using extensions::Extension;
25 using extensions::ExtensionPrefs;
26 using extensions::ExtensionRegistry;
27 using extensions::ExtensionSystem;
28 using extensions::InstallTracker;
29 namespace webstore_install = extensions::webstore_install;
31 namespace {
33 const char kWebstoreDomain[] = "cws.com";
34 const char kAppDomain[] = "app.com";
35 const char kNonAppDomain[] = "nonapp.com";
36 const char kTestDataPath[] = "extensions/platform_apps/ephemeral_launcher";
38 const char kExtensionId[] = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeid";
39 const char kExtensionTestPath[] = "extension";
40 const char kLegacyAppId[] = "lnbochkobjfnhbnbljgfgokadhmbahcn";
41 const char kLegacyAppTestPath[] = "legacy_app";
42 const char kNonExistentId[] = "baaaaaaaaaaaaaaaaaaaaaaaaaaaadid";
43 const char kDefaultAppId[] = "kbiancnbopdghkfedjhfdoegjadfjeal";
44 const char kDefaultAppCrxFilename[] = "app.crx";
45 const char kDefaultAppTestPath[] = "app";
46 const char kAppWithPermissionsId[] = "mbfcnecjknjpipkfkoangpfnhhlpamki";
47 const char kAppWithPermissionsFilename[] = "app_with_permissions.crx";
48 const char kHostedAppId[] = "haaaaaaaaaaaaaaaaaaaaaaaaaaappid";
49 const char kHostedAppLaunchUrl[] = "http://foo.bar.com";
51 class ExtensionInstallCheckerMock : public extensions::ExtensionInstallChecker {
52 public:
53 ExtensionInstallCheckerMock(Profile* profile,
54 const std::string& requirements_error)
55 : extensions::ExtensionInstallChecker(profile),
56 requirements_error_(requirements_error) {}
58 virtual ~ExtensionInstallCheckerMock() {}
60 private:
61 virtual void CheckRequirements() OVERRIDE {
62 // Simulate an asynchronous operation.
63 base::MessageLoopProxy::current()->PostTask(
64 FROM_HERE,
65 base::Bind(&ExtensionInstallCheckerMock::RequirementsErrorCheckDone,
66 base::Unretained(this),
67 current_sequence_number()));
70 void RequirementsErrorCheckDone(int sequence_number) {
71 std::vector<std::string> errors;
72 errors.push_back(requirements_error_);
73 OnRequirementsCheckDone(sequence_number, errors);
76 std::string requirements_error_;
79 class EphemeralAppLauncherForTest : public EphemeralAppLauncher {
80 public:
81 EphemeralAppLauncherForTest(const std::string& id,
82 Profile* profile,
83 const LaunchCallback& callback)
84 : EphemeralAppLauncher(id, profile, NULL, callback),
85 install_initiated_(false),
86 install_prompt_created_(false) {}
88 EphemeralAppLauncherForTest(const std::string& id, Profile* profile)
89 : EphemeralAppLauncher(id, profile, NULL, LaunchCallback()),
90 install_initiated_(false),
91 install_prompt_created_(false) {}
93 bool install_initiated() const { return install_initiated_; }
94 bool install_prompt_created() const { return install_prompt_created_; }
96 void set_requirements_error(const std::string& error) {
97 requirements_check_error_ = error;
100 private:
101 // Override necessary functions for testing.
103 virtual scoped_ptr<extensions::ExtensionInstallChecker> CreateInstallChecker()
104 OVERRIDE {
105 if (requirements_check_error_.empty()) {
106 return EphemeralAppLauncher::CreateInstallChecker();
107 } else {
108 return scoped_ptr<extensions::ExtensionInstallChecker>(
109 new ExtensionInstallCheckerMock(profile(),
110 requirements_check_error_));
114 virtual scoped_ptr<ExtensionInstallPrompt> CreateInstallUI() OVERRIDE {
115 install_prompt_created_ = true;
116 return EphemeralAppLauncher::CreateInstallUI();
119 virtual scoped_ptr<extensions::WebstoreInstaller::Approval> CreateApproval()
120 const OVERRIDE {
121 install_initiated_ = true;
122 return EphemeralAppLauncher::CreateApproval();
125 private:
126 virtual ~EphemeralAppLauncherForTest() {}
127 friend class base::RefCountedThreadSafe<EphemeralAppLauncherForTest>;
129 mutable bool install_initiated_;
130 std::string requirements_check_error_;
131 bool install_prompt_created_;
134 class LaunchObserver {
135 public:
136 LaunchObserver()
137 : done_(false),
138 waiting_(false),
139 result_(webstore_install::OTHER_ERROR) {}
141 webstore_install::Result result() const { return result_; }
142 const std::string& error() const { return error_; }
144 void OnLaunchCallback(webstore_install::Result result,
145 const std::string& error) {
146 result_ = result;
147 error_ = error;
148 done_ = true;
149 if (waiting_) {
150 waiting_ = false;
151 base::MessageLoopForUI::current()->Quit();
155 void Wait() {
156 if (done_)
157 return;
159 waiting_ = true;
160 content::RunMessageLoop();
163 private:
164 bool done_;
165 bool waiting_;
166 webstore_install::Result result_;
167 std::string error_;
170 class ManagementPolicyMock : public extensions::ManagementPolicy::Provider {
171 public:
172 ManagementPolicyMock() {}
174 virtual std::string GetDebugPolicyProviderName() const OVERRIDE {
175 return "ManagementPolicyMock";
178 virtual bool UserMayLoad(const Extension* extension,
179 base::string16* error) const OVERRIDE {
180 return false;
184 } // namespace
186 class EphemeralAppLauncherTest : public WebstoreInstallerTest {
187 public:
188 EphemeralAppLauncherTest()
189 : WebstoreInstallerTest(kWebstoreDomain,
190 kTestDataPath,
191 kDefaultAppCrxFilename,
192 kAppDomain,
193 kNonAppDomain) {}
195 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
196 WebstoreInstallerTest::SetUpCommandLine(command_line);
198 // Enable ephemeral apps flag.
199 command_line->AppendSwitch(switches::kEnableEphemeralApps);
202 base::FilePath GetTestPath(const char* test_name) {
203 return test_data_dir_.AppendASCII("platform_apps/ephemeral_launcher")
204 .AppendASCII(test_name);
207 const Extension* GetInstalledExtension(const std::string& id) {
208 return ExtensionRegistry::Get(profile())
209 ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
212 void SetCrxFilename(const std::string& filename) {
213 GURL crx_url = GenerateTestServerUrl(kWebstoreDomain, filename);
214 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
215 switches::kAppsGalleryUpdateURL, crx_url.spec());
218 void StartLauncherAndCheckResult(EphemeralAppLauncherForTest* launcher,
219 webstore_install::Result expected_result,
220 bool expect_install_initiated) {
221 ExtensionTestMessageListener launched_listener("launched", false);
222 LaunchObserver launch_observer;
224 launcher->launch_callback_ = base::Bind(&LaunchObserver::OnLaunchCallback,
225 base::Unretained(&launch_observer));
226 launcher->Start();
227 launch_observer.Wait();
229 // Verify the launch result.
230 EXPECT_EQ(expected_result, launch_observer.result());
231 EXPECT_EQ(expect_install_initiated, launcher->install_initiated());
233 // Verify that the app was actually launched if the launcher succeeded.
234 if (launch_observer.result() == webstore_install::SUCCESS)
235 EXPECT_TRUE(launched_listener.WaitUntilSatisfied());
236 else
237 EXPECT_FALSE(launched_listener.was_satisfied());
239 // Check the reference count to ensure the launcher instance will not be
240 // leaked.
241 EXPECT_TRUE(launcher->HasOneRef());
244 void RunLaunchTest(const std::string& id,
245 webstore_install::Result expected_result,
246 bool expect_install_initiated) {
247 InstallTracker* tracker = InstallTracker::Get(profile());
248 ASSERT_TRUE(tracker);
249 bool was_install_active = !!tracker->GetActiveInstall(id);
251 scoped_refptr<EphemeralAppLauncherForTest> launcher(
252 new EphemeralAppLauncherForTest(id, profile()));
253 StartLauncherAndCheckResult(
254 launcher.get(), expected_result, expect_install_initiated);
256 // Verify that the install was deregistered from the InstallTracker.
257 EXPECT_EQ(was_install_active, !!tracker->GetActiveInstall(id));
260 void ValidateAppInstalledEphemerally(const std::string& id) {
261 EXPECT_TRUE(GetInstalledExtension(id));
262 EXPECT_TRUE(extensions::util::IsEphemeralApp(id, profile()));
265 const Extension* InstallAndDisableApp(
266 const char* test_path,
267 Extension::DisableReason disable_reason) {
268 const Extension* app = InstallExtension(GetTestPath(test_path), 1);
269 EXPECT_TRUE(app);
270 if (!app)
271 return NULL;
273 if (disable_reason == Extension::DISABLE_GREYLIST) {
274 ExtensionPrefs::Get(profile())->SetExtensionBlacklistState(
275 app->id(), extensions::BLACKLISTED_MALWARE);
278 ExtensionService* service =
279 ExtensionSystem::Get(profile())->extension_service();
280 service->DisableExtension(app->id(), disable_reason);
282 if (disable_reason == Extension::DISABLE_PERMISSIONS_INCREASE) {
283 // When an extension is disabled due to a permissions increase, this
284 // flag needs to be set too, for some reason.
285 ExtensionPrefs::Get(profile())
286 ->SetDidExtensionEscalatePermissions(app, true);
289 EXPECT_FALSE(
290 ExtensionRegistry::Get(profile())->enabled_extensions().Contains(
291 app->id()));
292 return app;
296 class EphemeralAppLauncherTestDisabled : public EphemeralAppLauncherTest {
297 public:
298 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
299 // Skip EphemeralAppLauncherTest as it enables the feature.
300 WebstoreInstallerTest::SetUpCommandLine(command_line);
304 // Verifies that an ephemeral app will not be installed and launched if the
305 // feature is disabled.
306 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTestDisabled, FeatureDisabled) {
307 RunLaunchTest(
308 kDefaultAppCrxFilename, webstore_install::LAUNCH_FEATURE_DISABLED, false);
309 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
312 // Verifies that an app with no permission warnings will be installed
313 // ephemerally and launched without prompting the user.
314 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
315 LaunchAppWithNoPermissionWarnings) {
316 scoped_refptr<EphemeralAppLauncherForTest> launcher(
317 new EphemeralAppLauncherForTest(kDefaultAppId, profile()));
318 StartLauncherAndCheckResult(launcher.get(), webstore_install::SUCCESS, true);
319 ValidateAppInstalledEphemerally(kDefaultAppId);
321 // Apps with no permission warnings should not result in a prompt.
322 EXPECT_FALSE(launcher->install_prompt_created());
324 // After an app has been installed ephemerally, it can be launched again
325 // without installing from the web store.
326 RunLaunchTest(kDefaultAppId, webstore_install::SUCCESS, false);
329 // Verifies that an app with permission warnings will be installed
330 // ephemerally and launched if accepted by the user.
331 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
332 LaunchAppWithPermissionsWarnings) {
333 SetCrxFilename(kAppWithPermissionsFilename);
334 AutoAcceptInstall();
336 scoped_refptr<EphemeralAppLauncherForTest> launcher(
337 new EphemeralAppLauncherForTest(kAppWithPermissionsId, profile()));
338 StartLauncherAndCheckResult(launcher.get(), webstore_install::SUCCESS, true);
339 ValidateAppInstalledEphemerally(kAppWithPermissionsId);
340 EXPECT_TRUE(launcher->install_prompt_created());
343 // Verifies that an app with permission warnings will not be installed
344 // ephemerally if cancelled by the user.
345 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
346 CancelInstallAppWithPermissionWarnings) {
347 SetCrxFilename(kAppWithPermissionsFilename);
348 AutoCancelInstall();
350 scoped_refptr<EphemeralAppLauncherForTest> launcher(
351 new EphemeralAppLauncherForTest(kAppWithPermissionsId, profile()));
352 StartLauncherAndCheckResult(
353 launcher.get(), webstore_install::USER_CANCELLED, false);
354 EXPECT_FALSE(GetInstalledExtension(kAppWithPermissionsId));
355 EXPECT_TRUE(launcher->install_prompt_created());
358 // Verifies that an extension will not be installed ephemerally.
359 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallExtension) {
360 RunLaunchTest(
361 kExtensionId, webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE, false);
362 EXPECT_FALSE(GetInstalledExtension(kExtensionId));
365 // Verifies that an already installed extension will not be launched.
366 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchExtension) {
367 const Extension* extension =
368 InstallExtension(GetTestPath(kExtensionTestPath), 1);
369 ASSERT_TRUE(extension);
370 RunLaunchTest(extension->id(),
371 webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE,
372 false);
375 // Verifies that a legacy packaged app will not be installed ephemerally.
376 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallLegacyApp) {
377 RunLaunchTest(
378 kLegacyAppId, webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE, false);
379 EXPECT_FALSE(GetInstalledExtension(kLegacyAppId));
382 // Verifies that a legacy packaged app that is already installed can be
383 // launched.
384 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchLegacyApp) {
385 const Extension* extension =
386 InstallExtension(GetTestPath(kLegacyAppTestPath), 1);
387 ASSERT_TRUE(extension);
388 RunLaunchTest(extension->id(), webstore_install::SUCCESS, false);
391 // Verifies that a hosted app is not installed. Launch succeeds because we
392 // navigate to its launch url.
393 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchHostedApp) {
394 LaunchObserver launch_observer;
396 scoped_refptr<EphemeralAppLauncherForTest> launcher(
397 new EphemeralAppLauncherForTest(
398 kHostedAppId,
399 profile(),
400 base::Bind(&LaunchObserver::OnLaunchCallback,
401 base::Unretained(&launch_observer))));
402 launcher->Start();
403 launch_observer.Wait();
405 EXPECT_EQ(webstore_install::SUCCESS, launch_observer.result());
406 EXPECT_FALSE(launcher->install_initiated());
407 EXPECT_FALSE(GetInstalledExtension(kHostedAppId));
409 // Verify that a navigation to the launch url was attempted.
410 Browser* browser =
411 FindBrowserWithProfile(profile(), chrome::GetActiveDesktop());
412 ASSERT_TRUE(browser);
413 content::WebContents* web_contents =
414 browser->tab_strip_model()->GetActiveWebContents();
415 ASSERT_TRUE(web_contents);
416 EXPECT_EQ(GURL(kHostedAppLaunchUrl), web_contents->GetVisibleURL());
419 // Verifies that the EphemeralAppLauncher handles non-existent extension ids.
420 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, NonExistentExtensionId) {
421 RunLaunchTest(
422 kNonExistentId, webstore_install::WEBSTORE_REQUEST_ERROR, false);
423 EXPECT_FALSE(GetInstalledExtension(kNonExistentId));
426 // Verifies that an app blocked by management policy is not installed
427 // ephemerally.
428 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlockedByPolicy) {
429 // Register a provider that blocks the installation of all apps.
430 ManagementPolicyMock policy;
431 ExtensionSystem::Get(profile())->management_policy()->RegisterProvider(
432 &policy);
434 RunLaunchTest(kDefaultAppId, webstore_install::BLOCKED_BY_POLICY, false);
435 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
438 // Verifies that an app blacklisted for malware is not installed ephemerally.
439 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlacklistedForMalware) {
440 // Mock a BLACKLISTED_MALWARE return status.
441 extensions::TestBlacklist blacklist_tester(
442 ExtensionSystem::Get(profile())->blacklist());
443 blacklist_tester.SetBlacklistState(
444 kDefaultAppId, extensions::BLACKLISTED_MALWARE, false);
446 RunLaunchTest(kDefaultAppId, webstore_install::BLACKLISTED, false);
447 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
450 // Verifies that an app with unknown blacklist status is installed ephemerally
451 // and launched.
452 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlacklistStateUnknown) {
453 // Mock a BLACKLISTED_MALWARE return status.
454 extensions::TestBlacklist blacklist_tester(
455 ExtensionSystem::Get(profile())->blacklist());
456 blacklist_tester.SetBlacklistState(
457 kDefaultAppId, extensions::BLACKLISTED_UNKNOWN, false);
459 RunLaunchTest(kDefaultAppId, webstore_install::SUCCESS, true);
460 ValidateAppInstalledEphemerally(kDefaultAppId);
463 // Verifies that an app with unsupported requirements is not installed
464 // ephemerally.
465 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, UnsupportedRequirements) {
466 scoped_refptr<EphemeralAppLauncherForTest> launcher(
467 new EphemeralAppLauncherForTest(kDefaultAppId, profile()));
468 launcher->set_requirements_error("App has unsupported requirements");
470 StartLauncherAndCheckResult(
471 launcher.get(), webstore_install::REQUIREMENT_VIOLATIONS, false);
472 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
475 // Verifies that an app disabled due to permissions increase can be enabled
476 // and launched.
477 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, EnableAndLaunchApp) {
478 const Extension* app = InstallAndDisableApp(
479 kDefaultAppTestPath, Extension::DISABLE_PERMISSIONS_INCREASE);
480 ASSERT_TRUE(app);
482 AutoAcceptInstall();
483 RunLaunchTest(app->id(), webstore_install::SUCCESS, false);
486 // Verifies that if the user cancels the enable flow, the app will not be
487 // enabled and launched.
488 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, EnableCancelled) {
489 const Extension* app = InstallAndDisableApp(
490 kDefaultAppTestPath, Extension::DISABLE_PERMISSIONS_INCREASE);
491 ASSERT_TRUE(app);
493 AutoCancelInstall();
494 RunLaunchTest(app->id(), webstore_install::USER_CANCELLED, false);
497 // Verifies that an installed app that had been blocked by policy cannot be
498 // launched.
499 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchAppBlockedByPolicy) {
500 const Extension* app = InstallExtension(GetTestPath(kDefaultAppTestPath), 1);
501 ASSERT_TRUE(app);
503 // Simulate blocking of the app after it has been installed.
504 ManagementPolicyMock policy;
505 ExtensionSystem::Get(profile())->management_policy()->RegisterProvider(
506 &policy);
507 ExtensionSystem::Get(profile())->extension_service()->CheckManagementPolicy();
509 RunLaunchTest(app->id(), webstore_install::BLOCKED_BY_POLICY, false);
512 // Verifies that an installed blacklisted app cannot be launched.
513 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchBlacklistedApp) {
514 const Extension* app =
515 InstallAndDisableApp(kDefaultAppTestPath, Extension::DISABLE_GREYLIST);
516 ASSERT_TRUE(app);
518 RunLaunchTest(app->id(), webstore_install::BLACKLISTED, false);
521 // Verifies that an installed app with unsupported requirements cannot be
522 // launched.
523 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
524 LaunchAppWithUnsupportedRequirements) {
525 const Extension* app = InstallAndDisableApp(
526 kDefaultAppTestPath, Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
527 ASSERT_TRUE(app);
529 RunLaunchTest(app->id(), webstore_install::REQUIREMENT_VIOLATIONS, false);
532 // Verifies that a launch will fail if the app is currently being installed.
533 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallInProgress) {
534 extensions::ActiveInstallData install_data(kDefaultAppId);
535 InstallTracker::Get(profile())->AddActiveInstall(install_data);
537 RunLaunchTest(kDefaultAppId, webstore_install::INSTALL_IN_PROGRESS, false);
540 // Verifies that a launch will fail if a duplicate launch is in progress.
541 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, DuplicateLaunchInProgress) {
542 extensions::ActiveInstallData install_data(kDefaultAppId);
543 install_data.is_ephemeral = true;
544 InstallTracker::Get(profile())->AddActiveInstall(install_data);
546 RunLaunchTest(kDefaultAppId, webstore_install::LAUNCH_IN_PROGRESS, false);