Home | History | Annotate | Download | only in apps
      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(&notifiers);
    474 
    475   settings_provider->GetNotifierList(&notifiers);
    476   EXPECT_TRUE(IsNotifierInList(notifier_id, notifiers));
    477   STLDeleteElements(&notifiers);
    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(&notifiers);
    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