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