[safe-browsing] Database full hash matches like prefix match.
[chromium-blink-merge.git] / chrome / browser / apps / ephemeral_app_browsertest.cc
blob1f895c62f8a21315a86920f64250c82031776b63
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.
5 #include "apps/saved_files_service.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/stl_util.h"
8 #include "chrome/browser/apps/app_browsertest_util.h"
9 #include "chrome/browser/apps/ephemeral_app_service.h"
10 #include "chrome/browser/extensions/api/file_system/file_system_api.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/extension_test_message_listener.h"
13 #include "chrome/browser/extensions/extension_util.h"
14 #include "chrome/browser/notifications/desktop_notification_service.h"
15 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
16 #include "chrome/common/extensions/api/alarms.h"
17 #include "content/public/test/browser_test.h"
18 #include "content/public/test/test_utils.h"
19 #include "extensions/browser/event_router.h"
20 #include "extensions/browser/extension_prefs.h"
21 #include "extensions/browser/extension_system.h"
22 #include "extensions/browser/process_manager.h"
23 #include "extensions/common/switches.h"
24 #include "ui/message_center/message_center.h"
25 #include "ui/message_center/notifier_settings.h"
27 using extensions::Event;
28 using extensions::EventRouter;
29 using extensions::Extension;
30 using extensions::ExtensionInfo;
31 using extensions::ExtensionPrefs;
32 using extensions::ExtensionSystem;
33 using extensions::Manifest;
34 using extensions::PlatformAppBrowserTest;
36 namespace {
38 namespace alarms = extensions::api::alarms;
40 const char kDispatchEventTestApp[] = "ephemeral_apps/dispatch_event";
41 const char kMessagingReceiverApp[] = "ephemeral_apps/messaging_receiver";
42 const char kMessagingReceiverAppV2[] = "ephemeral_apps/messaging_receiver2";
43 const char kNotificationsTestApp[] = "ephemeral_apps/notification_settings";
44 const char kFileSystemTestApp[] = "ephemeral_apps/filesystem_retain_entries";
45 const char kRetainDataApp[] = "ephemeral_apps/retain_data";
47 typedef std::vector<message_center::Notifier*> NotifierList;
49 bool IsNotifierInList(const message_center::NotifierId& notifier_id,
50 const NotifierList& notifiers) {
51 for (NotifierList::const_iterator it = notifiers.begin();
52 it != notifiers.end(); ++it) {
53 const message_center::Notifier* notifier = *it;
54 if (notifier->notifier_id == notifier_id)
55 return true;
58 return false;
61 bool IsAppInExtensionsInfo(const ExtensionPrefs::ExtensionsInfo& ext_info,
62 const std::string& extension_id) {
63 for (size_t i = 0; i < ext_info.size(); ++i) {
64 ExtensionInfo* info = ext_info.at(i).get();
65 if (info->extension_id == extension_id)
66 return true;
69 return false;
72 } // namespace
74 class EphemeralAppBrowserTest : public PlatformAppBrowserTest {
75 protected:
76 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
77 // Skip PlatformAppBrowserTest, which sets different values for the switches
78 // below.
79 ExtensionBrowserTest::SetUpCommandLine(command_line);
81 // Make event pages get suspended immediately.
82 command_line->AppendSwitchASCII(
83 extensions::switches::kEventPageIdleTime, "10");
84 command_line->AppendSwitchASCII(
85 extensions::switches::kEventPageSuspendingTime, "10");
88 base::FilePath GetTestPath(const char* test_path) {
89 return test_data_dir_.AppendASCII("platform_apps").AppendASCII(test_path);
92 const Extension* InstallEphemeralApp(const char* test_path,
93 Manifest::Location manifest_location) {
94 const Extension* extension =
95 InstallExtensionWithSourceAndFlags(
96 GetTestPath(test_path),
98 manifest_location,
99 Extension::IS_EPHEMERAL);
100 return extension;
103 const Extension* InstallEphemeralApp(const char* test_path) {
104 return InstallEphemeralApp(test_path, Manifest::INTERNAL);
107 const Extension* InstallAndLaunchEphemeralApp(const char* test_path) {
108 ExtensionTestMessageListener launched_listener("launched", false);
109 const Extension* extension = InstallEphemeralApp(test_path);
110 EXPECT_TRUE(extension);
111 if (!extension)
112 return NULL;
114 LaunchPlatformApp(extension);
115 bool wait_result = launched_listener.WaitUntilSatisfied();
116 EXPECT_TRUE(wait_result);
117 if (!wait_result)
118 return NULL;
120 return extension;
123 bool LaunchAppAndRunTest(const Extension* app, const char* test_name) {
124 ExtensionTestMessageListener launched_listener("launched", true);
125 LaunchPlatformApp(app);
126 if (!launched_listener.WaitUntilSatisfied()) {
127 message_ = "Failed to receive launched message from test";
128 return false;
131 launched_listener.Reply(test_name);
133 ResultCatcher catcher;
134 if (!catcher.GetNextResult()) {
135 message_ = catcher.message();
136 return false;
139 CloseApp(app->id());
140 return true;
143 void CloseApp(const std::string& app_id) {
144 content::WindowedNotificationObserver event_page_destroyed_signal(
145 chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
146 content::Source<Profile>(browser()->profile()));
148 EXPECT_EQ(1U, GetAppWindowCountForApp(app_id));
149 apps::AppWindow* app_window = GetFirstAppWindowForApp(app_id);
150 ASSERT_TRUE(app_window);
151 CloseAppWindow(app_window);
153 event_page_destroyed_signal.Wait();
156 void EvictApp(const std::string& app_id) {
157 // Uninstall the app, which is what happens when ephemeral apps get evicted
158 // from the cache.
159 content::WindowedNotificationObserver uninstalled_signal(
160 chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
161 content::Source<Profile>(browser()->profile()));
163 ExtensionService* service =
164 ExtensionSystem::Get(browser()->profile())->extension_service();
165 ASSERT_TRUE(service);
166 service->UninstallExtension(app_id, false, NULL);
168 uninstalled_signal.Wait();
171 void VerifyAppNotLoaded(const std::string& app_id) {
172 EXPECT_FALSE(ExtensionSystem::Get(browser()->profile())->
173 process_manager()->GetBackgroundHostForExtension(app_id));
176 void DispatchAlarmEvent(EventRouter* event_router,
177 const std::string& app_id) {
178 alarms::Alarm dummy_alarm;
179 dummy_alarm.name = "test_alarm";
181 scoped_ptr<base::ListValue> args(new base::ListValue());
182 args->Append(dummy_alarm.ToValue().release());
183 scoped_ptr<Event> event(new Event(alarms::OnAlarm::kEventName,
184 args.Pass()));
186 event_router->DispatchEventToExtension(app_id, event.Pass());
189 void GarbageCollectData() {
190 EphemeralAppService* service =
191 EphemeralAppService::Get(browser()->profile());
192 ASSERT_TRUE(service);
193 service->GarbageCollectData();
197 // Verify that ephemeral apps can be launched and receive system events when
198 // they are running. Once they are inactive they should not receive system
199 // events.
200 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, EventDispatchWhenLaunched) {
201 const Extension* extension =
202 InstallAndLaunchEphemeralApp(kDispatchEventTestApp);
203 ASSERT_TRUE(extension);
205 // Send a fake alarm event to the app and verify that a response is
206 // received.
207 EventRouter* event_router = EventRouter::Get(browser()->profile());
208 ASSERT_TRUE(event_router);
210 ExtensionTestMessageListener alarm_received_listener("alarm_received", false);
211 DispatchAlarmEvent(event_router, extension->id());
212 ASSERT_TRUE(alarm_received_listener.WaitUntilSatisfied());
214 CloseApp(extension->id());
216 // The app needs to be launched once in order to have the onAlarm() event
217 // registered.
218 ASSERT_TRUE(event_router->ExtensionHasEventListener(
219 extension->id(), alarms::OnAlarm::kEventName));
221 // Dispatch the alarm event again and verify that the event page did not get
222 // loaded for the app.
223 DispatchAlarmEvent(event_router, extension->id());
224 VerifyAppNotLoaded(extension->id());
227 // Verify that ephemeral apps will receive messages while they are running.
228 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, ReceiveMessagesWhenLaunched) {
229 const Extension* receiver =
230 InstallAndLaunchEphemeralApp(kMessagingReceiverApp);
231 ASSERT_TRUE(receiver);
233 // Verify that messages are received while the app is running.
234 ExtensionApiTest::ResultCatcher result_catcher;
235 LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_success");
236 EXPECT_TRUE(result_catcher.GetNextResult());
238 CloseApp(receiver->id());
240 // Verify that messages are not received while the app is inactive.
241 LoadAndLaunchPlatformApp("ephemeral_apps/messaging_sender_fail");
242 EXPECT_TRUE(result_catcher.GetNextResult());
245 // Verify that an updated ephemeral app will still have its ephemeral flag
246 // enabled.
247 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, UpdateEphemeralApp) {
248 const Extension* app_v1 = InstallEphemeralApp(kMessagingReceiverApp);
249 ASSERT_TRUE(app_v1);
250 ASSERT_TRUE(app_v1->is_ephemeral());
251 std::string app_id = app_v1->id();
252 base::Version app_original_version = *app_v1->version();
253 app_v1 = NULL; // The extension object will be destroyed during update.
255 // Pack version 2 of the app.
256 base::ScopedTempDir temp_dir;
257 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
259 base::FilePath crx_path = temp_dir.path().AppendASCII("temp.crx");
260 if (!base::DeleteFile(crx_path, false)) {
261 ADD_FAILURE() << "Failed to delete crx: " << crx_path.value();
262 return;
265 base::FilePath app_v2_path = PackExtensionWithOptions(
266 GetTestPath(kMessagingReceiverAppV2),
267 crx_path,
268 GetTestPath(kMessagingReceiverApp).ReplaceExtension(
269 FILE_PATH_LITERAL(".pem")),
270 base::FilePath());
271 ASSERT_FALSE(app_v2_path.empty());
273 // Update the ephemeral app and wait for the update to finish.
274 extensions::CrxInstaller* crx_installer = NULL;
275 content::WindowedNotificationObserver windowed_observer(
276 chrome::NOTIFICATION_CRX_INSTALLER_DONE,
277 content::Source<extensions::CrxInstaller>(crx_installer));
278 ExtensionService* service =
279 ExtensionSystem::Get(browser()->profile())->extension_service();
280 EXPECT_TRUE(service->UpdateExtension(app_id, app_v2_path, true,
281 &crx_installer));
282 windowed_observer.Wait();
284 const Extension* app_v2 = service->GetExtensionById(app_id, false);
285 ASSERT_TRUE(app_v2);
286 EXPECT_TRUE(app_v2->version()->CompareTo(app_original_version) > 0);
287 EXPECT_TRUE(app_v2->is_ephemeral());
290 // Verify that if notifications have been disabled for an ephemeral app, it will
291 // remain disabled even after being evicted from the cache.
292 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, StickyNotificationSettings) {
293 const Extension* app = InstallEphemeralApp(kNotificationsTestApp);
294 ASSERT_TRUE(app);
296 // Disable notifications for this app.
297 DesktopNotificationService* notification_service =
298 DesktopNotificationServiceFactory::GetForProfile(browser()->profile());
299 ASSERT_TRUE(notification_service);
301 message_center::NotifierId notifier_id(
302 message_center::NotifierId::APPLICATION, app->id());
303 EXPECT_TRUE(notification_service->IsNotifierEnabled(notifier_id));
304 notification_service->SetNotifierEnabled(notifier_id, false);
305 EXPECT_FALSE(notification_service->IsNotifierEnabled(notifier_id));
307 // Remove the app.
308 EvictApp(app->id());
310 // Reinstall the ephemeral app and verify that notifications remain disabled.
311 app = InstallEphemeralApp(kNotificationsTestApp);
312 ASSERT_TRUE(app);
313 message_center::NotifierId reinstalled_notifier_id(
314 message_center::NotifierId::APPLICATION, app->id());
315 EXPECT_FALSE(notification_service->IsNotifierEnabled(
316 reinstalled_notifier_id));
319 // Verify that only running ephemeral apps will appear in the Notification
320 // Settings UI. Inactive, cached ephemeral apps should not appear.
321 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
322 IncludeRunningEphemeralAppsInNotifiers) {
323 message_center::NotifierSettingsProvider* settings_provider =
324 message_center::MessageCenter::Get()->GetNotifierSettingsProvider();
325 // TODO(tmdiep): Remove once notifications settings are supported across
326 // all platforms. This test will fail for Linux GTK.
327 if (!settings_provider)
328 return;
330 const Extension* app = InstallAndLaunchEphemeralApp(kNotificationsTestApp);
331 ASSERT_TRUE(app);
332 message_center::NotifierId notifier_id(
333 message_center::NotifierId::APPLICATION, app->id());
335 // Since the ephemeral app is running, it should be included in the list
336 // of notifiers to show in the UI.
337 NotifierList notifiers;
338 STLElementDeleter<NotifierList> notifier_deleter(&notifiers);
340 settings_provider->GetNotifierList(&notifiers);
341 EXPECT_TRUE(IsNotifierInList(notifier_id, notifiers));
342 STLDeleteElements(&notifiers);
344 // Close the ephemeral app.
345 CloseApp(app->id());
347 // Inactive ephemeral apps should not be included in the list of notifiers to
348 // show in the UI.
349 settings_provider->GetNotifierList(&notifiers);
350 EXPECT_FALSE(IsNotifierInList(notifier_id, notifiers));
353 // Verify that ephemeral apps will have no ability to retain file entries after
354 // close. Normal retainEntry behavior for installed apps is tested in
355 // FileSystemApiTest.
356 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest,
357 DisableRetainFileSystemEntries) {
358 // Create a dummy file that we can just return to the test.
359 base::ScopedTempDir temp_dir;
360 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
361 base::FilePath temp_file;
362 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.path(), &temp_file));
364 using extensions::FileSystemChooseEntryFunction;
365 FileSystemChooseEntryFunction::SkipPickerAndAlwaysSelectPathForTest(
366 &temp_file);
367 // The temporary file needs to be registered for the tests to pass on
368 // ChromeOS.
369 FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest(
370 "temp", temp_dir.path());
372 // The first test opens the file and writes the file handle to local storage.
373 const Extension* app = InstallEphemeralApp(kFileSystemTestApp,
374 Manifest::UNPACKED);
375 ASSERT_TRUE(LaunchAppAndRunTest(app, "OpenAndRetainFile")) << message_;
377 // Verify that after the app has been closed, all retained entries are
378 // flushed.
379 std::vector<apps::SavedFileEntry> file_entries =
380 apps::SavedFilesService::Get(browser()->profile())
381 ->GetAllFileEntries(app->id());
382 EXPECT_TRUE(file_entries.empty());
384 // The second test verifies that the file cannot be reopened.
385 ASSERT_TRUE(LaunchAppAndRunTest(app, "RestoreRetainedFile")) << message_;
388 // Verify that once evicted from the cache, the data of ephemeral apps will not
389 // be deleted.
390 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, RetainData) {
391 // Phase 1 - Install the ephemeral app and write data to various storage.
392 const Extension* app = InstallEphemeralApp(kRetainDataApp);
393 ASSERT_TRUE(app);
394 ASSERT_TRUE(LaunchAppAndRunTest(app, "WriteData")) << message_;
396 // Sanity check to ensure that the ReadData tests should pass before the app
397 // is removed.
398 ASSERT_TRUE(LaunchAppAndRunTest(app, "ReadData")) << message_;
400 // Remove the app.
401 const std::string app_id = app->id();
402 EvictApp(app->id());
403 app = NULL;
405 // The app should be in the list of evicted apps.
406 ExtensionPrefs* prefs = ExtensionPrefs::Get(browser()->profile());
407 ASSERT_TRUE(prefs);
408 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
409 prefs->GetEvictedEphemeralAppsInfo());
410 EXPECT_TRUE(IsAppInExtensionsInfo(*extensions_info, app_id));
412 // The app should not be in the list of installed extensions.
413 extensions_info = prefs->GetInstalledExtensionsInfo();
414 EXPECT_FALSE(IsAppInExtensionsInfo(*extensions_info, app_id));
416 // Ensure the evicted app is considered to have isolated storage. This will
417 // prevent its data from getting garbage collected by
418 // ExtensionService::GarbageCollectIsolatedStorage().
419 GURL site_url = extensions::util::GetSiteForExtensionId(
420 app_id, browser()->profile());
421 EXPECT_TRUE(extensions::util::SiteHasIsolatedStorage(
422 site_url, browser()->profile()));
424 // Phase 2 - Reinstall the ephemeral app and verify that data still exists
425 // in the storage.
426 app = InstallEphemeralApp(kRetainDataApp);
427 ASSERT_TRUE(app);
428 EXPECT_TRUE(LaunchAppAndRunTest(app, "ReadData")) << message_;
430 // The app should now be in the list of installed extensions, but not in the
431 // list of evicted apps.
432 extensions_info = prefs->GetInstalledExtensionsInfo();
433 EXPECT_TRUE(IsAppInExtensionsInfo(*extensions_info, app_id));
434 extensions_info = prefs->GetEvictedEphemeralAppsInfo();
435 EXPECT_FALSE(IsAppInExtensionsInfo(*extensions_info, app_id));
438 // Verify that the data of regular installed apps are deleted on uninstall.
439 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, RemoveInstalledData) {
440 // Install the ephemeral app and write data to various storage.
441 const Extension* app = InstallPlatformApp(kRetainDataApp);
442 ASSERT_TRUE(app);
443 ASSERT_TRUE(LaunchAppAndRunTest(app, "WriteData")) << message_;
445 // Remove the app.
446 const std::string app_id = app->id();
447 EvictApp(app->id());
448 app = NULL;
450 // The app should not be in the preferences.
451 ExtensionPrefs* prefs = ExtensionPrefs::Get(browser()->profile());
452 ASSERT_TRUE(prefs);
453 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
454 prefs->GetEvictedEphemeralAppsInfo());
455 EXPECT_FALSE(IsAppInExtensionsInfo(*extensions_info, app_id));
456 extensions_info = prefs->GetInstalledExtensionsInfo();
457 EXPECT_FALSE(IsAppInExtensionsInfo(*extensions_info, app_id));
459 // Reinstall the app and verify that all data has been reset.
460 app = InstallPlatformApp(kRetainDataApp);
461 ASSERT_TRUE(LaunchAppAndRunTest(app, "DataReset")) << message_;
464 // Verify that once evicted from the cache, ephemeral apps will remain in
465 // extension prefs, but marked as evicted. After garbage collection of data,
466 // both their data and preferences should be removed.
467 IN_PROC_BROWSER_TEST_F(EphemeralAppBrowserTest, GarbageCollectData) {
468 // Create two apps. Both will be evicted from the cache, but the data of
469 // one will be garbage collected.
470 const Extension* evict_app = InstallEphemeralApp(kRetainDataApp);
471 ASSERT_TRUE(evict_app);
472 ASSERT_TRUE(LaunchAppAndRunTest(evict_app, "WriteData")) << message_;
473 std::string evict_app_id = evict_app->id();
474 EvictApp(evict_app_id);
475 evict_app = NULL;
477 const Extension* retain_app = InstallEphemeralApp(kDispatchEventTestApp);
478 ASSERT_TRUE(retain_app);
479 std::string retain_app_id = retain_app->id();
480 EvictApp(retain_app_id);
481 retain_app = NULL;
483 ExtensionPrefs* prefs = ExtensionPrefs::Get(browser()->profile());
484 ASSERT_TRUE(prefs);
486 // Both apps should be in the list of evicted apps.
487 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
488 prefs->GetEvictedEphemeralAppsInfo());
489 EXPECT_TRUE(IsAppInExtensionsInfo(*extensions_info, retain_app_id));
490 EXPECT_TRUE(IsAppInExtensionsInfo(*extensions_info, evict_app_id));
492 // Set a fake last launch time so that the ephemeral app's data will be
493 // garbage collected.
494 base::Time launch_time =
495 base::Time::Now() - base::TimeDelta::FromDays(
496 EphemeralAppService::kDataInactiveThreshold + 1);
497 prefs->SetLastLaunchTime(evict_app_id, launch_time);
498 prefs->SetLastLaunchTime(retain_app_id, base::Time::Now());
500 // Garbage collect data.
501 GarbageCollectData();
503 // The garbage collected app should no longer be in the preferences.
504 extensions_info = prefs->GetEvictedEphemeralAppsInfo();
505 EXPECT_TRUE(IsAppInExtensionsInfo(*extensions_info, retain_app_id));
506 ASSERT_FALSE(IsAppInExtensionsInfo(*extensions_info, evict_app_id));
508 // Reinstall the app and verify that all data has been reset.
509 evict_app = InstallEphemeralApp(kRetainDataApp);
510 ASSERT_TRUE(LaunchAppAndRunTest(evict_app, "DataReset")) << message_;