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(&notifiers);
741
742  settings_provider->GetNotifierList(&notifiers);
743  EXPECT_TRUE(IsNotifierInList(notifier_id, notifiers));
744  STLDeleteElements(&notifiers);
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(&notifiers);
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