Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / notifications / platform_notification_context_unittest.cc
blob4560f7d5c1879f95888f52b74aea492cc8ca6a94
1 // Copyright 2015 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 "base/bind.h"
6 #include "base/files/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/run_loop.h"
9 #include "base/thread_task_runner_handle.h"
10 #include "content/browser/notifications/platform_notification_context_impl.h"
11 #include "content/browser/service_worker/embedded_worker_test_helper.h"
12 #include "content/browser/service_worker/service_worker_context_wrapper.h"
13 #include "content/common/service_worker/service_worker_types.h"
14 #include "content/public/browser/notification_database_data.h"
15 #include "content/public/test/test_browser_context.h"
16 #include "content/public/test/test_browser_thread_bundle.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "url/gurl.h"
20 namespace content {
22 // Fake render process id to use in tests requiring one.
23 const int kFakeRenderProcessId = 99;
25 // Fake Service Worker registration id to use in tests requiring one.
26 const int64_t kFakeServiceWorkerRegistrationId = 42;
28 class PlatformNotificationContextTest : public ::testing::Test {
29 public:
30 PlatformNotificationContextTest()
31 : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP),
32 success_(false) {}
34 // Callback to provide when reading a single notification from the database.
35 void DidReadNotificationData(
36 bool success, const NotificationDatabaseData& database_data) {
37 success_ = success;
38 database_data_ = database_data;
41 // Callback to provide when writing a notification to the database.
42 void DidWriteNotificationData(bool success, int64_t notification_id) {
43 success_ = success;
44 notification_id_ = notification_id;
47 // Callback to provide when deleting notification data from the database.
48 void DidDeleteNotificationData(bool success) {
49 success_ = success;
52 // Callback to provide when registering a Service Worker with a Service
53 // Worker Context. Will write the registration id to |store_registration_id|.
54 void DidRegisterServiceWorker(int64_t* store_registration_id,
55 ServiceWorkerStatusCode status,
56 const std::string& status_message,
57 int64_t service_worker_registration_id) {
58 DCHECK(store_registration_id);
59 EXPECT_EQ(SERVICE_WORKER_OK, status);
61 *store_registration_id = service_worker_registration_id;
64 // Callback to provide when unregistering a Service Worker. Will write the
65 // resulting status code to |store_status|.
66 void DidUnregisterServiceWorker(ServiceWorkerStatusCode* store_status,
67 ServiceWorkerStatusCode status) {
68 DCHECK(store_status);
69 *store_status = status;
72 // Callback to provide when reading multiple notifications from the database.
73 // Will store the success value in the class member, and write the read
74 // notification datas to |store_notification_datas|.
75 void DidReadAllNotificationDatas(
76 std::vector<NotificationDatabaseData>* store_notification_datas,
77 bool success,
78 const std::vector<NotificationDatabaseData>& notification_datas) {
79 DCHECK(store_notification_datas);
81 success_ = success;
82 *store_notification_datas = notification_datas;
85 protected:
86 // Creates a new PlatformNotificationContextImpl instance. When using this
87 // method, the underlying database will always be created in memory. The
88 // current message loop proxy will be used as the task runner.
89 PlatformNotificationContextImpl* CreatePlatformNotificationContext() {
90 PlatformNotificationContextImpl* context =
91 new PlatformNotificationContextImpl(base::FilePath(),
92 &browser_context_,
93 nullptr);
94 context->Initialize();
96 OverrideTaskRunnerForTesting(context);
97 return context;
100 // Overrides the task runner in |context| with the current message loop
101 // proxy, to reduce the number of threads involved in the tests.
102 void OverrideTaskRunnerForTesting(PlatformNotificationContextImpl* context) {
103 context->SetTaskRunnerForTesting(base::ThreadTaskRunnerHandle::Get());
106 // Returns the testing browsing context that can be used for this test.
107 BrowserContext* browser_context() { return &browser_context_; }
109 // Returns whether the last invoked callback finished successfully.
110 bool success() const { return success_; }
112 // Returns the NotificationDatabaseData associated with the last invoked
113 // ReadNotificationData callback.
114 const NotificationDatabaseData& database_data() const {
115 return database_data_;
118 // Returns the notification id of the notification last written.
119 int64_t notification_id() const { return notification_id_; }
121 private:
122 TestBrowserThreadBundle thread_bundle_;
123 TestBrowserContext browser_context_;
125 bool success_;
126 NotificationDatabaseData database_data_;
127 int64_t notification_id_;
130 TEST_F(PlatformNotificationContextTest, ReadNonExistentNotification) {
131 scoped_refptr<PlatformNotificationContextImpl> context =
132 CreatePlatformNotificationContext();
134 context->ReadNotificationData(
135 42 /* notification_id */,
136 GURL("https://example.com"),
137 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
138 base::Unretained(this)));
140 base::RunLoop().RunUntilIdle();
142 // The read operation should have failed, as it does not exist.
143 ASSERT_FALSE(success());
146 TEST_F(PlatformNotificationContextTest, WriteReadNotification) {
147 scoped_refptr<PlatformNotificationContextImpl> context =
148 CreatePlatformNotificationContext();
150 GURL origin("https://example.com");
151 NotificationDatabaseData notification_database_data;
152 notification_database_data.origin = origin;
154 context->WriteNotificationData(
155 origin,
156 notification_database_data,
157 base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
158 base::Unretained(this)));
160 base::RunLoop().RunUntilIdle();
162 // The write operation should have succeeded with a notification id.
163 ASSERT_TRUE(success());
164 EXPECT_GT(notification_id(), 0);
166 context->ReadNotificationData(
167 notification_id(),
168 origin,
169 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
170 base::Unretained(this)));
172 base::RunLoop().RunUntilIdle();
174 // The read operation should have succeeded, with the right notification.
175 ASSERT_TRUE(success());
177 const NotificationDatabaseData& read_database_data = database_data();
178 EXPECT_EQ(notification_database_data.origin, read_database_data.origin);
181 TEST_F(PlatformNotificationContextTest, DeleteInvalidNotification) {
182 scoped_refptr<PlatformNotificationContextImpl> context =
183 CreatePlatformNotificationContext();
185 context->DeleteNotificationData(
186 42 /* notification_id */,
187 GURL("https://example.com"),
188 base::Bind(&PlatformNotificationContextTest::DidDeleteNotificationData,
189 base::Unretained(this)));
191 base::RunLoop().RunUntilIdle();
193 // The notification may not have existed, but since the goal of deleting data
194 // is to make sure that it's gone, the goal has been satisfied. As such,
195 // deleting a non-existent notification is considered to be a success.
196 EXPECT_TRUE(success());
199 TEST_F(PlatformNotificationContextTest, DeleteNotification) {
200 scoped_refptr<PlatformNotificationContextImpl> context =
201 CreatePlatformNotificationContext();
203 GURL origin("https://example.com");
204 NotificationDatabaseData notification_database_data;
206 context->WriteNotificationData(
207 origin,
208 notification_database_data,
209 base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
210 base::Unretained(this)));
212 base::RunLoop().RunUntilIdle();
214 // The write operation should have succeeded with a notification id.
215 ASSERT_TRUE(success());
216 EXPECT_GT(notification_id(), 0);
218 context->DeleteNotificationData(
219 notification_id(),
220 origin,
221 base::Bind(&PlatformNotificationContextTest::DidDeleteNotificationData,
222 base::Unretained(this)));
224 base::RunLoop().RunUntilIdle();
226 // The notification existed, so it should have been removed successfully.
227 ASSERT_TRUE(success());
229 context->ReadNotificationData(
230 notification_id(),
231 origin,
232 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
233 base::Unretained(this)));
235 base::RunLoop().RunUntilIdle();
237 // The notification was removed, so we shouldn't be able to read it from
238 // the database anymore.
239 EXPECT_FALSE(success());
242 TEST_F(PlatformNotificationContextTest, ServiceWorkerUnregistered) {
243 scoped_ptr<EmbeddedWorkerTestHelper> embedded_worker_test_helper(
244 new EmbeddedWorkerTestHelper(base::FilePath(), kFakeRenderProcessId));
246 // Manually create the PlatformNotificationContextImpl so that the Service
247 // Worker context wrapper can be passed in.
248 scoped_refptr<PlatformNotificationContextImpl> notification_context(
249 new PlatformNotificationContextImpl(
250 base::FilePath(),
251 browser_context(),
252 embedded_worker_test_helper->context_wrapper()));
253 notification_context->Initialize();
255 OverrideTaskRunnerForTesting(notification_context.get());
257 GURL origin("https://example.com");
258 GURL script_url("https://example.com/worker.js");
260 int64_t service_worker_registration_id = kInvalidServiceWorkerRegistrationId;
262 // Register a Service Worker to get a valid registration id.
263 embedded_worker_test_helper->context()->RegisterServiceWorker(
264 origin,
265 script_url,
266 nullptr /* provider_host */,
267 base::Bind(&PlatformNotificationContextTest::DidRegisterServiceWorker,
268 base::Unretained(this), &service_worker_registration_id));
270 base::RunLoop().RunUntilIdle();
271 ASSERT_NE(service_worker_registration_id,
272 kInvalidServiceWorkerRegistrationId);
274 NotificationDatabaseData notification_database_data;
276 // Create a notification for that Service Worker registration.
277 notification_context->WriteNotificationData(
278 origin,
279 notification_database_data,
280 base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
281 base::Unretained(this)));
283 base::RunLoop().RunUntilIdle();
285 ASSERT_TRUE(success());
286 EXPECT_GT(notification_id(), 0);
288 ServiceWorkerStatusCode unregister_status;
290 // Now drop the Service Worker registration which owns that notification.
291 embedded_worker_test_helper->context()->UnregisterServiceWorker(
292 origin,
293 base::Bind(&PlatformNotificationContextTest::DidUnregisterServiceWorker,
294 base::Unretained(this), &unregister_status));
296 base::RunLoop().RunUntilIdle();
297 ASSERT_EQ(SERVICE_WORKER_OK, unregister_status);
299 // And verify that the associated notification has indeed been dropped.
300 notification_context->ReadNotificationData(
301 notification_id(),
302 origin,
303 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
304 base::Unretained(this)));
306 base::RunLoop().RunUntilIdle();
308 EXPECT_FALSE(success());
311 TEST_F(PlatformNotificationContextTest, DestroyDatabaseOnStorageWiped) {
312 scoped_refptr<PlatformNotificationContextImpl> context =
313 CreatePlatformNotificationContext();
315 GURL origin("https://example.com");
316 NotificationDatabaseData notification_database_data;
318 context->WriteNotificationData(
319 origin,
320 notification_database_data,
321 base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
322 base::Unretained(this)));
324 base::RunLoop().RunUntilIdle();
326 // The write operation should have succeeded with a notification id.
327 ASSERT_TRUE(success());
328 EXPECT_GT(notification_id(), 0);
330 // Call the OnStorageWiped override from the ServiceWorkerContextObserver,
331 // which indicates that the database should go away entirely.
332 context->OnStorageWiped();
334 // Verify that reading notification data fails because the data does not
335 // exist anymore. Deliberately omit RunUntilIdle(), since this is unlikely to
336 // be the case when OnStorageWiped gets called in production.
337 context->ReadNotificationData(
338 notification_id(),
339 origin,
340 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
341 base::Unretained(this)));
343 base::RunLoop().RunUntilIdle();
345 EXPECT_FALSE(success());
348 TEST_F(PlatformNotificationContextTest, DestroyOnDiskDatabase) {
349 base::ScopedTempDir database_dir;
350 ASSERT_TRUE(database_dir.CreateUniqueTempDir());
352 // Manually construct the PlatformNotificationContextImpl because this test
353 // requires the database to be created on the filesystem.
354 scoped_refptr<PlatformNotificationContextImpl> context(
355 new PlatformNotificationContextImpl(database_dir.path(),
356 browser_context(),
357 nullptr));
359 OverrideTaskRunnerForTesting(context.get());
361 // Trigger a read-operation to force creating the database.
362 context->ReadNotificationData(
363 42 /* notification_id */,
364 GURL("https://example.com"),
365 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
366 base::Unretained(this)));
368 base::RunLoop().RunUntilIdle();
370 EXPECT_FALSE(IsDirectoryEmpty(database_dir.path()));
371 EXPECT_FALSE(success());
373 // Blow away the database by faking a Service Worker Context wipe-out.
374 context->OnStorageWiped();
376 base::RunLoop().RunUntilIdle();
378 // The database's directory should be empty at this point.
379 EXPECT_TRUE(IsDirectoryEmpty(database_dir.path()));
382 TEST_F(PlatformNotificationContextTest, ReadAllServiceWorkerDataEmpty) {
383 scoped_refptr<PlatformNotificationContextImpl> context =
384 CreatePlatformNotificationContext();
386 GURL origin("https://example.com");
388 std::vector<NotificationDatabaseData> notification_database_datas;
389 context->ReadAllNotificationDataForServiceWorkerRegistration(
390 origin,
391 kFakeServiceWorkerRegistrationId,
392 base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas,
393 base::Unretained(this),
394 &notification_database_datas));
396 base::RunLoop().RunUntilIdle();
398 EXPECT_TRUE(success());
399 EXPECT_EQ(0u, notification_database_datas.size());
402 TEST_F(PlatformNotificationContextTest, ReadAllServiceWorkerDataFilled) {
403 scoped_refptr<PlatformNotificationContextImpl> context =
404 CreatePlatformNotificationContext();
406 GURL origin("https://example.com");
408 NotificationDatabaseData notification_database_data;
409 notification_database_data.origin = origin;
410 notification_database_data.service_worker_registration_id =
411 kFakeServiceWorkerRegistrationId;
413 // Insert ten notifications into the database belonging to origin and the
414 // test Service Worker Registration id.
415 for (int i = 0; i < 10; ++i) {
416 context->WriteNotificationData(
417 origin,
418 notification_database_data,
419 base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
420 base::Unretained(this)));
422 base::RunLoop().RunUntilIdle();
424 ASSERT_TRUE(success());
427 // Now read the notifications from the database again. There should be ten,
428 // all set with the correct origin and Service Worker Registration id.
429 std::vector<NotificationDatabaseData> notification_database_datas;
430 context->ReadAllNotificationDataForServiceWorkerRegistration(
431 origin,
432 kFakeServiceWorkerRegistrationId,
433 base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas,
434 base::Unretained(this),
435 &notification_database_datas));
437 base::RunLoop().RunUntilIdle();
439 ASSERT_TRUE(success());
440 ASSERT_EQ(10u, notification_database_datas.size());
442 for (int i = 0; i < 10; ++i) {
443 EXPECT_EQ(origin, notification_database_datas[i].origin);
444 EXPECT_EQ(kFakeServiceWorkerRegistrationId,
445 notification_database_datas[i].service_worker_registration_id);
449 } // namespace content