[ExtensionToolbarMac] Restrict action button drags to the container's bounds
[chromium-blink-merge.git] / chrome / browser / apps / ephemeral_app_launcher_browsertest.cc
blob6968440bb193c0b1a64ef469b473c011a406b51d
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/apps/ephemeral_app_service.h"
8 #include "chrome/browser/extensions/extension_install_checker.h"
9 #include "chrome/browser/extensions/extension_service.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"
23 #include "extensions/browser/process_manager.h"
24 #include "extensions/common/switches.h"
25 #include "extensions/test/extension_test_message_listener.h"
27 using extensions::Extension;
28 using extensions::ExtensionPrefs;
29 using extensions::ExtensionRegistry;
30 using extensions::ExtensionSystem;
31 using extensions::InstallTracker;
32 namespace webstore_install = extensions::webstore_install;
34 namespace {
36 const char kWebstoreDomain[] = "cws.com";
37 const char kAppDomain[] = "app.com";
38 const char kNonAppDomain[] = "nonapp.com";
39 const char kTestDataPath[] = "extensions/platform_apps/ephemeral_launcher";
41 const char kExtensionId[] = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeid";
42 const char kExtensionTestPath[] = "extension";
43 const char kLegacyAppId[] = "lnbochkobjfnhbnbljgfgokadhmbahcn";
44 const char kLegacyAppTestPath[] = "legacy_app";
45 const char kNonExistentId[] = "baaaaaaaaaaaaaaaaaaaaaaaaaaaadid";
46 const char kDefaultAppId[] = "kbiancnbopdghkfedjhfdoegjadfjeal";
47 const char kDefaultAppCrxFilename[] = "app.crx";
48 const char kDefaultAppTestPath[] = "app";
49 const char kAppWithPermissionsId[] = "mbfcnecjknjpipkfkoangpfnhhlpamki";
50 const char kAppWithPermissionsFilename[] = "app_with_permissions.crx";
51 const char kHostedAppId[] = "haaaaaaaaaaaaaaaaaaaaaaaaaaappid";
52 const char kHostedAppLaunchUrl[] = "http://foo.bar.com";
54 class ExtensionInstallCheckerMock : public extensions::ExtensionInstallChecker {
55 public:
56 ExtensionInstallCheckerMock(Profile* profile,
57 const std::string& requirements_error)
58 : extensions::ExtensionInstallChecker(profile),
59 requirements_error_(requirements_error) {}
61 ~ExtensionInstallCheckerMock() override {}
63 private:
64 void CheckRequirements() override {
65 // Simulate an asynchronous operation.
66 base::MessageLoopProxy::current()->PostTask(
67 FROM_HERE,
68 base::Bind(&ExtensionInstallCheckerMock::RequirementsErrorCheckDone,
69 base::Unretained(this),
70 current_sequence_number()));
73 void RequirementsErrorCheckDone(int sequence_number) {
74 std::vector<std::string> errors;
75 errors.push_back(requirements_error_);
76 OnRequirementsCheckDone(sequence_number, errors);
79 std::string requirements_error_;
82 class EphemeralAppLauncherForTest : public EphemeralAppLauncher {
83 public:
84 EphemeralAppLauncherForTest(const std::string& id,
85 Profile* profile,
86 const LaunchCallback& callback)
87 : EphemeralAppLauncher(id, profile, NULL, callback),
88 install_initiated_(false),
89 install_prompt_created_(false) {}
91 EphemeralAppLauncherForTest(const std::string& id, Profile* profile)
92 : EphemeralAppLauncher(id, profile, NULL, LaunchCallback()),
93 install_initiated_(false),
94 install_prompt_created_(false) {}
96 bool install_initiated() const { return install_initiated_; }
97 bool install_prompt_created() const { return install_prompt_created_; }
99 void set_requirements_error(const std::string& error) {
100 requirements_check_error_ = error;
103 private:
104 // Override necessary functions for testing.
106 scoped_ptr<extensions::ExtensionInstallChecker> CreateInstallChecker()
107 override {
108 if (requirements_check_error_.empty()) {
109 return EphemeralAppLauncher::CreateInstallChecker();
110 } else {
111 return scoped_ptr<extensions::ExtensionInstallChecker>(
112 new ExtensionInstallCheckerMock(profile(),
113 requirements_check_error_));
117 scoped_ptr<ExtensionInstallPrompt> CreateInstallUI() override {
118 install_prompt_created_ = true;
119 return EphemeralAppLauncher::CreateInstallUI();
122 scoped_ptr<extensions::WebstoreInstaller::Approval> CreateApproval()
123 const override {
124 install_initiated_ = true;
125 return EphemeralAppLauncher::CreateApproval();
128 private:
129 ~EphemeralAppLauncherForTest() override {}
130 friend class base::RefCountedThreadSafe<EphemeralAppLauncherForTest>;
132 mutable bool install_initiated_;
133 std::string requirements_check_error_;
134 bool install_prompt_created_;
137 class LaunchObserver {
138 public:
139 LaunchObserver()
140 : done_(false),
141 waiting_(false),
142 result_(webstore_install::OTHER_ERROR) {}
144 webstore_install::Result result() const { return result_; }
145 const std::string& error() const { return error_; }
147 void OnLaunchCallback(webstore_install::Result result,
148 const std::string& error) {
149 result_ = result;
150 error_ = error;
151 done_ = true;
152 if (waiting_) {
153 waiting_ = false;
154 base::MessageLoopForUI::current()->Quit();
158 void Wait() {
159 if (done_)
160 return;
162 waiting_ = true;
163 content::RunMessageLoop();
166 private:
167 bool done_;
168 bool waiting_;
169 webstore_install::Result result_;
170 std::string error_;
173 class ManagementPolicyMock : public extensions::ManagementPolicy::Provider {
174 public:
175 ManagementPolicyMock() {}
177 std::string GetDebugPolicyProviderName() const override {
178 return "ManagementPolicyMock";
181 bool UserMayLoad(const Extension* extension,
182 base::string16* error) const override {
183 return false;
187 } // namespace
189 class EphemeralAppLauncherTest : public WebstoreInstallerTest {
190 public:
191 EphemeralAppLauncherTest()
192 : WebstoreInstallerTest(kWebstoreDomain,
193 kTestDataPath,
194 kDefaultAppCrxFilename,
195 kAppDomain,
196 kNonAppDomain) {}
198 void SetUpCommandLine(base::CommandLine* command_line) override {
199 WebstoreInstallerTest::SetUpCommandLine(command_line);
201 // Make event pages get suspended immediately.
202 extensions::ProcessManager::SetEventPageIdleTimeForTesting(1);
203 extensions::ProcessManager::SetEventPageSuspendingTimeForTesting(1);
205 // Enable ephemeral apps flag.
206 command_line->AppendSwitch(switches::kEnableEphemeralApps);
209 void SetUpOnMainThread() override {
210 WebstoreInstallerTest::SetUpOnMainThread();
212 // Disable ephemeral apps immediately after they stop running in tests.
213 EphemeralAppService::Get(profile())->set_disable_delay_for_test(0);
216 base::FilePath GetTestPath(const char* test_name) {
217 return test_data_dir_.AppendASCII("platform_apps/ephemeral_launcher")
218 .AppendASCII(test_name);
221 const Extension* GetInstalledExtension(const std::string& id) {
222 return ExtensionRegistry::Get(profile())
223 ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
226 void SetCrxFilename(const std::string& filename) {
227 GURL crx_url = GenerateTestServerUrl(kWebstoreDomain, filename);
228 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
229 switches::kAppsGalleryUpdateURL, crx_url.spec());
232 void StartLauncherAndCheckResult(EphemeralAppLauncherForTest* launcher,
233 webstore_install::Result expected_result,
234 bool expect_install_initiated) {
235 ExtensionTestMessageListener launched_listener("launched", false);
236 LaunchObserver launch_observer;
238 launcher->launch_callback_ = base::Bind(&LaunchObserver::OnLaunchCallback,
239 base::Unretained(&launch_observer));
240 launcher->Start();
241 launch_observer.Wait();
243 // Verify the launch result.
244 EXPECT_EQ(expected_result, launch_observer.result());
245 EXPECT_EQ(expect_install_initiated, launcher->install_initiated());
247 // Verify that the app was actually launched if the launcher succeeded.
248 if (launch_observer.result() == webstore_install::SUCCESS)
249 EXPECT_TRUE(launched_listener.WaitUntilSatisfied());
250 else
251 EXPECT_FALSE(launched_listener.was_satisfied());
253 // Check the reference count to ensure the launcher instance will not be
254 // leaked.
255 EXPECT_TRUE(launcher->HasOneRef());
258 void RunLaunchTest(const std::string& id,
259 webstore_install::Result expected_result,
260 bool expect_install_initiated) {
261 InstallTracker* tracker = InstallTracker::Get(profile());
262 ASSERT_TRUE(tracker);
263 bool was_install_active = !!tracker->GetActiveInstall(id);
265 scoped_refptr<EphemeralAppLauncherForTest> launcher(
266 new EphemeralAppLauncherForTest(id, profile()));
267 StartLauncherAndCheckResult(
268 launcher.get(), expected_result, expect_install_initiated);
270 // Verify that the install was deregistered from the InstallTracker.
271 EXPECT_EQ(was_install_active, !!tracker->GetActiveInstall(id));
274 void ValidateAppInstalledEphemerally(const std::string& id) {
275 EXPECT_TRUE(GetInstalledExtension(id));
276 EXPECT_TRUE(extensions::util::IsEphemeralApp(id, profile()));
279 const Extension* InstallAndDisableApp(
280 const char* test_path,
281 Extension::DisableReason disable_reason) {
282 const Extension* app = InstallExtension(GetTestPath(test_path), 1);
283 EXPECT_TRUE(app);
284 if (!app)
285 return NULL;
287 ExtensionService* service =
288 ExtensionSystem::Get(profile())->extension_service();
289 service->DisableExtension(app->id(), disable_reason);
291 if (disable_reason == Extension::DISABLE_PERMISSIONS_INCREASE) {
292 // When an extension is disabled due to a permissions increase, this
293 // flag needs to be set too, for some reason.
294 ExtensionPrefs::Get(profile())
295 ->SetDidExtensionEscalatePermissions(app, true);
298 EXPECT_TRUE(
299 ExtensionRegistry::Get(profile())->disabled_extensions().Contains(
300 app->id()));
301 return app;
305 class EphemeralAppLauncherTestDisabled : public EphemeralAppLauncherTest {
306 public:
307 void SetUpCommandLine(base::CommandLine* command_line) override {
308 // Skip EphemeralAppLauncherTest as it enables the feature.
309 WebstoreInstallerTest::SetUpCommandLine(command_line);
313 // Verifies that an ephemeral app will not be installed and launched if the
314 // feature is disabled.
315 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTestDisabled, FeatureDisabled) {
316 RunLaunchTest(
317 kDefaultAppCrxFilename, webstore_install::LAUNCH_FEATURE_DISABLED, false);
318 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
321 // Verifies that an app with no permission warnings will be installed
322 // ephemerally and launched without prompting the user.
323 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
324 LaunchAppWithNoPermissionWarnings) {
325 content::WindowedNotificationObserver unloaded_signal(
326 extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
327 content::Source<Profile>(profile()));
329 scoped_refptr<EphemeralAppLauncherForTest> launcher(
330 new EphemeralAppLauncherForTest(kDefaultAppId, profile()));
331 StartLauncherAndCheckResult(launcher.get(), webstore_install::SUCCESS, true);
332 ValidateAppInstalledEphemerally(kDefaultAppId);
334 // Apps with no permission warnings should not result in a prompt.
335 EXPECT_FALSE(launcher->install_prompt_created());
337 // Ephemeral apps are unloaded after they stop running.
338 unloaded_signal.Wait();
340 // After an app has been installed ephemerally, it can be launched again
341 // without installing from the web store.
342 RunLaunchTest(kDefaultAppId, webstore_install::SUCCESS, false);
345 // Verifies that an app with permission warnings will be installed
346 // ephemerally and launched if accepted by the user.
347 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
348 LaunchAppWithPermissionsWarnings) {
349 SetCrxFilename(kAppWithPermissionsFilename);
350 AutoAcceptInstall();
352 scoped_refptr<EphemeralAppLauncherForTest> launcher(
353 new EphemeralAppLauncherForTest(kAppWithPermissionsId, profile()));
354 StartLauncherAndCheckResult(launcher.get(), webstore_install::SUCCESS, true);
355 ValidateAppInstalledEphemerally(kAppWithPermissionsId);
356 EXPECT_TRUE(launcher->install_prompt_created());
359 // Verifies that an app with permission warnings will not be installed
360 // ephemerally if cancelled by the user.
361 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
362 CancelInstallAppWithPermissionWarnings) {
363 SetCrxFilename(kAppWithPermissionsFilename);
364 AutoCancelInstall();
366 scoped_refptr<EphemeralAppLauncherForTest> launcher(
367 new EphemeralAppLauncherForTest(kAppWithPermissionsId, profile()));
368 StartLauncherAndCheckResult(
369 launcher.get(), webstore_install::USER_CANCELLED, false);
370 EXPECT_FALSE(GetInstalledExtension(kAppWithPermissionsId));
371 EXPECT_TRUE(launcher->install_prompt_created());
374 // Verifies that an extension will not be installed ephemerally.
375 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallExtension) {
376 RunLaunchTest(
377 kExtensionId, webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE, false);
378 EXPECT_FALSE(GetInstalledExtension(kExtensionId));
381 // Verifies that an already installed extension will not be launched.
382 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchExtension) {
383 const Extension* extension =
384 InstallExtension(GetTestPath(kExtensionTestPath), 1);
385 ASSERT_TRUE(extension);
386 RunLaunchTest(extension->id(),
387 webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE,
388 false);
391 // Verifies that a legacy packaged app will not be installed ephemerally.
392 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallLegacyApp) {
393 RunLaunchTest(
394 kLegacyAppId, webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE, false);
395 EXPECT_FALSE(GetInstalledExtension(kLegacyAppId));
398 // Verifies that a legacy packaged app that is already installed can be
399 // launched.
400 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchLegacyApp) {
401 const Extension* extension =
402 InstallExtension(GetTestPath(kLegacyAppTestPath), 1);
403 ASSERT_TRUE(extension);
404 RunLaunchTest(extension->id(), webstore_install::SUCCESS, false);
407 // Verifies that a hosted app is not installed. Launch succeeds because we
408 // navigate to its launch url.
409 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchHostedApp) {
410 LaunchObserver launch_observer;
412 scoped_refptr<EphemeralAppLauncherForTest> launcher(
413 new EphemeralAppLauncherForTest(
414 kHostedAppId,
415 profile(),
416 base::Bind(&LaunchObserver::OnLaunchCallback,
417 base::Unretained(&launch_observer))));
418 launcher->Start();
419 launch_observer.Wait();
421 EXPECT_EQ(webstore_install::SUCCESS, launch_observer.result());
422 EXPECT_FALSE(launcher->install_initiated());
423 EXPECT_FALSE(GetInstalledExtension(kHostedAppId));
425 // Verify that a navigation to the launch url was attempted.
426 Browser* browser =
427 FindBrowserWithProfile(profile(), chrome::GetActiveDesktop());
428 ASSERT_TRUE(browser);
429 content::WebContents* web_contents =
430 browser->tab_strip_model()->GetActiveWebContents();
431 ASSERT_TRUE(web_contents);
432 EXPECT_EQ(GURL(kHostedAppLaunchUrl), web_contents->GetVisibleURL());
435 // Verifies that the EphemeralAppLauncher handles non-existent extension ids.
436 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, NonExistentExtensionId) {
437 RunLaunchTest(
438 kNonExistentId, webstore_install::WEBSTORE_REQUEST_ERROR, false);
439 EXPECT_FALSE(GetInstalledExtension(kNonExistentId));
442 // Verifies that an app blocked by management policy is not installed
443 // ephemerally.
444 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlockedByPolicy) {
445 // Register a provider that blocks the installation of all apps.
446 ManagementPolicyMock policy;
447 ExtensionSystem::Get(profile())->management_policy()->RegisterProvider(
448 &policy);
450 RunLaunchTest(kDefaultAppId, webstore_install::BLOCKED_BY_POLICY, false);
451 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
454 // Verifies that an app blacklisted for malware is not installed ephemerally.
455 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlacklistedForMalware) {
456 // Mock a BLACKLISTED_MALWARE return status.
457 extensions::TestBlacklist blacklist_tester(
458 extensions::Blacklist::Get(profile()));
459 blacklist_tester.SetBlacklistState(
460 kDefaultAppId, extensions::BLACKLISTED_MALWARE, false);
462 RunLaunchTest(kDefaultAppId, webstore_install::BLACKLISTED, false);
463 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
466 // Verifies that an app with unknown blacklist status is installed ephemerally
467 // and launched.
468 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlacklistStateUnknown) {
469 // Mock a BLACKLISTED_MALWARE return status.
470 extensions::TestBlacklist blacklist_tester(
471 extensions::Blacklist::Get(profile()));
472 blacklist_tester.SetBlacklistState(
473 kDefaultAppId, extensions::BLACKLISTED_UNKNOWN, false);
475 RunLaunchTest(kDefaultAppId, webstore_install::SUCCESS, true);
476 ValidateAppInstalledEphemerally(kDefaultAppId);
479 // Verifies that an app with unsupported requirements is not installed
480 // ephemerally.
481 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, UnsupportedRequirements) {
482 scoped_refptr<EphemeralAppLauncherForTest> launcher(
483 new EphemeralAppLauncherForTest(kDefaultAppId, profile()));
484 launcher->set_requirements_error("App has unsupported requirements");
486 StartLauncherAndCheckResult(
487 launcher.get(), webstore_install::REQUIREMENT_VIOLATIONS, false);
488 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
491 // Verifies that an app disabled due to permissions increase can be enabled
492 // and launched.
493 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, EnableAndLaunchApp) {
494 const Extension* app = InstallAndDisableApp(
495 kDefaultAppTestPath, Extension::DISABLE_PERMISSIONS_INCREASE);
496 ASSERT_TRUE(app);
498 AutoAcceptInstall();
499 RunLaunchTest(app->id(), webstore_install::SUCCESS, false);
502 // Verifies that if the user cancels the enable flow, the app will not be
503 // enabled and launched.
504 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, EnableCancelled) {
505 const Extension* app = InstallAndDisableApp(
506 kDefaultAppTestPath, Extension::DISABLE_PERMISSIONS_INCREASE);
507 ASSERT_TRUE(app);
509 AutoCancelInstall();
510 RunLaunchTest(app->id(), webstore_install::USER_CANCELLED, false);
513 // Verifies that an installed app that had been blocked by policy cannot be
514 // launched.
515 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchAppBlockedByPolicy) {
516 const Extension* app = InstallExtension(GetTestPath(kDefaultAppTestPath), 1);
517 ASSERT_TRUE(app);
519 // Simulate blocking of the app after it has been installed.
520 ManagementPolicyMock policy;
521 ExtensionSystem::Get(profile())->management_policy()->RegisterProvider(
522 &policy);
523 ExtensionSystem::Get(profile())->extension_service()->CheckManagementPolicy();
525 RunLaunchTest(app->id(), webstore_install::BLOCKED_BY_POLICY, false);
528 // Verifies that an installed blacklisted app cannot be launched.
529 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchBlacklistedApp) {
530 const Extension* app = InstallExtension(GetTestPath(kDefaultAppTestPath), 1);
531 ASSERT_TRUE(app);
533 ExtensionService* service =
534 ExtensionSystem::Get(profile())->extension_service();
535 service->BlacklistExtensionForTest(app->id());
536 ASSERT_TRUE(
537 ExtensionRegistry::Get(profile())->blacklisted_extensions().Contains(
538 app->id()));
540 RunLaunchTest(app->id(), webstore_install::BLACKLISTED, false);
543 // Verifies that an installed app with unsupported requirements cannot be
544 // launched.
545 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
546 LaunchAppWithUnsupportedRequirements) {
547 const Extension* app = InstallAndDisableApp(
548 kDefaultAppTestPath, Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
549 ASSERT_TRUE(app);
551 RunLaunchTest(app->id(), webstore_install::REQUIREMENT_VIOLATIONS, false);
554 // Verifies that a launch will fail if the app is currently being installed.
555 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallInProgress) {
556 extensions::ActiveInstallData install_data(kDefaultAppId);
557 InstallTracker::Get(profile())->AddActiveInstall(install_data);
559 RunLaunchTest(kDefaultAppId, webstore_install::INSTALL_IN_PROGRESS, false);
562 // Verifies that a launch will fail if a duplicate launch is in progress.
563 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, DuplicateLaunchInProgress) {
564 extensions::ActiveInstallData install_data(kDefaultAppId);
565 install_data.is_ephemeral = true;
566 InstallTracker::Get(profile())->AddActiveInstall(install_data);
568 RunLaunchTest(kDefaultAppId, webstore_install::LAUNCH_IN_PROGRESS, false);