Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / apps / ephemeral_app_launcher_browsertest.cc
blob63e6bc966862ab7fd025b71c5424d918c48ee44b
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/thread_task_runner_handle.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/browser/test_extension_registry_observer.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::ThreadTaskRunnerHandle::Get()->PostTask(
67 FROM_HERE,
68 base::Bind(&ExtensionInstallCheckerMock::RequirementsErrorCheckDone,
69 base::Unretained(this), current_sequence_number()));
72 void RequirementsErrorCheckDone(int sequence_number) {
73 std::vector<std::string> errors;
74 errors.push_back(requirements_error_);
75 OnRequirementsCheckDone(sequence_number, errors);
78 std::string requirements_error_;
81 class EphemeralAppLauncherForTest : public EphemeralAppLauncher {
82 public:
83 EphemeralAppLauncherForTest(const std::string& id,
84 Profile* profile,
85 const LaunchCallback& callback)
86 : EphemeralAppLauncher(id, profile, NULL, callback),
87 install_initiated_(false),
88 install_prompt_created_(false) {}
90 EphemeralAppLauncherForTest(const std::string& id, Profile* profile)
91 : EphemeralAppLauncher(id, profile, NULL, LaunchCallback()),
92 install_initiated_(false),
93 install_prompt_created_(false) {}
95 bool install_initiated() const { return install_initiated_; }
96 bool install_prompt_created() const { return install_prompt_created_; }
98 void set_requirements_error(const std::string& error) {
99 requirements_check_error_ = error;
102 private:
103 // Override necessary functions for testing.
105 scoped_ptr<extensions::ExtensionInstallChecker> CreateInstallChecker()
106 override {
107 if (requirements_check_error_.empty()) {
108 return EphemeralAppLauncher::CreateInstallChecker();
109 } else {
110 return scoped_ptr<extensions::ExtensionInstallChecker>(
111 new ExtensionInstallCheckerMock(profile(),
112 requirements_check_error_));
116 scoped_ptr<ExtensionInstallPrompt> CreateInstallUI() override {
117 install_prompt_created_ = true;
118 return EphemeralAppLauncher::CreateInstallUI();
121 scoped_ptr<extensions::WebstoreInstaller::Approval> CreateApproval()
122 const override {
123 install_initiated_ = true;
124 return EphemeralAppLauncher::CreateApproval();
127 private:
128 ~EphemeralAppLauncherForTest() override {}
129 friend class base::RefCountedThreadSafe<EphemeralAppLauncherForTest>;
131 mutable bool install_initiated_;
132 std::string requirements_check_error_;
133 bool install_prompt_created_;
136 class LaunchObserver {
137 public:
138 LaunchObserver()
139 : done_(false),
140 waiting_(false),
141 result_(webstore_install::OTHER_ERROR) {}
143 webstore_install::Result result() const { return result_; }
144 const std::string& error() const { return error_; }
146 void OnLaunchCallback(webstore_install::Result result,
147 const std::string& error) {
148 result_ = result;
149 error_ = error;
150 done_ = true;
151 if (waiting_) {
152 waiting_ = false;
153 base::MessageLoopForUI::current()->Quit();
157 void Wait() {
158 if (done_)
159 return;
161 waiting_ = true;
162 content::RunMessageLoop();
165 private:
166 bool done_;
167 bool waiting_;
168 webstore_install::Result result_;
169 std::string error_;
172 class ManagementPolicyMock : public extensions::ManagementPolicy::Provider {
173 public:
174 ManagementPolicyMock() {}
176 std::string GetDebugPolicyProviderName() const override {
177 return "ManagementPolicyMock";
180 bool UserMayLoad(const Extension* extension,
181 base::string16* error) const override {
182 return false;
186 } // namespace
188 class EphemeralAppLauncherTest : public WebstoreInstallerTest {
189 public:
190 EphemeralAppLauncherTest()
191 : WebstoreInstallerTest(kWebstoreDomain,
192 kTestDataPath,
193 kDefaultAppCrxFilename,
194 kAppDomain,
195 kNonAppDomain) {}
197 void SetUpCommandLine(base::CommandLine* command_line) override {
198 WebstoreInstallerTest::SetUpCommandLine(command_line);
200 // Make event pages get suspended immediately.
201 extensions::ProcessManager::SetEventPageIdleTimeForTesting(1);
202 extensions::ProcessManager::SetEventPageSuspendingTimeForTesting(1);
204 // Enable ephemeral apps flag.
205 command_line->AppendSwitch(switches::kEnableEphemeralAppsInWebstore);
208 void SetUpOnMainThread() override {
209 WebstoreInstallerTest::SetUpOnMainThread();
211 // Disable ephemeral apps immediately after they stop running in tests.
212 EphemeralAppService::Get(profile())->set_disable_delay_for_test(0);
215 base::FilePath GetTestPath(const char* test_name) {
216 return test_data_dir_.AppendASCII("platform_apps/ephemeral_launcher")
217 .AppendASCII(test_name);
220 const Extension* GetInstalledExtension(const std::string& id) {
221 return ExtensionRegistry::Get(profile())
222 ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
225 void SetCrxFilename(const std::string& filename) {
226 GURL crx_url = GenerateTestServerUrl(kWebstoreDomain, filename);
227 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
228 switches::kAppsGalleryUpdateURL, crx_url.spec());
231 void StartLauncherAndCheckResult(EphemeralAppLauncherForTest* launcher,
232 webstore_install::Result expected_result,
233 bool expect_install_initiated) {
234 ExtensionTestMessageListener launched_listener("launched", false);
235 LaunchObserver launch_observer;
237 launcher->launch_callback_ = base::Bind(&LaunchObserver::OnLaunchCallback,
238 base::Unretained(&launch_observer));
239 launcher->Start();
240 launch_observer.Wait();
242 // Verify the launch result.
243 EXPECT_EQ(expected_result, launch_observer.result());
244 EXPECT_EQ(expect_install_initiated, launcher->install_initiated());
246 // Verify that the app was actually launched if the launcher succeeded.
247 if (launch_observer.result() == webstore_install::SUCCESS)
248 EXPECT_TRUE(launched_listener.WaitUntilSatisfied());
249 else
250 EXPECT_FALSE(launched_listener.was_satisfied());
252 // Check the reference count to ensure the launcher instance will not be
253 // leaked.
254 EXPECT_TRUE(launcher->HasOneRef());
257 void RunLaunchTest(const std::string& id,
258 webstore_install::Result expected_result,
259 bool expect_install_initiated) {
260 InstallTracker* tracker = InstallTracker::Get(profile());
261 ASSERT_TRUE(tracker);
262 bool was_install_active = !!tracker->GetActiveInstall(id);
264 scoped_refptr<EphemeralAppLauncherForTest> launcher(
265 new EphemeralAppLauncherForTest(id, profile()));
266 StartLauncherAndCheckResult(
267 launcher.get(), expected_result, expect_install_initiated);
269 // Verify that the install was deregistered from the InstallTracker.
270 EXPECT_EQ(was_install_active, !!tracker->GetActiveInstall(id));
273 void ValidateAppInstalledEphemerally(const std::string& id) {
274 EXPECT_TRUE(GetInstalledExtension(id));
275 EXPECT_TRUE(extensions::util::IsEphemeralApp(id, profile()));
278 const Extension* InstallAndDisableApp(
279 const char* test_path,
280 Extension::DisableReason disable_reason) {
281 const Extension* app = InstallExtension(GetTestPath(test_path), 1);
282 EXPECT_TRUE(app);
283 if (!app)
284 return NULL;
286 ExtensionService* service =
287 ExtensionSystem::Get(profile())->extension_service();
288 service->DisableExtension(app->id(), disable_reason);
290 EXPECT_TRUE(
291 ExtensionRegistry::Get(profile())->disabled_extensions().Contains(
292 app->id()));
293 return app;
297 class EphemeralAppLauncherTestDisabled : public EphemeralAppLauncherTest {
298 public:
299 void SetUpCommandLine(base::CommandLine* command_line) override {
300 // Skip EphemeralAppLauncherTest as it enables the feature.
301 WebstoreInstallerTest::SetUpCommandLine(command_line);
305 // Verifies that an ephemeral app will not be installed and launched if the
306 // feature is disabled.
307 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTestDisabled, FeatureDisabled) {
308 RunLaunchTest(
309 kDefaultAppCrxFilename, webstore_install::LAUNCH_FEATURE_DISABLED, false);
310 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
313 // Verifies that an app with no permission warnings will be installed
314 // ephemerally and launched without prompting the user.
315 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
316 LaunchAppWithNoPermissionWarnings) {
317 extensions::TestExtensionRegistryObserver observer(
318 ExtensionRegistry::Get(profile()));
320 scoped_refptr<EphemeralAppLauncherForTest> launcher(
321 new EphemeralAppLauncherForTest(kDefaultAppId, profile()));
322 StartLauncherAndCheckResult(launcher.get(), webstore_install::SUCCESS, true);
323 ValidateAppInstalledEphemerally(kDefaultAppId);
325 // Apps with no permission warnings should not result in a prompt.
326 EXPECT_FALSE(launcher->install_prompt_created());
328 // Ephemeral apps are unloaded after they stop running.
329 observer.WaitForExtensionUnloaded();
331 // After an app has been installed ephemerally, it can be launched again
332 // without installing from the web store.
333 RunLaunchTest(kDefaultAppId, webstore_install::SUCCESS, false);
336 // Verifies that an app with permission warnings will be installed
337 // ephemerally and launched if accepted by the user.
338 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
339 LaunchAppWithPermissionsWarnings) {
340 SetCrxFilename(kAppWithPermissionsFilename);
341 AutoAcceptInstall();
343 scoped_refptr<EphemeralAppLauncherForTest> launcher(
344 new EphemeralAppLauncherForTest(kAppWithPermissionsId, profile()));
345 StartLauncherAndCheckResult(launcher.get(), webstore_install::SUCCESS, true);
346 ValidateAppInstalledEphemerally(kAppWithPermissionsId);
347 EXPECT_TRUE(launcher->install_prompt_created());
350 // Verifies that an app with permission warnings will not be installed
351 // ephemerally if cancelled by the user.
352 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
353 CancelInstallAppWithPermissionWarnings) {
354 SetCrxFilename(kAppWithPermissionsFilename);
355 AutoCancelInstall();
357 scoped_refptr<EphemeralAppLauncherForTest> launcher(
358 new EphemeralAppLauncherForTest(kAppWithPermissionsId, profile()));
359 StartLauncherAndCheckResult(
360 launcher.get(), webstore_install::USER_CANCELLED, false);
361 EXPECT_FALSE(GetInstalledExtension(kAppWithPermissionsId));
362 EXPECT_TRUE(launcher->install_prompt_created());
365 // Verifies that an extension will not be installed ephemerally.
366 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallExtension) {
367 RunLaunchTest(
368 kExtensionId, webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE, false);
369 EXPECT_FALSE(GetInstalledExtension(kExtensionId));
372 // Verifies that an already installed extension will not be launched.
373 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchExtension) {
374 const Extension* extension =
375 InstallExtension(GetTestPath(kExtensionTestPath), 1);
376 ASSERT_TRUE(extension);
377 RunLaunchTest(extension->id(),
378 webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE,
379 false);
382 // Verifies that a legacy packaged app will not be installed ephemerally.
383 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallLegacyApp) {
384 RunLaunchTest(
385 kLegacyAppId, webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE, false);
386 EXPECT_FALSE(GetInstalledExtension(kLegacyAppId));
389 // Verifies that a legacy packaged app that is already installed can be
390 // launched.
391 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchLegacyApp) {
392 const Extension* extension =
393 InstallExtension(GetTestPath(kLegacyAppTestPath), 1);
394 ASSERT_TRUE(extension);
395 RunLaunchTest(extension->id(), webstore_install::SUCCESS, false);
398 // Verifies that a hosted app is not installed. Launch succeeds because we
399 // navigate to its launch url.
400 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchHostedApp) {
401 LaunchObserver launch_observer;
403 scoped_refptr<EphemeralAppLauncherForTest> launcher(
404 new EphemeralAppLauncherForTest(
405 kHostedAppId,
406 profile(),
407 base::Bind(&LaunchObserver::OnLaunchCallback,
408 base::Unretained(&launch_observer))));
409 launcher->Start();
410 launch_observer.Wait();
412 EXPECT_EQ(webstore_install::SUCCESS, launch_observer.result());
413 EXPECT_FALSE(launcher->install_initiated());
414 EXPECT_FALSE(GetInstalledExtension(kHostedAppId));
416 // Verify that a navigation to the launch url was attempted.
417 Browser* browser =
418 FindBrowserWithProfile(profile(), chrome::GetActiveDesktop());
419 ASSERT_TRUE(browser);
420 content::WebContents* web_contents =
421 browser->tab_strip_model()->GetActiveWebContents();
422 ASSERT_TRUE(web_contents);
423 EXPECT_EQ(GURL(kHostedAppLaunchUrl), web_contents->GetVisibleURL());
426 // Verifies that the EphemeralAppLauncher handles non-existent extension ids.
427 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, NonExistentExtensionId) {
428 RunLaunchTest(
429 kNonExistentId, webstore_install::WEBSTORE_REQUEST_ERROR, false);
430 EXPECT_FALSE(GetInstalledExtension(kNonExistentId));
433 // Verifies that an app blocked by management policy is not installed
434 // ephemerally.
435 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlockedByPolicy) {
436 // Register a provider that blocks the installation of all apps.
437 ManagementPolicyMock policy;
438 ExtensionSystem::Get(profile())->management_policy()->RegisterProvider(
439 &policy);
441 RunLaunchTest(kDefaultAppId, webstore_install::BLOCKED_BY_POLICY, false);
442 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
445 // The blacklist relies on safe-browsing database infrastructure.
446 #if defined(SAFE_BROWSING_DB_LOCAL)
447 // Verifies that an app blacklisted for malware is not installed ephemerally.
448 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlacklistedForMalware) {
449 // Mock a BLACKLISTED_MALWARE return status.
450 extensions::TestBlacklist blacklist_tester(
451 extensions::Blacklist::Get(profile()));
452 blacklist_tester.SetBlacklistState(
453 kDefaultAppId, extensions::BLACKLISTED_MALWARE, false);
455 RunLaunchTest(kDefaultAppId, webstore_install::BLACKLISTED, false);
456 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
459 // Verifies that an app with unknown blacklist status is installed ephemerally
460 // and launched.
461 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlacklistStateUnknown) {
462 // Mock a BLACKLISTED_MALWARE return status.
463 extensions::TestBlacklist blacklist_tester(
464 extensions::Blacklist::Get(profile()));
465 blacklist_tester.SetBlacklistState(
466 kDefaultAppId, extensions::BLACKLISTED_UNKNOWN, false);
468 RunLaunchTest(kDefaultAppId, webstore_install::SUCCESS, true);
469 ValidateAppInstalledEphemerally(kDefaultAppId);
471 #endif
473 // Verifies that an app with unsupported requirements is not installed
474 // ephemerally.
475 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, UnsupportedRequirements) {
476 scoped_refptr<EphemeralAppLauncherForTest> launcher(
477 new EphemeralAppLauncherForTest(kDefaultAppId, profile()));
478 launcher->set_requirements_error("App has unsupported requirements");
480 StartLauncherAndCheckResult(
481 launcher.get(), webstore_install::REQUIREMENT_VIOLATIONS, false);
482 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
485 // Verifies that an app disabled due to permissions increase can be enabled
486 // and launched.
487 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, EnableAndLaunchApp) {
488 const Extension* app = InstallAndDisableApp(
489 kDefaultAppTestPath, Extension::DISABLE_PERMISSIONS_INCREASE);
490 ASSERT_TRUE(app);
492 AutoAcceptInstall();
493 RunLaunchTest(app->id(), webstore_install::SUCCESS, false);
496 // Verifies that if the user cancels the enable flow, the app will not be
497 // enabled and launched.
498 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, EnableCancelled) {
499 const Extension* app = InstallAndDisableApp(
500 kDefaultAppTestPath, Extension::DISABLE_PERMISSIONS_INCREASE);
501 ASSERT_TRUE(app);
503 AutoCancelInstall();
504 RunLaunchTest(app->id(), webstore_install::USER_CANCELLED, false);
507 // Verifies that an installed app that had been blocked by policy cannot be
508 // launched.
509 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchAppBlockedByPolicy) {
510 const Extension* app = InstallExtension(GetTestPath(kDefaultAppTestPath), 1);
511 ASSERT_TRUE(app);
513 // Simulate blocking of the app after it has been installed.
514 ManagementPolicyMock policy;
515 ExtensionSystem::Get(profile())->management_policy()->RegisterProvider(
516 &policy);
517 ExtensionSystem::Get(profile())->extension_service()->CheckManagementPolicy();
519 RunLaunchTest(app->id(), webstore_install::BLOCKED_BY_POLICY, false);
522 // Verifies that an installed blacklisted app cannot be launched.
523 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchBlacklistedApp) {
524 const Extension* app = InstallExtension(GetTestPath(kDefaultAppTestPath), 1);
525 ASSERT_TRUE(app);
527 ExtensionService* service =
528 ExtensionSystem::Get(profile())->extension_service();
529 service->BlacklistExtensionForTest(app->id());
530 ASSERT_TRUE(
531 ExtensionRegistry::Get(profile())->blacklisted_extensions().Contains(
532 app->id()));
534 RunLaunchTest(app->id(), webstore_install::BLACKLISTED, false);
537 // Verifies that an installed app with unsupported requirements cannot be
538 // launched.
539 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
540 LaunchAppWithUnsupportedRequirements) {
541 const Extension* app = InstallAndDisableApp(
542 kDefaultAppTestPath, Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
543 ASSERT_TRUE(app);
545 RunLaunchTest(app->id(), webstore_install::REQUIREMENT_VIOLATIONS, false);
548 // Verifies that a launch will fail if the app is currently being installed.
549 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallInProgress) {
550 extensions::ActiveInstallData install_data(kDefaultAppId);
551 InstallTracker::Get(profile())->AddActiveInstall(install_data);
553 RunLaunchTest(kDefaultAppId, webstore_install::INSTALL_IN_PROGRESS, false);
556 // Verifies that a launch will fail if a duplicate launch is in progress.
557 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, DuplicateLaunchInProgress) {
558 extensions::ActiveInstallData install_data(kDefaultAppId);
559 install_data.is_ephemeral = true;
560 InstallTracker::Get(profile())->AddActiveInstall(install_data);
562 RunLaunchTest(kDefaultAppId, webstore_install::LAUNCH_IN_PROGRESS, false);