OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdint.h> | 5 #include <stdint.h> |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/files/file_util.h" | 8 #include "base/files/file_util.h" |
9 #include "base/files/scoped_temp_dir.h" | 9 #include "base/files/scoped_temp_dir.h" |
10 #include "base/run_loop.h" | 10 #include "base/run_loop.h" |
11 #include "base/strings/utf_string_conversions.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "base/test/simple_test_clock.h" |
12 #include "base/threading/thread_task_runner_handle.h" | 13 #include "base/threading/thread_task_runner_handle.h" |
13 #include "content/browser/notifications/platform_notification_context_impl.h" | 14 #include "content/browser/notifications/platform_notification_context_impl.h" |
14 #include "content/browser/service_worker/embedded_worker_test_helper.h" | 15 #include "content/browser/service_worker/embedded_worker_test_helper.h" |
15 #include "content/browser/service_worker/service_worker_context_wrapper.h" | 16 #include "content/browser/service_worker/service_worker_context_wrapper.h" |
16 #include "content/common/service_worker/service_worker_types.h" | 17 #include "content/common/service_worker/service_worker_types.h" |
17 #include "content/public/browser/notification_database_data.h" | 18 #include "content/public/browser/notification_database_data.h" |
18 #include "content/public/common/notification_resources.h" | 19 #include "content/public/common/notification_resources.h" |
19 #include "content/public/test/test_browser_context.h" | 20 #include "content/public/test/test_browser_context.h" |
20 #include "content/public/test/test_browser_thread_bundle.h" | 21 #include "content/public/test/test_browser_thread_bundle.h" |
21 #include "content/test/mock_platform_notification_service.h" | 22 #include "content/test/mock_platform_notification_service.h" |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 // Callback to provide when unregistering a Service Worker. Will write the | 79 // Callback to provide when unregistering a Service Worker. Will write the |
79 // resulting status code to |store_status|. | 80 // resulting status code to |store_status|. |
80 void DidUnregisterServiceWorker(ServiceWorkerStatusCode* store_status, | 81 void DidUnregisterServiceWorker(ServiceWorkerStatusCode* store_status, |
81 ServiceWorkerStatusCode status) { | 82 ServiceWorkerStatusCode status) { |
82 DCHECK(store_status); | 83 DCHECK(store_status); |
83 *store_status = status; | 84 *store_status = status; |
84 } | 85 } |
85 | 86 |
86 // Callback to provide when reading multiple notifications from the database. | 87 // Callback to provide when reading multiple notifications from the database. |
87 // Will store the success value in the class member, and write the read | 88 // Will store the success value in the class member, and write the read |
88 // notification datas to |store_notification_datas|. | 89 // notification datas to |*out_notification_datas|. |
89 void DidReadAllNotificationDatas( | 90 void DidReadAllNotificationDatas( |
90 std::vector<NotificationDatabaseData>* store_notification_datas, | 91 std::vector<NotificationDatabaseData>* out_notification_datas, |
91 bool success, | 92 bool success, |
92 const std::vector<NotificationDatabaseData>& notification_datas) { | 93 const std::vector<NotificationDatabaseData>& notification_datas) { |
93 DCHECK(store_notification_datas); | 94 DCHECK(out_notification_datas); |
94 | 95 |
95 success_ = success; | 96 success_ = success; |
96 *store_notification_datas = notification_datas; | 97 *out_notification_datas = notification_datas; |
| 98 } |
| 99 |
| 100 // Callback to provide when calling GetDisplayedNotifications on the |
| 101 // PlatformNotificationService. |
| 102 void DidGetDisplayedNotifications( |
| 103 std::unique_ptr<std::set<std::string>>* out_notifications, |
| 104 bool* out_supports_synchronization, |
| 105 std::unique_ptr<std::set<std::string>> notifications, |
| 106 bool supports_synchronization) { |
| 107 DCHECK(out_notifications); |
| 108 DCHECK(out_supports_synchronization); |
| 109 |
| 110 *out_notifications = std::move(notifications); |
| 111 *out_supports_synchronization = supports_synchronization; |
97 } | 112 } |
98 | 113 |
99 protected: | 114 protected: |
100 // Creates a new PlatformNotificationContextImpl instance. When using this | 115 // Creates a new PlatformNotificationContextImpl instance. When using this |
101 // method, the underlying database will always be created in memory. | 116 // method, the underlying database will always be created in memory. |
102 PlatformNotificationContextImpl* CreatePlatformNotificationContext() { | 117 PlatformNotificationContextImpl* CreatePlatformNotificationContext() { |
103 PlatformNotificationContextImpl* context = | 118 PlatformNotificationContextImpl* context = |
104 new PlatformNotificationContextImpl(base::FilePath(), &browser_context_, | 119 new PlatformNotificationContextImpl(base::FilePath(), &browser_context_, |
105 nullptr); | 120 nullptr); |
106 context->Initialize(); | 121 context->Initialize(); |
107 | 122 |
108 OverrideTaskRunnerForTesting(context); | 123 OverrideTaskRunnerForTesting(context); |
109 return context; | 124 return context; |
110 } | 125 } |
111 | 126 |
| 127 // Creates and returns a fake clock for the |context| that can be used to |
| 128 // advance the time. Used by tests that care about the deletion grace period. |
| 129 base::SimpleTestClock* CreateFakeClock( |
| 130 PlatformNotificationContextImpl* context) { |
| 131 base::SimpleTestClock* clock = new base::SimpleTestClock(); |
| 132 context->clock_ = base::WrapUnique(clock); |
| 133 return clock; |
| 134 } |
| 135 |
112 // Overrides the task runner in |context| with the current message loop | 136 // Overrides the task runner in |context| with the current message loop |
113 // proxy, to reduce the number of threads involved in the tests. | 137 // proxy, to reduce the number of threads involved in the tests. |
114 void OverrideTaskRunnerForTesting(PlatformNotificationContextImpl* context) { | 138 void OverrideTaskRunnerForTesting(PlatformNotificationContextImpl* context) { |
115 context->SetTaskRunnerForTesting(base::ThreadTaskRunnerHandle::Get()); | 139 context->SetTaskRunnerForTesting(base::ThreadTaskRunnerHandle::Get()); |
116 } | 140 } |
117 | 141 |
118 // Returns the testing browsing context that can be used for this test. | 142 // Returns the testing browsing context that can be used for this test. |
119 BrowserContext* browser_context() { return &browser_context_; } | 143 BrowserContext* browser_context() { return &browser_context_; } |
120 | 144 |
121 // Returns whether the last invoked callback finished successfully. | 145 // Returns whether the last invoked callback finished successfully. |
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
500 } | 524 } |
501 } | 525 } |
502 | 526 |
503 TEST_F(PlatformNotificationContextTest, SynchronizeNotifications) { | 527 TEST_F(PlatformNotificationContextTest, SynchronizeNotifications) { |
504 NotificationBrowserClient notification_browser_client; | 528 NotificationBrowserClient notification_browser_client; |
505 SetBrowserClientForTesting(¬ification_browser_client); | 529 SetBrowserClientForTesting(¬ification_browser_client); |
506 | 530 |
507 scoped_refptr<PlatformNotificationContextImpl> context = | 531 scoped_refptr<PlatformNotificationContextImpl> context = |
508 CreatePlatformNotificationContext(); | 532 CreatePlatformNotificationContext(); |
509 | 533 |
| 534 base::SimpleTestClock* clock = CreateFakeClock(context.get()); |
| 535 |
510 GURL origin("https://example.com"); | 536 GURL origin("https://example.com"); |
511 NotificationDatabaseData notification_database_data; | 537 NotificationDatabaseData notification_database_data; |
512 notification_database_data.service_worker_registration_id = | 538 notification_database_data.service_worker_registration_id = |
513 kFakeServiceWorkerRegistrationId; | 539 kFakeServiceWorkerRegistrationId; |
514 PlatformNotificationData notification_data; | 540 PlatformNotificationData notification_data; |
515 content::NotificationResources notification_resources; | 541 content::NotificationResources notification_resources; |
516 | 542 |
517 context->WriteNotificationData( | 543 context->WriteNotificationData( |
518 origin, notification_database_data, | 544 origin, notification_database_data, |
519 base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData, | 545 base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData, |
520 base::Unretained(this))); | 546 base::Unretained(this))); |
521 | 547 |
522 base::RunLoop().RunUntilIdle(); | 548 base::RunLoop().RunUntilIdle(); |
523 ASSERT_TRUE(success()); | 549 ASSERT_TRUE(success()); |
524 EXPECT_FALSE(notification_id().empty()); | 550 EXPECT_FALSE(notification_id().empty()); |
525 | 551 |
| 552 // Forward the time by a minute to ensure that we're past the grace period for |
| 553 // newly shown notifications, making sure that the list of displayed |
| 554 // notifications retrieved from the PlatformNotificationService will be used. |
| 555 clock->Advance(base::TimeDelta::FromMinutes(1)); |
| 556 |
526 PlatformNotificationService* service = | 557 PlatformNotificationService* service = |
527 notification_browser_client.GetPlatformNotificationService(); | 558 notification_browser_client.GetPlatformNotificationService(); |
528 | 559 |
529 service->DisplayPersistentNotification(browser_context(), notification_id(), | 560 service->DisplayPersistentNotification(browser_context(), notification_id(), |
530 origin, origin, notification_data, | 561 origin, origin, notification_data, |
531 notification_resources); | 562 notification_resources); |
532 | 563 |
533 std::vector<NotificationDatabaseData> notification_database_datas; | 564 std::vector<NotificationDatabaseData> notification_database_datas; |
534 context->ReadAllNotificationDataForServiceWorkerRegistration( | 565 context->ReadAllNotificationDataForServiceWorkerRegistration( |
535 origin, kFakeServiceWorkerRegistrationId, | 566 origin, kFakeServiceWorkerRegistrationId, |
(...skipping 22 matching lines...) Expand all Loading... |
558 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData, | 589 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData, |
559 base::Unretained(this))); | 590 base::Unretained(this))); |
560 | 591 |
561 base::RunLoop().RunUntilIdle(); | 592 base::RunLoop().RunUntilIdle(); |
562 | 593 |
563 // The notification was removed, so we shouldn't be able to read it from | 594 // The notification was removed, so we shouldn't be able to read it from |
564 // the database anymore. | 595 // the database anymore. |
565 EXPECT_FALSE(success()); | 596 EXPECT_FALSE(success()); |
566 } | 597 } |
567 | 598 |
| 599 TEST_F(PlatformNotificationContextTest, SynchronizeNotificationsDisplayRace) { |
| 600 // This test verifies that a possible race condition where a developer shows |
| 601 // a notification, and then gets all shown notifications before waiting for |
| 602 // acknowledgement (which, in itself, is too optimistic), is made less severe |
| 603 // by remembering the most recently shown notification for a brief period of |
| 604 // time. |
| 605 |
| 606 NotificationBrowserClient notification_browser_client; |
| 607 SetBrowserClientForTesting(¬ification_browser_client); |
| 608 |
| 609 scoped_refptr<PlatformNotificationContextImpl> context = |
| 610 CreatePlatformNotificationContext(); |
| 611 |
| 612 base::SimpleTestClock* clock = CreateFakeClock(context.get()); |
| 613 |
| 614 GURL origin("https://example.com"); |
| 615 NotificationDatabaseData notification_database_data; |
| 616 notification_database_data.service_worker_registration_id = |
| 617 kFakeServiceWorkerRegistrationId; |
| 618 PlatformNotificationData notification_data; |
| 619 content::NotificationResources notification_resources; |
| 620 |
| 621 context->WriteNotificationData( |
| 622 origin, notification_database_data, |
| 623 base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData, |
| 624 base::Unretained(this))); |
| 625 |
| 626 base::RunLoop().RunUntilIdle(); |
| 627 ASSERT_TRUE(success()); |
| 628 EXPECT_FALSE(notification_id().empty()); |
| 629 |
| 630 // The |notification_data| deliberately has not been dispatched to the |
| 631 // PlatformNotificationService yet. This will cause the mock to return that |
| 632 // no notifications have been displayed, simulating the race condition. |
| 633 |
| 634 std::unique_ptr<std::set<std::string>> notifications; |
| 635 bool supports_synchronization = false; |
| 636 |
| 637 PlatformNotificationService* service = |
| 638 notification_browser_client.GetPlatformNotificationService(); |
| 639 service->GetDisplayedNotifications( |
| 640 browser_context(), |
| 641 base::Bind(&PlatformNotificationContextTest::DidGetDisplayedNotifications, |
| 642 base::Unretained(this), ¬ifications, |
| 643 &supports_synchronization)); |
| 644 |
| 645 base::RunLoop().RunUntilIdle(); |
| 646 ASSERT_TRUE(supports_synchronization); |
| 647 ASSERT_EQ(notifications->size(), 0u); |
| 648 |
| 649 // Reading all notifications should still return the one notification that was |
| 650 // displayed, since it was the most recent one. |
| 651 |
| 652 std::vector<NotificationDatabaseData> notification_database_datas; |
| 653 context->ReadAllNotificationDataForServiceWorkerRegistration( |
| 654 origin, kFakeServiceWorkerRegistrationId, |
| 655 base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas, |
| 656 base::Unretained(this), ¬ification_database_datas)); |
| 657 |
| 658 base::RunLoop().RunUntilIdle(); |
| 659 |
| 660 ASSERT_TRUE(success()); |
| 661 ASSERT_EQ(1u, notification_database_datas.size()); |
| 662 |
| 663 // Now forward the time by a minute, which means that the grace period should |
| 664 // have exceeded. Getting the notifications again should ignore it now. |
| 665 clock->Advance(base::TimeDelta::FromMinutes(1)); |
| 666 |
| 667 context->ReadAllNotificationDataForServiceWorkerRegistration( |
| 668 origin, kFakeServiceWorkerRegistrationId, |
| 669 base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas, |
| 670 base::Unretained(this), ¬ification_database_datas)); |
| 671 |
| 672 base::RunLoop().RunUntilIdle(); |
| 673 |
| 674 ASSERT_TRUE(success()); |
| 675 ASSERT_EQ(0u, notification_database_datas.size()); |
| 676 } |
| 677 |
568 } // namespace content | 678 } // namespace content |
OLD | NEW |