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/saved_files_service.h" 10 #include "base/files/scoped_temp_dir.h" 11 #include "base/scoped_observer.h" 12 #include "base/stl_util.h" 13 #include "chrome/browser/apps/app_browsertest_util.h" 14 #include "chrome/browser/extensions/api/file_system/file_system_api.h" 15 #include "chrome/browser/extensions/app_sync_data.h" 16 #include "chrome/browser/extensions/extension_service.h" 17 #include "chrome/browser/extensions/extension_sync_service.h" 18 #include "chrome/browser/extensions/extension_test_message_listener.h" 19 #include "chrome/browser/extensions/extension_util.h" 20 #include "chrome/browser/notifications/desktop_notification_service.h" 21 #include "chrome/browser/notifications/desktop_notification_service_factory.h" 22 #include "chrome/common/chrome_switches.h" 23 #include "chrome/common/extensions/api/alarms.h" 24 #include "content/public/test/browser_test.h" 25 #include "content/public/test/test_utils.h" 26 #include "extensions/browser/app_sorting.h" 27 #include "extensions/browser/event_router.h" 28 #include "extensions/browser/extension_prefs.h" 29 #include "extensions/browser/extension_registry.h" 30 #include "extensions/browser/extension_registry_observer.h" 31 #include "extensions/browser/extension_system.h" 32 #include "extensions/browser/extension_util.h" 33 #include "extensions/browser/process_manager.h" 34 #include "extensions/common/extension.h" 35 #include "extensions/common/switches.h" 36 #include "sync/api/fake_sync_change_processor.h" 37 #include "sync/api/sync_change_processor_wrapper_for_test.h" 38 #include "sync/api/sync_error_factory_mock.h" 39 #include "ui/message_center/message_center.h" 40 #include "ui/message_center/notifier_settings.h" 41 42 using extensions::AppSyncData; 43 using extensions::Event; 44 using extensions::EventRouter; 45 using extensions::Extension; 46 using extensions::ExtensionPrefs; 47 using extensions::ExtensionRegistry; 48 using extensions::ExtensionRegistryObserver; 49 using extensions::ExtensionSystem; 50 using extensions::Manifest; 51 52 namespace { 53 54 namespace alarms = extensions::api::alarms; 55 56 const char kDispatchEventTestApp[] = "ephemeral_apps/dispatch_event"; 57 const char kNotificationsTestApp[] = "ephemeral_apps/notification_settings"; 58 const char kFileSystemTestApp[] = "ephemeral_apps/filesystem_retain_entries"; 59 60 typedef std::vector<message_center::Notifier*> NotifierList; 61 62 bool IsNotifierInList(const message_center::NotifierId& notifier_id, 63 const NotifierList& notifiers) { 64 for (NotifierList::const_iterator it = notifiers.begin(); 65 it != notifiers.end(); ++it) { 66 const message_center::Notifier* notifier = *it; 67 if (notifier->notifier_id == notifier_id) 68 return true; 69 } 70 71 return false; 72 } 73 74 // Saves some parameters from the extension installed notification in order 75 // to verify them in tests. 76 class InstallObserver : public ExtensionRegistryObserver { 77 public: 78 struct InstallParameters { 79 std::string id; 80 bool is_update; 81 bool from_ephemeral; 82 83 InstallParameters( 84 const std::string& id, 85 bool is_update, 86 bool from_ephemeral) 87 : id(id), is_update(is_update), from_ephemeral(from_ephemeral) {} 88 }; 89 90 explicit InstallObserver(Profile* profile) : registry_observer_(this) { 91 registry_observer_.Add(ExtensionRegistry::Get(profile)); 92 } 93 94 virtual ~InstallObserver() {} 95 96 const InstallParameters& Last() { 97 CHECK(!install_params_.empty()); 98 return install_params_.back(); 99 } 100 101 private: 102 virtual void OnExtensionWillBeInstalled( 103 content::BrowserContext* browser_context, 104 const Extension* extension, 105 bool is_update, 106 bool from_ephemeral, 107 const std::string& old_name) OVERRIDE { 108 install_params_.push_back( 109 InstallParameters(extension->id(), is_update, from_ephemeral)); 110 } 111 112 std::vector<InstallParameters> install_params_; 113 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> 114 registry_observer_; 115 }; 116 117 } // namespace 118 119 120 // EphemeralAppTestBase: 121 122 const char EphemeralAppTestBase::kMessagingReceiverApp[] = 123 "ephemeral_apps/messaging_receiver"; 124 const char EphemeralAppTestBase::kMessagingReceiverAppV2[] = 125 "ephemeral_apps/messaging_receiver2"; 126 127 EphemeralAppTestBase::EphemeralAppTestBase() {} 128 129 EphemeralAppTestBase::~EphemeralAppTestBase() {} 130 131 void EphemeralAppTestBase::SetUpCommandLine(base::CommandLine* command_line) { 132 // Skip PlatformAppBrowserTest, which sets different values for the switches 133 // below. 134 ExtensionBrowserTest::SetUpCommandLine(command_line); 135 136 // Make event pages get suspended immediately. 137 command_line->AppendSwitchASCII( 138 extensions::switches::kEventPageIdleTime, "10"); 139 command_line->AppendSwitchASCII( 140 extensions::switches::kEventPageSuspendingTime, "10"); 141 142 // Enable ephemeral apps flag. 143 command_line->AppendSwitch(switches::kEnableEphemeralApps); 144 } 145 146 base::FilePath EphemeralAppTestBase::GetTestPath(const char* test_path) { 147 return test_data_dir_.AppendASCII("platform_apps").AppendASCII(test_path); 148 } 149 150 const Extension* EphemeralAppTestBase::InstallEphemeralApp( 151 const char* test_path, Manifest::Location manifest_location) { 152 const Extension* extension = InstallEphemeralAppWithSourceAndFlags( 153 GetTestPath(test_path), 1, manifest_location, Extension::NO_FLAGS); 154 EXPECT_TRUE(extension); 155 if (extension) 156 EXPECT_TRUE(extensions::util::IsEphemeralApp(extension->id(), profile())); 157 return extension; 158 } 159 160 const Extension* EphemeralAppTestBase::InstallEphemeralApp( 161 const char* test_path) { 162 return InstallEphemeralApp(test_path, Manifest::INTERNAL); 163 } 164 165 const Extension* EphemeralAppTestBase::InstallAndLaunchEphemeralApp( 166 const char* test_path) { 167 ExtensionTestMessageListener launched_listener("launched", false); 168 const Extension* extension = InstallEphemeralApp(test_path); 169 EXPECT_TRUE(extension); 170 if (!extension) 171 return NULL; 172 173 LaunchPlatformApp(extension); 174 bool wait_result = launched_listener.WaitUntilSatisfied(); 175 EXPECT_TRUE(wait_result); 176 if (!wait_result) 177 return NULL; 178 179 return extension; 180 } 181 182 const Extension* EphemeralAppTestBase::UpdateEphemeralApp( 183 const std::string& app_id, 184 const base::FilePath& test_dir, 185 const base::FilePath& pem_path) { 186 // Pack a new version of the app. 187 base::ScopedTempDir temp_dir; 188 EXPECT_TRUE(temp_dir.CreateUniqueTempDir()); 189 190 base::FilePath crx_path = temp_dir.path().AppendASCII("temp.crx"); 191 if (!base::DeleteFile(crx_path, false)) { 192 ADD_FAILURE() << "Failed to delete existing crx: " << crx_path.value(); 193 return NULL; 194 } 195 196 base::FilePath app_v2_path = PackExtensionWithOptions( 197 test_dir, crx_path, pem_path, base::FilePath()); 198 EXPECT_FALSE(app_v2_path.empty()); 199 200 // Update the ephemeral app and wait for the update to finish. 201 extensions::CrxInstaller* crx_installer = NULL; 202 content::WindowedNotificationObserver windowed_observer( 203 chrome::NOTIFICATION_CRX_INSTALLER_DONE, 204 content::Source<extensions::CrxInstaller>(crx_installer)); 205 ExtensionService* service = 206 ExtensionSystem::Get(profile())->extension_service(); 207 EXPECT_TRUE(service->UpdateExtension(app_id, app_v2_path, true, 208 &crx_installer)); 209 windowed_observer.Wait(); 210 211 return service->GetExtensionById(app_id, false); 212 } 213 214 void EphemeralAppTestBase::PromoteEphemeralApp( 215 const extensions::Extension* app) { 216 ExtensionService* extension_service = 217 ExtensionSystem::Get(profile())->extension_service(); 218 ASSERT_TRUE(extension_service); 219 extension_service->PromoteEphemeralApp(app, false); 220 } 221 222 void EphemeralAppTestBase::CloseApp(const std::string& app_id) { 223 content::WindowedNotificationObserver event_page_destroyed_signal( 224 chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, 225 content::Source<Profile>(profile())); 226 227 EXPECT_EQ(1U, GetAppWindowCountForApp(app_id)); 228 apps::AppWindow* app_window = GetFirstAppWindowForApp(app_id); 229 ASSERT_TRUE(app_window); 230 CloseAppWindow(app_window); 231 232 event_page_destroyed_signal.Wait(); 233 } 234 235 void EphemeralAppTestBase::EvictApp(const std::string& app_id) { 236 // Uninstall the app, which is what happens when ephemeral apps get evicted 237 // from the cache. 238 content::WindowedNotificationObserver uninstalled_signal( 239 chrome::NOTIFICATION_EXTENSION_UNINSTALLED_DEPRECATED, 240 content::Source<Profile>(profile())); 241 242 ExtensionService* service = 243 ExtensionSystem::Get(profile())->extension_service(); 244 ASSERT_TRUE(service); 245 service->UninstallExtension(app_id, false, NULL); 246 247 uninstalled_signal.Wait(); 248 } 249 250 // EphemeralAppBrowserTest: 251 252 class EphemeralAppBrowserTest : public EphemeralAppTestBase { 253 protected: 254 bool LaunchAppAndRunTest(const Extension* app, const char* test_name) { 255 ExtensionTestMessageListener launched_listener("launched", true); 256 LaunchPlatformApp(app); 257 if (!launched_listener.WaitUntilSatisfied()) { 258 message_ = "Failed to receive launched message from test"; 259 return false; 260 } 261 262 ResultCatcher catcher; 263 launched_listener.Reply(test_name); 264 265 bool result = catcher.GetNextResult(); 266 message_ = catcher.message(); 267 268 CloseApp(app->id()); 269 return result; 270 } 271 272 void VerifyAppNotLoaded(const std::string& app_id) { 273 EXPECT_FALSE(ExtensionSystem::Get(profile())-> 274 process_manager()->GetBackgroundHostForExtension(app_id)); 275 } 276 277 void DispatchAlarmEvent(EventRouter* event_router, 278 const std::string& app_id) { 279 alarms::Alarm dummy_alarm; 280 dummy_alarm.name = "test_alarm"; 281 282 scoped_ptr<base::ListValue> args(new base::ListValue()); 283 args->Append(dummy_alarm.ToValue().release()); 284 scoped_ptr<Event> event(new Event(alarms::OnAlarm::kEventName, 285 args.Pass())); 286 287 event_router->DispatchEventToExtension(app_id, event.Pass()); 288 } 289 290 const Extension* ReplaceEphemeralApp(const std::string& app_id, 291 const char* test_path) { 292 return UpdateExtensionWaitForIdle(app_id, GetTestPath(test_path), 0); 293 } 294 295 void VerifyPromotedApp(const std::string& app_id, 296 ExtensionRegistry::IncludeFlag expected_set) { 297 const Extension* app = ExtensionRegistry::Get(profile())->GetExtensionById( 298 app_id, expected_set); 299 ASSERT_TRUE(app); 300 301 // The app should not be ephemeral. 302 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); 303 ASSERT_TRUE(prefs); 304 EXPECT_FALSE(prefs->IsEphemeralApp(app_id)); 305 306 // Check sort ordinals. 307 extensions::AppSorting* app_sorting = prefs->app_sorting(); 308 EXPECT_TRUE(app_sorting->GetAppLaunchOrdinal(app_id).IsValid()); 309 EXPECT_TRUE(app_sorting->GetPageOrdinal(app_id).IsValid()); 310 } 311 312 void InitSyncService() { 313 ExtensionSyncService* sync_service = ExtensionSyncService::Get(profile()); 314 sync_service->MergeDataAndStartSyncing( 315 syncer::APPS, 316 syncer::SyncDataList(), 317 scoped_ptr<syncer::SyncChangeProcessor>( 318 new syncer::SyncChangeProcessorWrapperForTest( 319 &mock_sync_processor_)), 320 scoped_ptr<syncer::SyncErrorFactory>( 321 new syncer::SyncErrorFactoryMock())); 322 } 323 324 scoped_ptr<AppSyncData> GetFirstSyncChangeForApp(const std::string& id) { 325 scoped_ptr<AppSyncData> sync_data; 326 for (syncer::SyncChangeList::iterator it = 327 mock_sync_processor_.changes().begin(); 328 it != mock_sync_processor_.changes().end(); ++it) { 329 sync_data.reset(new AppSyncData(*it)); 330 if (sync_data->id() == id) 331 return sync_data.Pass(); 332 } 333 334 return scoped_ptr<AppSyncData>(); 335 } 336 337 void VerifySyncChange(const AppSyncData* sync_change, bool expect_enabled) { 338 ASSERT_TRUE(sync_change); 339 EXPECT_TRUE(sync_change->page_ordinal().IsValid()); 340 EXPECT_TRUE(sync_change->app_launch_ordinal().IsValid()); 341 EXPECT_FALSE(sync_change->uninstalled()); 342 EXPECT_EQ(expect_enabled, sync_change->extension_sync_data().enabled()); 343 } 344 345 syncer::FakeSyncChangeProcessor mock_sync_processor_; 346 }; 347 348 // Verify that ephemeral apps can be launched and receive system events when 349 // they are running. Once they are inactive they should not receive system 350 // events. 351 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, EventDispatchWhenLaunched) { 352 const Extension* extension = 353 InstallAndLaunchEphemeralApp(kDispatchEventTestApp); 354 ASSERT_TRUE(extension); 355 356 // Send a fake alarm event to the app and verify that a response is 357 // received. 358 EventRouter* event_router = EventRouter::Get(profile()); 359 ASSERT_TRUE(event_router); 360 361 ExtensionTestMessageListener alarm_received_listener("alarm_received", false); 362 DispatchAlarmEvent(event_router, extension->id()); 363 ASSERT_TRUE(alarm_received_listener.WaitUntilSatisfied()); 364 365 CloseApp(extension->id()); 366 367 // The app needs to be launched once in order to have the onAlarm() event 368 // registered. 369 ASSERT_TRUE(event_router->ExtensionHasEventListener( 370 extension->id(), alarms::OnAlarm::kEventName)); 371 372 // Dispatch the alarm event again and verify that the event page did not get 373 // loaded for the app. 374 DispatchAlarmEvent(event_router, extension->id()); 375 VerifyAppNotLoaded(extension->id()); 376 } 377 378 // Verify that ephemeral apps will receive messages while they are running. 379 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, ReceiveMessagesWhenLaunched) { 380 const Extension* receiver = 381 InstallAndLaunchEphemeralApp(kMessagingReceiverApp); 382 ASSERT_TRUE(receiver); 383 384 // Verify that messages are received while the app is running. 385 ExtensionApiTest::ResultCatcher result_catcher; 386 LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_success", 387 "Launched"); 388 EXPECT_TRUE(result_catcher.GetNextResult()); 389 390 CloseApp(receiver->id()); 391 392 // Verify that messages are not received while the app is inactive. 393 LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_fail", "Launched"); 394 EXPECT_TRUE(result_catcher.GetNextResult()); 395 } 396 397 // Verify that an updated ephemeral app will still have its ephemeral flag 398 // enabled. 399 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, UpdateEphemeralApp) { 400 const Extension* app_v1 = InstallEphemeralApp(kMessagingReceiverApp); 401 ASSERT_TRUE(app_v1); 402 std::string app_id = app_v1->id(); 403 base::Version app_original_version = *app_v1->version(); 404 app_v1 = NULL; // The extension object will be destroyed during update. 405 406 // Update to version 2 of the app. 407 InstallObserver installed_observer(profile()); 408 const Extension* app_v2 = UpdateEphemeralApp( 409 app_id, GetTestPath(kMessagingReceiverAppV2), 410 GetTestPath(kMessagingReceiverApp).ReplaceExtension( 411 FILE_PATH_LITERAL(".pem"))); 412 413 // Check the notification parameters. 414 const InstallObserver::InstallParameters& params = installed_observer.Last(); 415 EXPECT_EQ(app_id, params.id); 416 EXPECT_TRUE(params.is_update); 417 EXPECT_FALSE(params.from_ephemeral); 418 419 // The ephemeral flag should still be enabled. 420 ASSERT_TRUE(app_v2); 421 EXPECT_TRUE(app_v2->version()->CompareTo(app_original_version) > 0); 422 EXPECT_TRUE(extensions::util::IsEphemeralApp(app_v2->id(), profile())); 423 } 424 425 // Verify that if notifications have been disabled for an ephemeral app, it will 426 // remain disabled even after being evicted from the cache. 427 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, StickyNotificationSettings) { 428 const Extension* app = InstallEphemeralApp(kNotificationsTestApp); 429 ASSERT_TRUE(app); 430 431 // Disable notifications for this app. 432 DesktopNotificationService* notification_service = 433 DesktopNotificationServiceFactory::GetForProfile(profile()); 434 ASSERT_TRUE(notification_service); 435 436 message_center::NotifierId notifier_id( 437 message_center::NotifierId::APPLICATION, app->id()); 438 EXPECT_TRUE(notification_service->IsNotifierEnabled(notifier_id)); 439 notification_service->SetNotifierEnabled(notifier_id, false); 440 EXPECT_FALSE(notification_service->IsNotifierEnabled(notifier_id)); 441 442 // Remove the app. 443 EvictApp(app->id()); 444 445 // Reinstall the ephemeral app and verify that notifications remain disabled. 446 app = InstallEphemeralApp(kNotificationsTestApp); 447 ASSERT_TRUE(app); 448 message_center::NotifierId reinstalled_notifier_id( 449 message_center::NotifierId::APPLICATION, app->id()); 450 EXPECT_FALSE(notification_service->IsNotifierEnabled( 451 reinstalled_notifier_id)); 452 } 453 454 // Verify that only running ephemeral apps will appear in the Notification 455 // Settings UI. Inactive, cached ephemeral apps should not appear. 456 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 457 IncludeRunningEphemeralAppsInNotifiers) { 458 message_center::NotifierSettingsProvider* settings_provider = 459 message_center::MessageCenter::Get()->GetNotifierSettingsProvider(); 460 // TODO(tmdiep): Remove once notifications settings are supported across 461 // all platforms. This test will fail for Linux GTK. 462 if (!settings_provider) 463 return; 464 465 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 466 ASSERT_TRUE(app); 467 message_center::NotifierId notifier_id( 468 message_center::NotifierId::APPLICATION, app->id()); 469 470 // Since the ephemeral app is running, it should be included in the list 471 // of notifiers to show in the UI. 472 NotifierList notifiers; 473 STLElementDeleter<NotifierList> notifier_deleter(¬ifiers); 474 475 settings_provider->GetNotifierList(¬ifiers); 476 EXPECT_TRUE(IsNotifierInList(notifier_id, notifiers)); 477 STLDeleteElements(¬ifiers); 478 479 // Close the ephemeral app. 480 CloseApp(app->id()); 481 482 // Inactive ephemeral apps should not be included in the list of notifiers to 483 // show in the UI. 484 settings_provider->GetNotifierList(¬ifiers); 485 EXPECT_FALSE(IsNotifierInList(notifier_id, notifiers)); 486 } 487 488 // Verify that ephemeral apps will have no ability to retain file entries after 489 // close. Normal retainEntry behavior for installed apps is tested in 490 // FileSystemApiTest. 491 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 492 DisableRetainFileSystemEntries) { 493 // Create a dummy file that we can just return to the test. 494 base::ScopedTempDir temp_dir; 495 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 496 base::FilePath temp_file; 497 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file)); 498 499 using extensions::FileSystemChooseEntryFunction; 500 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest( 501 &temp_file); 502 // The temporary file needs to be registered for the tests to pass on 503 // ChromeOS. 504 FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( 505 "temp", temp_dir.path()); 506 507 // The first test opens the file and writes the file handle to local storage. 508 const Extension* app = InstallEphemeralApp(kFileSystemTestApp, 509 Manifest::UNPACKED); 510 ASSERT_TRUE(LaunchAppAndRunTest(app, "OpenAndRetainFile")) << message_; 511 512 // Verify that after the app has been closed, all retained entries are 513 // flushed. 514 std::vector<apps::SavedFileEntry> file_entries = 515 apps::SavedFilesService::Get(profile()) 516 ->GetAllFileEntries(app->id()); 517 EXPECT_TRUE(file_entries.empty()); 518 519 // The second test verifies that the file cannot be reopened. 520 ASSERT_TRUE(LaunchAppAndRunTest(app, "RestoreRetainedFile")) << message_; 521 } 522 523 // Checks the process of installing and then promoting an ephemeral app. 524 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteEphemeralApp) { 525 InitSyncService(); 526 527 const Extension* app = InstallEphemeralApp(kNotificationsTestApp); 528 ASSERT_TRUE(app); 529 530 // Ephemeral apps should not be synced. 531 scoped_ptr<AppSyncData> sync_change = GetFirstSyncChangeForApp(app->id()); 532 EXPECT_FALSE(sync_change.get()); 533 534 // Promote the app to a regular installed app. 535 InstallObserver installed_observer(profile()); 536 PromoteEphemeralApp(app); 537 VerifyPromotedApp(app->id(), ExtensionRegistry::ENABLED); 538 539 // Check the notification parameters. 540 const InstallObserver::InstallParameters& params = installed_observer.Last(); 541 EXPECT_EQ(app->id(), params.id); 542 EXPECT_TRUE(params.is_update); 543 EXPECT_TRUE(params.from_ephemeral); 544 545 // The installation should now be synced. 546 sync_change = GetFirstSyncChangeForApp(app->id()); 547 VerifySyncChange(sync_change.get(), true); 548 } 549 550 // Verifies that promoting an ephemeral app will enable it. 551 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteEphemeralAppAndEnable) { 552 InitSyncService(); 553 554 const Extension* app = InstallEphemeralApp(kNotificationsTestApp); 555 ASSERT_TRUE(app); 556 557 // Disable the ephemeral app due to a permissions increase. This also involves 558 // setting the DidExtensionEscalatePermissions flag. 559 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); 560 prefs->SetDidExtensionEscalatePermissions(app, true); 561 ExtensionService* service = 562 ExtensionSystem::Get(profile())->extension_service(); 563 service->DisableExtension(app->id(), Extension::DISABLE_PERMISSIONS_INCREASE); 564 ASSERT_TRUE(ExtensionRegistry::Get(profile())-> 565 GetExtensionById(app->id(), ExtensionRegistry::DISABLED)); 566 567 // Promote to a regular installed app. It should be enabled. 568 PromoteEphemeralApp(app); 569 VerifyPromotedApp(app->id(), ExtensionRegistry::ENABLED); 570 EXPECT_FALSE(prefs->DidExtensionEscalatePermissions(app->id())); 571 572 scoped_ptr<AppSyncData> sync_change = GetFirstSyncChangeForApp(app->id()); 573 VerifySyncChange(sync_change.get(), true); 574 } 575 576 // Verifies that promoting an ephemeral app that has unsupported requirements 577 // will not enable it. 578 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 579 PromoteUnsupportedEphemeralApp) { 580 InitSyncService(); 581 582 const Extension* app = InstallEphemeralApp(kNotificationsTestApp); 583 ASSERT_TRUE(app); 584 585 // Disable the ephemeral app. 586 ExtensionService* service = 587 ExtensionSystem::Get(profile())->extension_service(); 588 service->DisableExtension( 589 app->id(), Extension::DISABLE_UNSUPPORTED_REQUIREMENT); 590 ASSERT_TRUE(ExtensionRegistry::Get(profile())-> 591 GetExtensionById(app->id(), ExtensionRegistry::DISABLED)); 592 593 // Promote to a regular installed app. It should remain disabled. 594 PromoteEphemeralApp(app); 595 VerifyPromotedApp(app->id(), ExtensionRegistry::DISABLED); 596 597 scoped_ptr<AppSyncData> sync_change = GetFirstSyncChangeForApp(app->id()); 598 VerifySyncChange(sync_change.get(), false); 599 } 600 601 // Checks the process of promoting an ephemeral app from sync. 602 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, PromoteEphemeralAppFromSync) { 603 InitSyncService(); 604 605 const Extension* app = InstallEphemeralApp(kNotificationsTestApp); 606 ASSERT_TRUE(app); 607 std::string app_id = app->id(); 608 609 // Simulate an install from sync. 610 const syncer::StringOrdinal kAppLaunchOrdinal("x"); 611 const syncer::StringOrdinal kPageOrdinal("y"); 612 AppSyncData app_sync_data( 613 *app, 614 true /* enabled */, 615 false /* incognito enabled */, 616 false /* remote install */, 617 kAppLaunchOrdinal, 618 kPageOrdinal, 619 extensions::LAUNCH_TYPE_REGULAR); 620 621 ExtensionSyncService* sync_service = ExtensionSyncService::Get(profile()); 622 sync_service->ProcessAppSyncData(app_sync_data); 623 624 // Verify the installation. 625 VerifyPromotedApp(app_id, ExtensionRegistry::ENABLED); 626 627 // The sort ordinals from sync should not be overridden. 628 ExtensionPrefs* prefs = ExtensionPrefs::Get(profile()); 629 extensions::AppSorting* app_sorting = prefs->app_sorting(); 630 EXPECT_TRUE(app_sorting->GetAppLaunchOrdinal(app_id).Equals( 631 kAppLaunchOrdinal)); 632 EXPECT_TRUE(app_sorting->GetPageOrdinal(app_id).Equals(kPageOrdinal)); 633 } 634 635 // In most cases, ExtensionService::PromoteEphemeralApp() will be called to 636 // permanently install an ephemeral app. However, there may be cases where an 637 // install occurs through the usual route of installing from the Web Store (due 638 // to race conditions). Ensure that the app is still installed correctly. 639 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 640 ReplaceEphemeralAppWithInstalledApp) { 641 const Extension* app = InstallEphemeralApp(kNotificationsTestApp); 642 ASSERT_TRUE(app); 643 std::string app_id = app->id(); 644 app = NULL; 645 646 InstallObserver installed_observer(profile()); 647 ReplaceEphemeralApp(app_id, kNotificationsTestApp); 648 VerifyPromotedApp(app_id, ExtensionRegistry::ENABLED); 649 650 // Check the notification parameters. 651 const InstallObserver::InstallParameters& params = installed_observer.Last(); 652 EXPECT_EQ(app_id, params.id); 653 EXPECT_TRUE(params.is_update); 654 EXPECT_TRUE(params.from_ephemeral); 655 } 656 657 // This is similar to ReplaceEphemeralAppWithInstalledApp, but installs will 658 // be delayed until the app is idle. 659 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, 660 ReplaceEphemeralAppWithDelayedInstalledApp) { 661 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp); 662 ASSERT_TRUE(app); 663 std::string app_id = app->id(); 664 app = NULL; 665 666 // Initiate install. 667 ReplaceEphemeralApp(app_id, kNotificationsTestApp); 668 669 // The delayed installation will occur when the ephemeral app is closed. 670 content::WindowedNotificationObserver installed_signal( 671 chrome::NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED, 672 content::Source<Profile>(profile())); 673 InstallObserver installed_observer(profile()); 674 CloseApp(app_id); 675 installed_signal.Wait(); 676 VerifyPromotedApp(app_id, ExtensionRegistry::ENABLED); 677 678 // Check the notification parameters. 679 const InstallObserver::InstallParameters& params = installed_observer.Last(); 680 EXPECT_EQ(app_id, params.id); 681 EXPECT_TRUE(params.is_update); 682 EXPECT_TRUE(params.from_ephemeral); 683 } 684