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. 4 5#include "chrome/browser/apps/ephemeral_app_browsertest.h" 6 7#include <vector> 8 9#include "apps/app_restore_service.h" 10#include "apps/saved_files_service.h" 11#include "base/files/scoped_temp_dir.h" 12#include "base/scoped_observer.h" 13#include "base/stl_util.h" 14#include "chrome/browser/apps/app_browsertest_util.h" 15#include "chrome/browser/apps/ephemeral_app_service.h" 16#include "chrome/browser/extensions/api/file_system/file_system_api.h" 17#include "chrome/browser/extensions/app_sync_data.h" 18#include "chrome/browser/extensions/extension_service.h" 19#include "chrome/browser/extensions/extension_sync_service.h" 20#include "chrome/browser/extensions/extension_util.h" 21#include "chrome/browser/notifications/desktop_notification_service.h" 22#include "chrome/browser/notifications/desktop_notification_service_factory.h" 23#include "chrome/common/chrome_switches.h" 24#include "chrome/common/extensions/api/alarms.h" 25#include "content/public/browser/power_save_blocker.h" 26#include "content/public/test/browser_test.h" 27#include "content/public/test/test_utils.h" 28#include "extensions/browser/api/power/power_api_manager.h" 29#include "extensions/browser/app_sorting.h" 30#include "extensions/browser/event_router.h" 31#include "extensions/browser/extension_prefs.h" 32#include "extensions/browser/extension_registry.h" 33#include "extensions/browser/extension_registry_observer.h" 34#include "extensions/browser/extension_system.h" 35#include "extensions/browser/extension_util.h" 36#include "extensions/browser/notification_types.h" 37#include "extensions/browser/process_manager.h" 38#include "extensions/browser/uninstall_reason.h" 39#include "extensions/common/extension.h" 40#include "extensions/common/switches.h" 41#include "extensions/test/extension_test_message_listener.h" 42#include "extensions/test/result_catcher.h" 43#include "sync/api/fake_sync_change_processor.h" 44#include "sync/api/sync_change_processor_wrapper_for_test.h" 45#include "sync/api/sync_error_factory_mock.h" 46#include "ui/message_center/message_center.h" 47#include "ui/message_center/notifier_settings.h" 48 49using extensions::AppSyncData; 50using extensions::Event; 51using extensions::EventRouter; 52using extensions::Extension; 53using extensions::ExtensionPrefs; 54using extensions::ExtensionRegistry; 55using extensions::ExtensionRegistryObserver; 56using extensions::ExtensionSystem; 57using extensions::Manifest; 58using extensions::ResultCatcher; 59 60namespace { 61 62namespace alarms = extensions::api::alarms; 63 64const char kPowerTestApp[] = "ephemeral_apps/power"; 65 66// Enabling sync causes these tests to be flaky on Windows. Disable sync so that 67// everything else can be tested. See crbug.com/401028 68#if defined(OS_WIN) 69const bool kEnableSync = false; 70#else 71const bool kEnableSync = true; 72#endif 73 74typedef std::vector<message_center::Notifier*> NotifierList; 75 76bool IsNotifierInList(const message_center::NotifierId& notifier_id, 77 const NotifierList& notifiers) { 78 for (NotifierList::const_iterator it = notifiers.begin(); 79 it != notifiers.end(); ++it) { 80 const message_center::Notifier* notifier = *it; 81 if (notifier->notifier_id == notifier_id) 82 return true; 83 } 84 85 return false; 86} 87 88// Saves some parameters from the extension installed notification in order 89// to verify them in tests. 90class InstallObserver : public ExtensionRegistryObserver { 91 public: 92 struct InstallParameters { 93 std::string id; 94 bool is_update; 95 bool from_ephemeral; 96 97 InstallParameters( 98 const std::string& id, 99 bool is_update, 100 bool from_ephemeral) 101 : id(id), is_update(is_update), from_ephemeral(from_ephemeral) {} 102 }; 103 104 explicit InstallObserver(Profile* profile) : registry_observer_(this) { 105 registry_observer_.Add(ExtensionRegistry::Get(profile)); 106 } 107 108 virtual ~InstallObserver() {} 109 110 const InstallParameters& Last() { 111 CHECK(!install_params_.empty()); 112 return install_params_.back(); 113 } 114 115 private: 116 virtual void OnExtensionWillBeInstalled( 117 content::BrowserContext* browser_context, 118 const Extension* extension, 119 bool is_update, 120 bool from_ephemeral, 121 const std::string& old_name) OVERRIDE { 122 install_params_.push_back( 123 InstallParameters(extension->id(), is_update, from_ephemeral)); 124 } 125 126 std::vector<InstallParameters> install_params_; 127 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> 128 registry_observer_; 129}; 130 131// Instead of actually changing the system power settings, tests will just 132// issue requests to this mock. 133class PowerSettingsMock { 134 public: 135 PowerSettingsMock() : keep_awake_count_(0) {} 136 137 void request_keep_awake() { ++keep_awake_count_; } 138 139 void release_keep_awake() { 140 --keep_awake_count_; 141 ASSERT_GE(keep_awake_count_, 0); 142 } 143 144 int keep_awake_count() const { return keep_awake_count_; } 145 146 private: 147 int keep_awake_count_; 148 149 DISALLOW_COPY_AND_ASSIGN(PowerSettingsMock); 150}; 151 152// Stub implementation of content::PowerSaveBlocker that updates the 153// PowerSettingsMock. 154class PowerSaveBlockerStub : public content::PowerSaveBlocker { 155 public: 156 explicit PowerSaveBlockerStub(PowerSettingsMock* power_settings) 157 : power_settings_(power_settings) { 158 power_settings_->request_keep_awake(); 159 } 160 161 virtual ~PowerSaveBlockerStub() { power_settings_->release_keep_awake(); } 162 163 static scoped_ptr<PowerSaveBlocker> Create(PowerSettingsMock* power_settings, 164 PowerSaveBlockerType type, 165 const std::string& reason) { 166 return scoped_ptr<PowerSaveBlocker>( 167 new PowerSaveBlockerStub(power_settings)); 168 } 169 170 private: 171 PowerSettingsMock* power_settings_; // Not owned. 172 173 DISALLOW_COPY_AND_ASSIGN(PowerSaveBlockerStub); 174}; 175 176} // namespace 177 178 179// EphemeralAppTestBase: 180 181const char EphemeralAppTestBase::kMessagingReceiverApp[] = 182 "ephemeral_apps/messaging_receiver"; 183const char EphemeralAppTestBase::kMessagingReceiverAppV2[] = 184 "ephemeral_apps/messaging_receiver2"; 185const char EphemeralAppTestBase::kDispatchEventTestApp[] = 186 "ephemeral_apps/dispatch_event"; 187const char EphemeralAppTestBase::kNotificationsTestApp[] = 188 "ephemeral_apps/notification_settings"; 189const char EphemeralAppTestBase::kFileSystemTestApp[] = 190 "ephemeral_apps/filesystem_retain_entries"; 191 192EphemeralAppTestBase::EphemeralAppTestBase() {} 193 194EphemeralAppTestBase::~EphemeralAppTestBase() {} 195 196void EphemeralAppTestBase::SetUpCommandLine(base::CommandLine* command_line) { 197 // Skip PlatformAppBrowserTest, which sets different values for the switches 198 // below. 199 ExtensionBrowserTest::SetUpCommandLine(command_line); 200 201 // Make event pages get suspended immediately. 202 extensions::ProcessManager::SetEventPageIdleTimeForTesting(1); 203 extensions::ProcessManager::SetEventPageSuspendingTimeForTesting(1); 204 205 // Enable ephemeral apps flag. 206 command_line->AppendSwitch(switches::kEnableEphemeralApps); 207} 208 209void EphemeralAppTestBase::SetUpOnMainThread() { 210 PlatformAppBrowserTest::SetUpOnMainThread(); 211 212 // Disable ephemeral apps immediately after they stop running in tests. 213 EphemeralAppService::Get(profile())->set_disable_delay_for_test(0); 214} 215 216base::FilePath EphemeralAppTestBase::GetTestPath(const char* test_path) { 217 return test_data_dir_.AppendASCII("platform_apps").AppendASCII(test_path); 218} 219 220const Extension* EphemeralAppTestBase::InstallEphemeralApp( 221 const char* test_path, Manifest::Location manifest_location) { 222 const Extension* extension = InstallEphemeralAppWithSourceAndFlags( 223 GetTestPath(test_path), 1, manifest_location, Extension::NO_FLAGS); 224 EXPECT_TRUE(extension); 225 if (extension) 226 EXPECT_TRUE(extensions::util::IsEphemeralApp(extension->id(), profile())); 227 return extension; 228} 229 230const Extension* EphemeralAppTestBase::InstallEphemeralApp( 231 const char* test_path) { 232 return InstallEphemeralApp(test_path, Manifest::INTERNAL); 233} 234 235const Extension* EphemeralAppTestBase::InstallAndLaunchEphemeralApp( 236 const char* test_path) { 237 ExtensionTestMessageListener launched_listener("launched", false); 238 const Extension* extension = InstallEphemeralApp(test_path); 239 EXPECT_TRUE(extension); 240 if (!extension) 241 return NULL; 242 243 LaunchPlatformApp(extension); 244 bool wait_result = launched_listener.WaitUntilSatisfied(); 245 EXPECT_TRUE(wait_result); 246 if (!wait_result) 247 return NULL; 248 249 return extension; 250} 251 252const Extension* EphemeralAppTestBase::UpdateEphemeralApp( 253 const std::string& app_id, 254 const base::FilePath& test_dir, 255 const base::FilePath& pem_path) { 256 // Pack a new version of the app. 257 base::ScopedTempDir temp_dir; 258 EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); 259 260 base::FilePath crx_path = temp_dir.path().AppendASCII("temp.crx"); 261 if (!base::DeleteFile(crx_path, false)) { 262 ADD_FAILURE() << "Failed to delete existing crx: " << crx_path.value(); 263 return NULL; 264 } 265 266 base::FilePath app_v2_path = PackExtensionWithOptions( 267 test_dir, crx_path, pem_path, base::FilePath()); 268 EXPECT_FALSE(app_v2_path.empty()); 269 270 // Update the ephemeral app and wait for the update to finish. 271 extensions::CrxInstaller* crx_installer = NULL; 272 content::WindowedNotificationObserver windowed_observer( 273 extensions::NOTIFICATION_CRX_INSTALLER_DONE, 274 content::Source<extensions::CrxInstaller>(crx_installer)); 275 ExtensionService* service = 276 ExtensionSystem::Get(profile())->extension_service(); 277 EXPECT_TRUE(service->UpdateExtension(app_id, app_v2_path, true, 278 &crx_installer)); 279 windowed_observer.Wait(); 280 281 return ExtensionRegistry::Get(profile()) 282 ->GetExtensionById(app_id, ExtensionRegistry::EVERYTHING); 283} 284 285void EphemeralAppTestBase::PromoteEphemeralApp( 286 const extensions::Extension* app) { 287 ExtensionService* extension_service = 288 ExtensionSystem::Get(profile())->extension_service(); 289 ASSERT_TRUE(extension_service); 290 extension_service->PromoteEphemeralApp(app, false); 291} 292 293void EphemeralAppTestBase::DisableEphemeralApp( 294 const Extension* app, 295 Extension::DisableReason disable_reason) { 296 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); 297 298 // Disabling due to a permissions increase also involves setting the 299 // DidExtensionEscalatePermissions flag. 300 if (disable_reason == Extension::DISABLE_PERMISSIONS_INCREASE) 301 prefs->SetDidExtensionEscalatePermissions(app, true); 302 303 ExtensionSystem::Get(profile())->extension_service()->DisableExtension( 304 app->id(), disable_reason); 305 306 ASSERT_TRUE(ExtensionRegistry::Get(profile())->disabled_extensions().Contains( 307 app->id())); 308} 309 310void EphemeralAppTestBase::CloseApp(const std::string& app_id) { 311 EXPECT_EQ(1U, GetAppWindowCountForApp(app_id)); 312 extensions::AppWindow* app_window = GetFirstAppWindowForApp(app_id); 313 ASSERT_TRUE(app_window); 314 CloseAppWindow(app_window); 315} 316 317void EphemeralAppTestBase::CloseAppWaitForUnload(const std::string& app_id) { 318 // Ephemeral apps are unloaded from extension system after they stop running. 319 content::WindowedNotificationObserver unloaded_signal( 320 extensions::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED, 321 content::Source<Profile>(profile())); 322 CloseApp(app_id); 323 unloaded_signal.Wait(); 324} 325 326void EphemeralAppTestBase::EvictApp(const std::string& app_id) { 327 // Uninstall the app, which is what happens when ephemeral apps get evicted 328 // from the cache. 329 content::WindowedNotificationObserver uninstalled_signal( 330 extensions::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED, 331 content::Source<Profile>(profile())); 332 333 ExtensionService* service = 334 ExtensionSystem::Get(profile())->extension_service(); 335 ASSERT_TRUE(service); 336 service->UninstallExtension( 337 app_id, 338 extensions::UNINSTALL_REASON_ORPHANED_EPHEMERAL_EXTENSION, 339 base::Bind(&base::DoNothing), 340 NULL); 341 342 uninstalled_signal.Wait(); 343} 344 345// EphemeralAppBrowserTest: 346 347class EphemeralAppBrowserTest : public EphemeralAppTestBase { 348 protected: 349 bool LaunchAppAndRunTest(const Extension* app, const char* test_name) { 350 // Ephemeral apps are unloaded after they are closed. Ensure they are 351 // enabled before launch. 352 ExtensionService* service = 353 ExtensionSystem::Get(profile())->extension_service(); 354 service->EnableExtension(app->id()); 355 356 ExtensionTestMessageListener launched_listener("launched", true); 357 LaunchPlatformApp(app); 358 if (!launched_listener.WaitUntilSatisfied()) { 359 message_ = "Failed to receive launched message from test"; 360 return false; 361 } 362 363 ResultCatcher catcher; 364 launched_listener.Reply(test_name); 365 366 bool result = catcher.GetNextResult(); 367 message_ = catcher.message(); 368 369 CloseAppWaitForUnload(app->id()); 370 return result; 371 } 372 373 // Verify that the event page of the app has not been loaded. 374 void VerifyAppNotLoaded(const std::string& app_id) { 375 EXPECT_FALSE(ExtensionSystem::Get(profile())-> 376 process_manager()->GetBackgroundHostForExtension(app_id)); 377 } 378 379 // Verify properties of ephemeral apps. 380 void VerifyEphemeralApp(const std::string& app_id) { 381 EXPECT_TRUE(extensions::util::IsEphemeralApp(app_id, profile())); 382 383 // Ephemeral apps should not be synced. 384 scoped_ptr<AppSyncData> sync_change = GetLastSyncChangeForApp(app_id); 385 EXPECT_FALSE(sync_change.get()); 386 387 // Ephemeral apps should not be assigned ordinals. 388 extensions::AppSorting* app_sorting = 389 ExtensionPrefs::Get(profile())->app_sorting(); 390 EXPECT_FALSE(app_sorting->GetAppLaunchOrdinal(app_id).IsValid()); 391 EXPECT_FALSE(app_sorting->GetPageOrdinal(app_id).IsValid()); 392 } 393 394 // Verify that after ephemeral apps stop running, they reside in extension 395 // system in a disabled and unloaded state. 396 void VerifyInactiveEphemeralApp(const std::string& app_id) { 397 EXPECT_TRUE( 398 ExtensionRegistry::Get(profile())->disabled_extensions().Contains( 399 app_id)); 400 401 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); 402 EXPECT_TRUE(prefs->IsExtensionDisabled(app_id)); 403 EXPECT_NE(0, 404 prefs->GetDisableReasons(app_id) & 405 Extension::DISABLE_INACTIVE_EPHEMERAL_APP); 406 } 407 408 // Verify the state of an app that has been promoted from an ephemeral to a 409 // fully installed app. 410 void VerifyPromotedApp(const std::string& app_id, 411 ExtensionRegistry::IncludeFlag expected_set) { 412 const Extension* app = ExtensionRegistry::Get(profile()) 413 ->GetExtensionById(app_id, expected_set); 414 ASSERT_TRUE(app) << "App not found in expected set: " << expected_set; 415 416 // The app should not be ephemeral. 417 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); 418 ASSERT_TRUE(prefs); 419 EXPECT_FALSE(prefs->IsEphemeralApp(app_id)); 420 EXPECT_EQ(0, 421 prefs->GetDisableReasons(app_id) & 422 Extension::DISABLE_INACTIVE_EPHEMERAL_APP); 423 424 // Check sort ordinals. 425 extensions::AppSorting* app_sorting = prefs->app_sorting(); 426 EXPECT_TRUE(app_sorting->GetAppLaunchOrdinal(app_id).IsValid()); 427 EXPECT_TRUE(app_sorting->GetPageOrdinal(app_id).IsValid()); 428 } 429 430 // Dispatch a fake alarm event to the app. 431 void DispatchAlarmEvent(EventRouter* event_router, 432 const std::string& app_id) { 433 alarms::Alarm dummy_alarm; 434 dummy_alarm.name = "test_alarm"; 435 436 scoped_ptr<base::ListValue> args(new base::ListValue()); 437 args->Append(dummy_alarm.ToValue().release()); 438 scoped_ptr<Event> event(new Event(alarms::OnAlarm::kEventName, 439 args.Pass())); 440 441 event_router->DispatchEventToExtension(app_id, event.Pass()); 442 } 443 444 // Simulates the scenario where an app is installed, via the normal 445 // installation route, on top of an ephemeral app. This can occur due to race 446 // conditions. 447 const Extension* ReplaceEphemeralApp(const std::string& app_id, 448 const char* test_path, 449 int expected_enabled_change) { 450 return UpdateExtensionWaitForIdle( 451 app_id, GetTestPath(test_path), expected_enabled_change); 452 } 453 454 void PromoteEphemeralAppAndVerify( 455 const Extension* app, 456 ExtensionRegistry::IncludeFlag expected_set) { 457 ASSERT_TRUE(app); 458 459 // Ephemeral apps should not be synced. 460 scoped_ptr<AppSyncData> sync_change = GetLastSyncChangeForApp(app->id()); 461 EXPECT_FALSE(sync_change.get()); 462 463 // Promote the app to a regular installed app. 464 InstallObserver installed_observer(profile()); 465 PromoteEphemeralApp(app); 466 VerifyPromotedApp(app->id(), expected_set); 467 468 // Check the notification parameters. 469 const InstallObserver::InstallParameters& params = 470 installed_observer.Last(); 471 EXPECT_EQ(app->id(), params.id); 472 EXPECT_TRUE(params.is_update); 473 EXPECT_TRUE(params.from_ephemeral); 474 475 // The installation should now be synced. 476 sync_change = GetLastSyncChangeForApp(app->id()); 477 VerifySyncChange(sync_change.get(), 478 expected_set == ExtensionRegistry::ENABLED); 479 } 480 481 void PromoteEphemeralAppFromSyncAndVerify( 482 const Extension* app, 483 bool enable_from_sync, 484 ExtensionRegistry::IncludeFlag expected_set) { 485 ASSERT_TRUE(app); 486 487 // Simulate an install from sync. 488 const syncer::StringOrdinal kAppLaunchOrdinal("x"); 489 const syncer::StringOrdinal kPageOrdinal("y"); 490 AppSyncData app_sync_data(*app, 491 enable_from_sync, 492 false /* incognito enabled */, 493 false /* remote install */, 494 kAppLaunchOrdinal, 495 kPageOrdinal, 496 extensions::LAUNCH_TYPE_REGULAR); 497 498 std::string app_id = app->id(); 499 app = NULL; 500 501 ExtensionSyncService* sync_service = ExtensionSyncService::Get(profile()); 502 sync_service->ProcessAppSyncData(app_sync_data); 503 504 // Verify the installation. 505 VerifyPromotedApp(app_id, expected_set); 506 507 // The sort ordinals from sync should not be overridden. 508 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); 509 extensions::AppSorting* app_sorting = prefs->app_sorting(); 510 EXPECT_TRUE( 511 app_sorting->GetAppLaunchOrdinal(app_id).Equals(kAppLaunchOrdinal)); 512 EXPECT_TRUE(app_sorting->GetPageOrdinal(app_id).Equals(kPageOrdinal)); 513 } 514 515 void InitSyncService() { 516 if (!kEnableSync) 517 return; 518 519 ExtensionSyncService* sync_service = ExtensionSyncService::Get(profile()); 520 sync_service->MergeDataAndStartSyncing( 521 syncer::APPS, 522 syncer::SyncDataList(), 523 scoped_ptr<syncer::SyncChangeProcessor>( 524 new syncer::SyncChangeProcessorWrapperForTest( 525 &mock_sync_processor_)), 526 scoped_ptr<syncer::SyncErrorFactory>( 527 new syncer::SyncErrorFactoryMock())); 528 } 529 530 scoped_ptr<AppSyncData> GetLastSyncChangeForApp(const std::string& id) { 531 scoped_ptr<AppSyncData> sync_data; 532 for (syncer::SyncChangeList::iterator it = 533 mock_sync_processor_.changes().begin(); 534 it != mock_sync_processor_.changes().end(); ++it) { 535 scoped_ptr<AppSyncData> data(new AppSyncData(*it)); 536 if (data->id() == id) 537 sync_data.reset(data.release()); 538 } 539 540 return sync_data.Pass(); 541 } 542 543 void VerifySyncChange(const AppSyncData* sync_change, bool expect_enabled) { 544 if (!kEnableSync) 545 return; 546 547 ASSERT_TRUE(sync_change); 548 EXPECT_TRUE(sync_change->page_ordinal().IsValid()); 549 EXPECT_TRUE(sync_change->app_launch_ordinal().IsValid()); 550 EXPECT_FALSE(sync_change->uninstalled()); 551 EXPECT_EQ(expect_enabled, sync_change->extension_sync_data().enabled()); 552 } 553 554 void TestInstallEvent(bool close_app) { 555 ExtensionTestMessageListener first_msg_listener(false); 556 const Extension* app = InstallAndLaunchEphemeralApp(kDispatchEventTestApp); 557 ASSERT_TRUE(app); 558 559 // When an ephemeral app is first added, it should not receive the 560 // onInstalled event, hence the first message received from the test should 561 // be "launched" and not "installed". 562 ASSERT_TRUE(first_msg_listener.WaitUntilSatisfied()); 563 EXPECT_EQ(std::string("launched"), first_msg_listener.message()); 564 565 if (close_app) 566 CloseAppWaitForUnload(app->id()); 567 568 // When installed permanently, the app should receive the onInstalled event. 569 ExtensionTestMessageListener install_listener("installed", false); 570 PromoteEphemeralApp(app); 571 ASSERT_TRUE(install_listener.WaitUntilSatisfied()); 572 } 573 574 private: 575 syncer::FakeSyncChangeProcessor mock_sync_processor_; 576}; 577 578// Verify that ephemeral apps can be launched and receive system events when 579// they are running. Once they are inactive they should not receive system 580// events. 581IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, EventDispatchWhenLaunched) { 582 const Extension* extension = 583 InstallAndLaunchEphemeralApp(kDispatchEventTestApp); 584 ASSERT_TRUE(extension); 585 586 // Send a fake alarm event to the app and verify that a response is 587 // received. 588 EventRouter* event_router = EventRouter::Get(profile()); 589 ASSERT_TRUE(event_router); 590 591 ExtensionTestMessageListener alarm_received_listener("alarm_received", false); 592 DispatchAlarmEvent(event_router, extension->id()); 593 ASSERT_TRUE(alarm_received_listener.WaitUntilSatisfied()); 594 595 CloseAppWaitForUnload(extension->id()); 596 597 // Dispatch the alarm event again and verify that the event page did not get 598 // loaded for the app. 599 DispatchAlarmEvent(event_router, extension->id()); 600 VerifyAppNotLoaded(extension->id()); 601} 602 603// Verify that ephemeral apps will receive messages while they are running. 604// Flaky test: crbug.com/394426 605IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 606 DISABLED_ReceiveMessagesWhenLaunched) { 607 const Extension* receiver = 608 InstallAndLaunchEphemeralApp(kMessagingReceiverApp); 609 ASSERT_TRUE(receiver); 610 611 // Verify that messages are received while the app is running. 612 ResultCatcher result_catcher; 613 LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_success", 614 "Launched"); 615 EXPECT_TRUE(result_catcher.GetNextResult()); 616 617 CloseAppWaitForUnload(receiver->id()); 618 619 // Verify that messages are not received while the app is inactive. 620 LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_fail", "Launched"); 621 EXPECT_TRUE(result_catcher.GetNextResult()); 622} 623 624// Verifies that the chrome.runtime.onInstalled() event is received by a running 625// ephemeral app only when it is promoted. 626IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 627 InstallEventReceivedWhileRunning) { 628 TestInstallEvent(false /* close app */); 629} 630 631// Verifies that when an idle ephemeral app is promoted, it will be loaded to 632// receive the chrome.runtime.onInstalled() event. 633IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, InstallEventReceivedWhileIdle) { 634 TestInstallEvent(true /* close app */); 635} 636 637// Verifies that the chrome.runtime.onRestarted() event is received by an 638// ephemeral app. 639IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, RestartEventReceived) { 640 const Extension* app = InstallAndLaunchEphemeralApp(kDispatchEventTestApp); 641 ASSERT_TRUE(app); 642 CloseAppWaitForUnload(app->id()); 643 644 // Fake ephemeral app running before restart. 645 ExtensionSystem::Get(profile())->extension_service()->EnableExtension( 646 app->id()); 647 ASSERT_TRUE(ExtensionRegistry::Get(profile())->enabled_extensions().Contains( 648 app->id())); 649 ExtensionPrefs::Get(profile())->SetExtensionRunning(app->id(), true); 650 651 ExtensionTestMessageListener restart_listener("restarted", false); 652 apps::AppRestoreService::Get(profile())->HandleStartup(true); 653 EXPECT_TRUE(restart_listener.WaitUntilSatisfied()); 654} 655 656// Verify that an updated ephemeral app will still have its ephemeral flag 657// enabled. 658IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, UpdateEphemeralApp) { 659 InitSyncService(); 660 661 const Extension* app_v1 = InstallAndLaunchEphemeralApp(kMessagingReceiverApp); 662 ASSERT_TRUE(app_v1); 663 VerifyEphemeralApp(app_v1->id()); 664 CloseAppWaitForUnload(app_v1->id()); 665 VerifyInactiveEphemeralApp(app_v1->id()); 666 667 std::string app_id = app_v1->id(); 668 base::Version app_original_version = *app_v1->version(); 669 670 // Update to version 2 of the app. 671 app_v1 = NULL; // The extension object will be destroyed during update. 672 InstallObserver installed_observer(profile()); 673 const Extension* app_v2 = 674 UpdateEphemeralApp(app_id, 675 GetTestPath(kMessagingReceiverAppV2), 676 GetTestPath(kMessagingReceiverApp) 677 .ReplaceExtension(FILE_PATH_LITERAL(".pem"))); 678 679 // Check the notification parameters. 680 const InstallObserver::InstallParameters& params = installed_observer.Last(); 681 EXPECT_EQ(app_id, params.id); 682 EXPECT_TRUE(params.is_update); 683 EXPECT_FALSE(params.from_ephemeral); 684 685 // The ephemeral flag should still be set. 686 ASSERT_TRUE(app_v2); 687 EXPECT_GT(app_v2->version()->CompareTo(app_original_version), 0); 688 VerifyEphemeralApp(app_id); 689 690 // The app should still be disabled in extension system. 691 VerifyInactiveEphemeralApp(app_id); 692} 693 694// Verify that if notifications have been disabled for an ephemeral app, it will 695// remain disabled even after being evicted from the cache. 696IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, StickyNotificationSettings) { 697 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 698 ASSERT_TRUE(app); 699 700 // Disable notifications for this app. 701 DesktopNotificationService* notification_service = 702 DesktopNotificationServiceFactory::GetForProfile(profile()); 703 ASSERT_TRUE(notification_service); 704 705 message_center::NotifierId notifier_id( 706 message_center::NotifierId::APPLICATION, app->id()); 707 EXPECT_TRUE(notification_service->IsNotifierEnabled(notifier_id)); 708 notification_service->SetNotifierEnabled(notifier_id, false); 709 EXPECT_FALSE(notification_service->IsNotifierEnabled(notifier_id)); 710 711 // Remove the app. 712 CloseAppWaitForUnload(app->id()); 713 EvictApp(app->id()); 714 715 // Reinstall the ephemeral app and verify that notifications remain disabled. 716 app = InstallEphemeralApp(kNotificationsTestApp); 717 ASSERT_TRUE(app); 718 message_center::NotifierId reinstalled_notifier_id( 719 message_center::NotifierId::APPLICATION, app->id()); 720 EXPECT_FALSE(notification_service->IsNotifierEnabled( 721 reinstalled_notifier_id)); 722} 723 724// Verify that only running ephemeral apps will appear in the Notification 725// Settings UI. Inactive, cached ephemeral apps should not appear. 726IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 727 IncludeRunningEphemeralAppsInNotifiers) { 728 message_center::NotifierSettingsProvider* settings_provider = 729 message_center::MessageCenter::Get()->GetNotifierSettingsProvider(); 730 DCHECK(settings_provider); 731 732 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 733 ASSERT_TRUE(app); 734 message_center::NotifierId notifier_id( 735 message_center::NotifierId::APPLICATION, app->id()); 736 737 // Since the ephemeral app is running, it should be included in the list 738 // of notifiers to show in the UI. 739 NotifierList notifiers; 740 STLElementDeleter<NotifierList> notifier_deleter(¬ifiers); 741 742 settings_provider->GetNotifierList(¬ifiers); 743 EXPECT_TRUE(IsNotifierInList(notifier_id, notifiers)); 744 STLDeleteElements(¬ifiers); 745 746 // Close the ephemeral app. 747 CloseAppWaitForUnload(app->id()); 748 749 // Inactive ephemeral apps should not be included in the list of notifiers to 750 // show in the UI. 751 settings_provider->GetNotifierList(¬ifiers); 752 EXPECT_FALSE(IsNotifierInList(notifier_id, notifiers)); 753} 754 755// Verify that ephemeral apps will have no ability to retain file entries after 756// close. Normal retainEntry behavior for installed apps is tested in 757// FileSystemApiTest. 758IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 759 DisableRetainFileSystemEntries) { 760 // Create a dummy file that we can just return to the test. 761 base::ScopedTempDir temp_dir; 762 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 763 base::FilePath temp_file; 764 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file)); 765 766 using extensions::FileSystemChooseEntryFunction; 767 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( 768 &temp_file); 769 // The temporary file needs to be registered for the tests to pass on 770 // ChromeOS. 771 FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( 772 "temp", temp_dir.path()); 773 774 // The first test opens the file and writes the file handle to local storage. 775 const Extension* app = InstallEphemeralApp(kFileSystemTestApp, 776 Manifest::UNPACKED); 777 ASSERT_TRUE(LaunchAppAndRunTest(app, "OpenAndRetainFile")) << message_; 778 779 // Verify that after the app has been closed, all retained entries are 780 // flushed. 781 std::vector<apps::SavedFileEntry> file_entries = 782 apps::SavedFilesService::Get(profile()) 783 ->GetAllFileEntries(app->id()); 784 EXPECT_TRUE(file_entries.empty()); 785 786 // The second test verifies that the file cannot be reopened. 787 ASSERT_TRUE(LaunchAppAndRunTest(app, "RestoreRetainedFile")) << message_; 788} 789 790// Checks the process of launching an ephemeral app and then promoting the app 791// while it is running. 792IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppWhileRunning) { 793 InitSyncService(); 794 795 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 796 ASSERT_TRUE(app); 797 798 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::ENABLED); 799 800 // Ensure that the app is not unloaded and disabled after it is closed. 801 CloseApp(app->id()); 802 VerifyPromotedApp(app->id(), ExtensionRegistry::ENABLED); 803} 804 805// Checks the process of launching an ephemeral app and then promoting the app 806// while it is idle. 807IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppWhileIdle) { 808 InitSyncService(); 809 810 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 811 ASSERT_TRUE(app); 812 CloseAppWaitForUnload(app->id()); 813 VerifyInactiveEphemeralApp(app->id()); 814 815 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::ENABLED); 816} 817 818// Verifies that promoting an ephemeral app that was disabled due to a 819// permissions increase will enable it. 820IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppAndGrantPermissions) { 821 InitSyncService(); 822 823 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 824 ASSERT_TRUE(app); 825 CloseAppWaitForUnload(app->id()); 826 DisableEphemeralApp(app, Extension::DISABLE_PERMISSIONS_INCREASE); 827 828 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::ENABLED); 829 EXPECT_FALSE(ExtensionPrefs::Get(profile()) 830 ->DidExtensionEscalatePermissions(app->id())); 831} 832 833// Verifies that promoting an ephemeral app that has unsupported requirements 834// will not enable it. 835IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 836 PromoteUnsupportedEphemeralApp) { 837 InitSyncService(); 838 839 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 840 ASSERT_TRUE(app); 841 CloseAppWaitForUnload(app->id()); 842 DisableEphemeralApp(app, Extension::DISABLE_UNSUPPORTED_REQUIREMENT); 843 844 // When promoted to a regular installed app, it should remain disabled. 845 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::DISABLED); 846} 847 848// Verifies that promoting an ephemeral app that is blacklisted will not enable 849// it. 850IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 851 PromoteBlacklistedEphemeralApp) { 852 InitSyncService(); 853 854 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 855 ASSERT_TRUE(app); 856 CloseAppWaitForUnload(app->id()); 857 858 ExtensionService* service = 859 ExtensionSystem::Get(profile())->extension_service(); 860 service->BlacklistExtensionForTest(app->id()); 861 ASSERT_TRUE( 862 ExtensionRegistry::Get(profile())->blacklisted_extensions().Contains( 863 app->id())); 864 865 // When promoted to a regular installed app, it should remain blacklisted. 866 PromoteEphemeralAppAndVerify(app, ExtensionRegistry::BLACKLISTED); 867 868 // The app should be synced, but disabled. 869 scoped_ptr<AppSyncData> sync_change = GetLastSyncChangeForApp(app->id()); 870 VerifySyncChange(sync_change.get(), false); 871} 872 873// Checks the process of promoting an ephemeral app from sync while the app is 874// running. 875IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 876 PromoteAppFromSyncWhileRunning) { 877 InitSyncService(); 878 879 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 880 ASSERT_TRUE(app); 881 882 PromoteEphemeralAppFromSyncAndVerify(app, true, ExtensionRegistry::ENABLED); 883 884 // Ensure that the app is not unloaded and disabled after it is closed. 885 CloseApp(app->id()); 886 VerifyPromotedApp(app->id(), ExtensionRegistry::ENABLED); 887} 888 889// Checks the process of promoting an ephemeral app from sync while the app is 890// idle. 891IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteAppFromSyncWhileIdle) { 892 InitSyncService(); 893 894 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 895 ASSERT_TRUE(app); 896 CloseAppWaitForUnload(app->id()); 897 VerifyInactiveEphemeralApp(app->id()); 898 899 PromoteEphemeralAppFromSyncAndVerify(app, true, ExtensionRegistry::ENABLED); 900} 901 902// Checks the process of promoting an ephemeral app from sync, where the app 903// from sync is disabled, and the ephemeral app is running. 904IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 905 PromoteDisabledAppFromSyncWhileRunning) { 906 InitSyncService(); 907 908 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 909 ASSERT_TRUE(app); 910 911 PromoteEphemeralAppFromSyncAndVerify(app, false, ExtensionRegistry::DISABLED); 912} 913 914// Checks the process of promoting an ephemeral app from sync, where the app 915// from sync is disabled, and the ephemeral app is idle. 916IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 917 PromoteDisabledAppFromSyncWhileIdle) { 918 InitSyncService(); 919 920 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 921 ASSERT_TRUE(app); 922 CloseAppWaitForUnload(app->id()); 923 VerifyInactiveEphemeralApp(app->id()); 924 925 PromoteEphemeralAppFromSyncAndVerify(app, false, ExtensionRegistry::DISABLED); 926} 927 928// In most cases, ExtensionService::PromoteEphemeralApp() will be called to 929// permanently install an ephemeral app. However, there may be cases where an 930// install occurs through the usual route of installing from the Web Store (due 931// to race conditions). Ensure that the app is still installed correctly. 932IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 933 ReplaceEphemeralAppWithInstalledApp) { 934 InitSyncService(); 935 936 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 937 ASSERT_TRUE(app); 938 CloseAppWaitForUnload(app->id()); 939 std::string app_id = app->id(); 940 app = NULL; 941 942 InstallObserver installed_observer(profile()); 943 ReplaceEphemeralApp(app_id, kNotificationsTestApp, 1); 944 VerifyPromotedApp(app_id, ExtensionRegistry::ENABLED); 945 946 // Check the notification parameters. 947 const InstallObserver::InstallParameters& params = installed_observer.Last(); 948 EXPECT_EQ(app_id, params.id); 949 EXPECT_TRUE(params.is_update); 950 EXPECT_TRUE(params.from_ephemeral); 951} 952 953// This is similar to ReplaceEphemeralAppWithInstalledApp, but installs will 954// be delayed until the app is idle. 955IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 956 ReplaceEphemeralAppWithDelayedInstalledApp) { 957 InitSyncService(); 958 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 959 ASSERT_TRUE(app); 960 std::string app_id = app->id(); 961 app = NULL; 962 963 // Initiate install. 964 ReplaceEphemeralApp(app_id, kNotificationsTestApp, 0); 965 966 // The delayed installation will occur when the ephemeral app is closed. 967 content::WindowedNotificationObserver installed_signal( 968 extensions::NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED, 969 content::Source<Profile>(profile())); 970 InstallObserver installed_observer(profile()); 971 CloseAppWaitForUnload(app_id); 972 installed_signal.Wait(); 973 VerifyPromotedApp(app_id, ExtensionRegistry::ENABLED); 974 975 // Check the notification parameters. 976 const InstallObserver::InstallParameters& params = installed_observer.Last(); 977 EXPECT_EQ(app_id, params.id); 978 EXPECT_TRUE(params.is_update); 979 EXPECT_TRUE(params.from_ephemeral); 980} 981 982// Verifies that an installed app cannot turn into an ephemeral app as result of 983// race conditions, i.e. an ephemeral app can be promoted to an installed app, 984// but not vice versa. 985IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 986 ReplaceInstalledAppWithEphemeralApp) { 987 const Extension* app = InstallPlatformApp(kNotificationsTestApp); 988 ASSERT_TRUE(app); 989 std::string app_id = app->id(); 990 app = NULL; 991 992 EXPECT_FALSE(extensions::util::IsEphemeralApp(app_id, profile())); 993 app = 994 InstallEphemeralAppWithSourceAndFlags(GetTestPath(kNotificationsTestApp), 995 0, 996 Manifest::INTERNAL, 997 Extension::NO_FLAGS); 998 EXPECT_FALSE(extensions::util::IsEphemeralApp(app_id, profile())); 999} 1000 1001// Ephemerality was previously encoded by the Extension::IS_EPHEMERAL creation 1002// flag. This was changed to an "ephemeral_app" property. Check that the prefs 1003// are handled correctly. 1004IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 1005 ExtensionPrefBackcompatibility) { 1006 // Ensure that apps with the old prefs are recognized as ephemeral. 1007 const Extension* app = 1008 InstallExtensionWithSourceAndFlags(GetTestPath(kNotificationsTestApp), 1009 1, 1010 Manifest::INTERNAL, 1011 Extension::IS_EPHEMERAL); 1012 ASSERT_TRUE(app); 1013 EXPECT_TRUE(extensions::util::IsEphemeralApp(app->id(), profile())); 1014 1015 // Ensure that when the app is promoted to an installed app, the bit in the 1016 // creation flags is cleared. 1017 PromoteEphemeralApp(app); 1018 EXPECT_FALSE(extensions::util::IsEphemeralApp(app->id(), profile())); 1019 1020 int creation_flags = 1021 ExtensionPrefs::Get(profile())->GetCreationFlags(app->id()); 1022 EXPECT_EQ(0, creation_flags & Extension::IS_EPHEMERAL); 1023} 1024 1025// Verifies that the power keep awake will be automatically released for 1026// ephemeral apps that stop running. Well behaved apps should actually call 1027// chrome.power.releaseKeepAwake() themselves. 1028IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, ReleasePowerKeepAwake) { 1029 PowerSettingsMock power_settings; 1030 extensions::PowerApiManager* power_manager = 1031 extensions::PowerApiManager::Get(profile()); 1032 power_manager->SetCreateBlockerFunctionForTesting( 1033 base::Bind(&PowerSaveBlockerStub::Create, &power_settings)); 1034 1035 const Extension* app = InstallAndLaunchEphemeralApp(kPowerTestApp); 1036 ASSERT_TRUE(app); 1037 EXPECT_EQ(1, power_settings.keep_awake_count()); 1038 1039 CloseAppWaitForUnload(app->id()); 1040 1041 EXPECT_EQ(0, power_settings.keep_awake_count()); 1042} 1043