• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
IsNotifierInList(const message_center::NotifierId & notifier_id,const NotifierList & notifiers)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 
InstallParameters__anon52cacdbc0111::InstallObserver::InstallParameters83     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 
InstallObserver(Profile * profile)90   explicit InstallObserver(Profile* profile) : registry_observer_(this) {
91     registry_observer_.Add(ExtensionRegistry::Get(profile));
92   }
93 
~InstallObserver()94   virtual ~InstallObserver() {}
95 
Last()96   const InstallParameters& Last() {
97     CHECK(!install_params_.empty());
98     return install_params_.back();
99   }
100 
101  private:
OnExtensionWillBeInstalled(content::BrowserContext * browser_context,const Extension * extension,bool is_update,bool from_ephemeral,const std::string & old_name)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 
EphemeralAppTestBase()127 EphemeralAppTestBase::EphemeralAppTestBase() {}
128 
~EphemeralAppTestBase()129 EphemeralAppTestBase::~EphemeralAppTestBase() {}
130 
SetUpCommandLine(base::CommandLine * command_line)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 
GetTestPath(const char * test_path)146 base::FilePath EphemeralAppTestBase::GetTestPath(const char* test_path) {
147   return test_data_dir_.AppendASCII("platform_apps").AppendASCII(test_path);
148 }
149 
InstallEphemeralApp(const char * test_path,Manifest::Location manifest_location)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 
InstallEphemeralApp(const char * test_path)160 const Extension* EphemeralAppTestBase::InstallEphemeralApp(
161     const char* test_path) {
162   return InstallEphemeralApp(test_path, Manifest::INTERNAL);
163 }
164 
InstallAndLaunchEphemeralApp(const char * test_path)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 
UpdateEphemeralApp(const std::string & app_id,const base::FilePath & test_dir,const base::FilePath & pem_path)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 
PromoteEphemeralApp(const extensions::Extension * app)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 
CloseApp(const std::string & app_id)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 
EvictApp(const std::string & app_id)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:
LaunchAppAndRunTest(const Extension * app,const char * test_name)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 
VerifyAppNotLoaded(const std::string & app_id)272   void VerifyAppNotLoaded(const std::string& app_id) {
273     EXPECT_FALSE(ExtensionSystem::Get(profile())->
274         process_manager()->GetBackgroundHostForExtension(app_id));
275   }
276 
DispatchAlarmEvent(EventRouter * event_router,const std::string & app_id)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 
ReplaceEphemeralApp(const std::string & app_id,const char * test_path)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 
VerifyPromotedApp(const std::string & app_id,ExtensionRegistry::IncludeFlag expected_set)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 
InitSyncService()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 
GetFirstSyncChangeForApp(const std::string & id)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 
VerifySyncChange(const AppSyncData * sync_change,bool expect_enabled)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,EventDispatchWhenLaunched)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,ReceiveMessagesWhenLaunched)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,UpdateEphemeralApp)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,StickyNotificationSettings)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,IncludeRunningEphemeralAppsInNotifiers)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,DisableRetainFileSystemEntries)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,PromoteEphemeralApp)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,PromoteEphemeralAppAndEnable)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,PromoteUnsupportedEphemeralApp)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,PromoteEphemeralAppFromSync)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,ReplaceEphemeralAppWithInstalledApp)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.
IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,ReplaceEphemeralAppWithDelayedInstalledApp)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