Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / chrome / browser / apps / ephemeral_app_launcher_browsertest.cc
blob818f764beeafa537cec9a99d025067ce61683dc7
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/extension_test_message_listener.h"
11 #include "chrome/browser/extensions/install_tracker.h"
12 #include "chrome/browser/extensions/test_blacklist.h"
13 #include "chrome/browser/extensions/webstore_installer_test.h"
14 #include "chrome/browser/ui/browser_finder.h"
15 #include "chrome/browser/ui/tabs/tab_strip_model.h"
16 #include "chrome/common/chrome_switches.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/test/test_utils.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/browser/extension_registry.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/browser/extension_util.h"
23 #include "extensions/browser/management_policy.h"
24 #include "extensions/common/switches.h"
26 using extensions::Extension;
27 using extensions::ExtensionPrefs;
28 using extensions::ExtensionRegistry;
29 using extensions::ExtensionSystem;
30 using extensions::InstallTracker;
31 namespace webstore_install = extensions::webstore_install;
33 namespace {
35 const char kWebstoreDomain[] = "cws.com";
36 const char kAppDomain[] = "app.com";
37 const char kNonAppDomain[] = "nonapp.com";
38 const char kTestDataPath[] = "extensions/platform_apps/ephemeral_launcher";
40 const char kExtensionId[] = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeid";
41 const char kExtensionTestPath[] = "extension";
42 const char kLegacyAppId[] = "lnbochkobjfnhbnbljgfgokadhmbahcn";
43 const char kLegacyAppTestPath[] = "legacy_app";
44 const char kNonExistentId[] = "baaaaaaaaaaaaaaaaaaaaaaaaaaaadid";
45 const char kDefaultAppId[] = "kbiancnbopdghkfedjhfdoegjadfjeal";
46 const char kDefaultAppCrxFilename[] = "app.crx";
47 const char kDefaultAppTestPath[] = "app";
48 const char kAppWithPermissionsId[] = "mbfcnecjknjpipkfkoangpfnhhlpamki";
49 const char kAppWithPermissionsFilename[] = "app_with_permissions.crx";
50 const char kHostedAppId[] = "haaaaaaaaaaaaaaaaaaaaaaaaaaappid";
51 const char kHostedAppLaunchUrl[] = "http://foo.bar.com";
53 class ExtensionInstallCheckerMock : public extensions::ExtensionInstallChecker {
54 public:
55 ExtensionInstallCheckerMock(Profile* profile,
56 const std::string& requirements_error)
57 : extensions::ExtensionInstallChecker(profile),
58 requirements_error_(requirements_error) {}
60 virtual ~ExtensionInstallCheckerMock() {}
62 private:
63 virtual void CheckRequirements() OVERRIDE {
64 // Simulate an asynchronous operation.
65 base::MessageLoopProxy::current()->PostTask(
66 FROM_HERE,
67 base::Bind(&ExtensionInstallCheckerMock::RequirementsErrorCheckDone,
68 base::Unretained(this),
69 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 virtual 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 virtual scoped_ptr<ExtensionInstallPrompt> CreateInstallUI() OVERRIDE {
117 install_prompt_created_ = true;
118 return EphemeralAppLauncher::CreateInstallUI();
121 virtual scoped_ptr<extensions::WebstoreInstaller::Approval> CreateApproval()
122 const OVERRIDE {
123 install_initiated_ = true;
124 return EphemeralAppLauncher::CreateApproval();
127 private:
128 virtual ~EphemeralAppLauncherForTest() {}
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 virtual std::string GetDebugPolicyProviderName() const OVERRIDE {
177 return "ManagementPolicyMock";
180 virtual 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 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
198 WebstoreInstallerTest::SetUpCommandLine(command_line);
200 // Make event pages get suspended immediately.
201 command_line->AppendSwitchASCII(extensions::switches::kEventPageIdleTime,
202 "10");
203 command_line->AppendSwitchASCII(
204 extensions::switches::kEventPageSuspendingTime, "10");
206 // Enable ephemeral apps flag.
207 command_line->AppendSwitch(switches::kEnableEphemeralApps);
210 virtual void SetUpOnMainThread() OVERRIDE {
211 WebstoreInstallerTest::SetUpOnMainThread();
213 // Disable ephemeral apps immediately after they stop running in tests.
214 EphemeralAppService::Get(profile())->set_disable_delay_for_test(0);
217 base::FilePath GetTestPath(const char* test_name) {
218 return test_data_dir_.AppendASCII("platform_apps/ephemeral_launcher")
219 .AppendASCII(test_name);
222 const Extension* GetInstalledExtension(const std::string& id) {
223 return ExtensionRegistry::Get(profile())
224 ->GetExtensionById(id, ExtensionRegistry::EVERYTHING);
227 void SetCrxFilename(const std::string& filename) {
228 GURL crx_url = GenerateTestServerUrl(kWebstoreDomain, filename);
229 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
230 switches::kAppsGalleryUpdateURL, crx_url.spec());
233 void StartLauncherAndCheckResult(EphemeralAppLauncherForTest* launcher,
234 webstore_install::Result expected_result,
235 bool expect_install_initiated) {
236 ExtensionTestMessageListener launched_listener("launched", false);
237 LaunchObserver launch_observer;
239 launcher->launch_callback_ = base::Bind(&LaunchObserver::OnLaunchCallback,
240 base::Unretained(&launch_observer));
241 launcher->Start();
242 launch_observer.Wait();
244 // Verify the launch result.
245 EXPECT_EQ(expected_result, launch_observer.result());
246 EXPECT_EQ(expect_install_initiated, launcher->install_initiated());
248 // Verify that the app was actually launched if the launcher succeeded.
249 if (launch_observer.result() == webstore_install::SUCCESS)
250 EXPECT_TRUE(launched_listener.WaitUntilSatisfied());
251 else
252 EXPECT_FALSE(launched_listener.was_satisfied());
254 // Check the reference count to ensure the launcher instance will not be
255 // leaked.
256 EXPECT_TRUE(launcher->HasOneRef());
259 void RunLaunchTest(const std::string& id,
260 webstore_install::Result expected_result,
261 bool expect_install_initiated) {
262 InstallTracker* tracker = InstallTracker::Get(profile());
263 ASSERT_TRUE(tracker);
264 bool was_install_active = !!tracker->GetActiveInstall(id);
266 scoped_refptr<EphemeralAppLauncherForTest> launcher(
267 new EphemeralAppLauncherForTest(id, profile()));
268 StartLauncherAndCheckResult(
269 launcher.get(), expected_result, expect_install_initiated);
271 // Verify that the install was deregistered from the InstallTracker.
272 EXPECT_EQ(was_install_active, !!tracker->GetActiveInstall(id));
275 void ValidateAppInstalledEphemerally(const std::string& id) {
276 EXPECT_TRUE(GetInstalledExtension(id));
277 EXPECT_TRUE(extensions::util::IsEphemeralApp(id, profile()));
280 const Extension* InstallAndDisableApp(
281 const char* test_path,
282 Extension::DisableReason disable_reason) {
283 const Extension* app = InstallExtension(GetTestPath(test_path), 1);
284 EXPECT_TRUE(app);
285 if (!app)
286 return NULL;
288 ExtensionService* service =
289 ExtensionSystem::Get(profile())->extension_service();
290 service->DisableExtension(app->id(), disable_reason);
292 if (disable_reason == Extension::DISABLE_PERMISSIONS_INCREASE) {
293 // When an extension is disabled due to a permissions increase, this
294 // flag needs to be set too, for some reason.
295 ExtensionPrefs::Get(profile())
296 ->SetDidExtensionEscalatePermissions(app, true);
299 EXPECT_TRUE(
300 ExtensionRegistry::Get(profile())->disabled_extensions().Contains(
301 app->id()));
302 return app;
306 class EphemeralAppLauncherTestDisabled : public EphemeralAppLauncherTest {
307 public:
308 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
309 // Skip EphemeralAppLauncherTest as it enables the feature.
310 WebstoreInstallerTest::SetUpCommandLine(command_line);
314 // Verifies that an ephemeral app will not be installed and launched if the
315 // feature is disabled.
316 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTestDisabled, FeatureDisabled) {
317 RunLaunchTest(
318 kDefaultAppCrxFilename, webstore_install::LAUNCH_FEATURE_DISABLED, false);
319 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
322 // Verifies that an app with no permission warnings will be installed
323 // ephemerally and launched without prompting the user.
324 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
325 LaunchAppWithNoPermissionWarnings) {
326 content::WindowedNotificationObserver unloaded_signal(
327 extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
328 content::Source<Profile>(profile()));
330 scoped_refptr<EphemeralAppLauncherForTest> launcher(
331 new EphemeralAppLauncherForTest(kDefaultAppId, profile()));
332 StartLauncherAndCheckResult(launcher.get(), webstore_install::SUCCESS, true);
333 ValidateAppInstalledEphemerally(kDefaultAppId);
335 // Apps with no permission warnings should not result in a prompt.
336 EXPECT_FALSE(launcher->install_prompt_created());
338 // Ephemeral apps are unloaded after they stop running.
339 unloaded_signal.Wait();
341 // After an app has been installed ephemerally, it can be launched again
342 // without installing from the web store.
343 RunLaunchTest(kDefaultAppId, webstore_install::SUCCESS, false);
346 // Verifies that an app with permission warnings will be installed
347 // ephemerally and launched if accepted by the user.
348 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
349 LaunchAppWithPermissionsWarnings) {
350 SetCrxFilename(kAppWithPermissionsFilename);
351 AutoAcceptInstall();
353 scoped_refptr<EphemeralAppLauncherForTest> launcher(
354 new EphemeralAppLauncherForTest(kAppWithPermissionsId, profile()));
355 StartLauncherAndCheckResult(launcher.get(), webstore_install::SUCCESS, true);
356 ValidateAppInstalledEphemerally(kAppWithPermissionsId);
357 EXPECT_TRUE(launcher->install_prompt_created());
360 // Verifies that an app with permission warnings will not be installed
361 // ephemerally if cancelled by the user.
362 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
363 CancelInstallAppWithPermissionWarnings) {
364 SetCrxFilename(kAppWithPermissionsFilename);
365 AutoCancelInstall();
367 scoped_refptr<EphemeralAppLauncherForTest> launcher(
368 new EphemeralAppLauncherForTest(kAppWithPermissionsId, profile()));
369 StartLauncherAndCheckResult(
370 launcher.get(), webstore_install::USER_CANCELLED, false);
371 EXPECT_FALSE(GetInstalledExtension(kAppWithPermissionsId));
372 EXPECT_TRUE(launcher->install_prompt_created());
375 // Verifies that an extension will not be installed ephemerally.
376 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallExtension) {
377 RunLaunchTest(
378 kExtensionId, webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE, false);
379 EXPECT_FALSE(GetInstalledExtension(kExtensionId));
382 // Verifies that an already installed extension will not be launched.
383 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchExtension) {
384 const Extension* extension =
385 InstallExtension(GetTestPath(kExtensionTestPath), 1);
386 ASSERT_TRUE(extension);
387 RunLaunchTest(extension->id(),
388 webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE,
389 false);
392 // Verifies that a legacy packaged app will not be installed ephemerally.
393 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallLegacyApp) {
394 RunLaunchTest(
395 kLegacyAppId, webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE, false);
396 EXPECT_FALSE(GetInstalledExtension(kLegacyAppId));
399 // Verifies that a legacy packaged app that is already installed can be
400 // launched.
401 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchLegacyApp) {
402 const Extension* extension =
403 InstallExtension(GetTestPath(kLegacyAppTestPath), 1);
404 ASSERT_TRUE(extension);
405 RunLaunchTest(extension->id(), webstore_install::SUCCESS, false);
408 // Verifies that a hosted app is not installed. Launch succeeds because we
409 // navigate to its launch url.
410 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchHostedApp) {
411 LaunchObserver launch_observer;
413 scoped_refptr<EphemeralAppLauncherForTest> launcher(
414 new EphemeralAppLauncherForTest(
415 kHostedAppId,
416 profile(),
417 base::Bind(&LaunchObserver::OnLaunchCallback,
418 base::Unretained(&launch_observer))));
419 launcher->Start();
420 launch_observer.Wait();
422 EXPECT_EQ(webstore_install::SUCCESS, launch_observer.result());
423 EXPECT_FALSE(launcher->install_initiated());
424 EXPECT_FALSE(GetInstalledExtension(kHostedAppId));
426 // Verify that a navigation to the launch url was attempted.
427 Browser* browser =
428 FindBrowserWithProfile(profile(), chrome::GetActiveDesktop());
429 ASSERT_TRUE(browser);
430 content::WebContents* web_contents =
431 browser->tab_strip_model()->GetActiveWebContents();
432 ASSERT_TRUE(web_contents);
433 EXPECT_EQ(GURL(kHostedAppLaunchUrl), web_contents->GetVisibleURL());
436 // Verifies that the EphemeralAppLauncher handles non-existent extension ids.
437 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, NonExistentExtensionId) {
438 RunLaunchTest(
439 kNonExistentId, webstore_install::WEBSTORE_REQUEST_ERROR, false);
440 EXPECT_FALSE(GetInstalledExtension(kNonExistentId));
443 // Verifies that an app blocked by management policy is not installed
444 // ephemerally.
445 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlockedByPolicy) {
446 // Register a provider that blocks the installation of all apps.
447 ManagementPolicyMock policy;
448 ExtensionSystem::Get(profile())->management_policy()->RegisterProvider(
449 &policy);
451 RunLaunchTest(kDefaultAppId, webstore_install::BLOCKED_BY_POLICY, false);
452 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
455 // Verifies that an app blacklisted for malware is not installed ephemerally.
456 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlacklistedForMalware) {
457 // Mock a BLACKLISTED_MALWARE return status.
458 extensions::TestBlacklist blacklist_tester(
459 ExtensionSystem::Get(profile())->blacklist());
460 blacklist_tester.SetBlacklistState(
461 kDefaultAppId, extensions::BLACKLISTED_MALWARE, false);
463 RunLaunchTest(kDefaultAppId, webstore_install::BLACKLISTED, false);
464 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
467 // Verifies that an app with unknown blacklist status is installed ephemerally
468 // and launched.
469 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, BlacklistStateUnknown) {
470 // Mock a BLACKLISTED_MALWARE return status.
471 extensions::TestBlacklist blacklist_tester(
472 ExtensionSystem::Get(profile())->blacklist());
473 blacklist_tester.SetBlacklistState(
474 kDefaultAppId, extensions::BLACKLISTED_UNKNOWN, false);
476 RunLaunchTest(kDefaultAppId, webstore_install::SUCCESS, true);
477 ValidateAppInstalledEphemerally(kDefaultAppId);
480 // Verifies that an app with unsupported requirements is not installed
481 // ephemerally.
482 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, UnsupportedRequirements) {
483 scoped_refptr<EphemeralAppLauncherForTest> launcher(
484 new EphemeralAppLauncherForTest(kDefaultAppId, profile()));
485 launcher->set_requirements_error("App has unsupported requirements");
487 StartLauncherAndCheckResult(
488 launcher.get(), webstore_install::REQUIREMENT_VIOLATIONS, false);
489 EXPECT_FALSE(GetInstalledExtension(kDefaultAppId));
492 // Verifies that an app disabled due to permissions increase can be enabled
493 // and launched.
494 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, EnableAndLaunchApp) {
495 const Extension* app = InstallAndDisableApp(
496 kDefaultAppTestPath, Extension::DISABLE_PERMISSIONS_INCREASE);
497 ASSERT_TRUE(app);
499 AutoAcceptInstall();
500 RunLaunchTest(app->id(), webstore_install::SUCCESS, false);
503 // Verifies that if the user cancels the enable flow, the app will not be
504 // enabled and launched.
505 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, EnableCancelled) {
506 const Extension* app = InstallAndDisableApp(
507 kDefaultAppTestPath, Extension::DISABLE_PERMISSIONS_INCREASE);
508 ASSERT_TRUE(app);
510 AutoCancelInstall();
511 RunLaunchTest(app->id(), webstore_install::USER_CANCELLED, false);
514 // Verifies that an installed app that had been blocked by policy cannot be
515 // launched.
516 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchAppBlockedByPolicy) {
517 const Extension* app = InstallExtension(GetTestPath(kDefaultAppTestPath), 1);
518 ASSERT_TRUE(app);
520 // Simulate blocking of the app after it has been installed.
521 ManagementPolicyMock policy;
522 ExtensionSystem::Get(profile())->management_policy()->RegisterProvider(
523 &policy);
524 ExtensionSystem::Get(profile())->extension_service()->CheckManagementPolicy();
526 RunLaunchTest(app->id(), webstore_install::BLOCKED_BY_POLICY, false);
529 // Verifies that an installed blacklisted app cannot be launched.
530 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, LaunchBlacklistedApp) {
531 const Extension* app = InstallExtension(GetTestPath(kDefaultAppTestPath), 1);
532 ASSERT_TRUE(app);
534 ExtensionService* service =
535 ExtensionSystem::Get(profile())->extension_service();
536 service->BlacklistExtensionForTest(app->id());
537 ASSERT_TRUE(
538 ExtensionRegistry::Get(profile())->blacklisted_extensions().Contains(
539 app->id()));
541 RunLaunchTest(app->id(), webstore_install::BLACKLISTED, false);
544 // Verifies that an installed app with unsupported requirements cannot be
545 // launched.
546 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest,
547 LaunchAppWithUnsupportedRequirements) {
548 const Extension* app = InstallAndDisableApp(
549 kDefaultAppTestPath, Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
550 ASSERT_TRUE(app);
552 RunLaunchTest(app->id(), webstore_install::REQUIREMENT_VIOLATIONS, false);
555 // Verifies that a launch will fail if the app is currently being installed.
556 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, InstallInProgress) {
557 extensions::ActiveInstallData install_data(kDefaultAppId);
558 InstallTracker::Get(profile())->AddActiveInstall(install_data);
560 RunLaunchTest(kDefaultAppId, webstore_install::INSTALL_IN_PROGRESS, false);
563 // Verifies that a launch will fail if a duplicate launch is in progress.
564 IN_PROC_BROWSER_TEST_F(EphemeralAppLauncherTest, DuplicateLaunchInProgress) {
565 extensions::ActiveInstallData install_data(kDefaultAppId);
566 install_data.is_ephemeral = true;
567 InstallTracker::Get(profile())->AddActiveInstall(install_data);
569 RunLaunchTest(kDefaultAppId, webstore_install::LAUNCH_IN_PROGRESS, false);