Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(754)

Side by Side Diff: content/browser/notifications/platform_notification_context_unittest.cc

Issue 2878443002: Address a race condition in displaying notifications
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/browser/notifications/platform_notification_context_impl.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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();
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 // Delete the notification from the display service without removing it from 559 // Delete the notification from the display service without removing it from
545 // the database. It should automatically synchronize on the next read. 560 // the database. It should automatically synchronize on the next read.
546 service->ClosePersistentNotification(browser_context(), notification_id()); 561 service->ClosePersistentNotification(browser_context(), notification_id());
547 context->ReadAllNotificationDataForServiceWorkerRegistration( 562 context->ReadAllNotificationDataForServiceWorkerRegistration(
548 origin, kFakeServiceWorkerRegistrationId, 563 origin, kFakeServiceWorkerRegistrationId,
549 base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas, 564 base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas,
550 base::Unretained(this), &notification_database_datas)); 565 base::Unretained(this), &notification_database_datas));
551 base::RunLoop().RunUntilIdle(); 566 base::RunLoop().RunUntilIdle();
552 567
553 ASSERT_TRUE(success()); 568 ASSERT_TRUE(success());
554 ASSERT_EQ(0u, notification_database_datas.size()); 569 ASSERT_EQ(0u, notification_database_datas.size());
awdf 2017/05/10 17:01:57 This line is now failing - see https://00e9e64baca
Peter Beverloo 2017/05/10 17:09:22 Done.
555 570
556 context->ReadNotificationData( 571 context->ReadNotificationData(
557 notification_id(), origin, 572 notification_id(), origin,
558 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData, 573 base::Bind(&PlatformNotificationContextTest::DidReadNotificationData,
559 base::Unretained(this))); 574 base::Unretained(this)));
560 575
561 base::RunLoop().RunUntilIdle(); 576 base::RunLoop().RunUntilIdle();
562 577
563 // The notification was removed, so we shouldn't be able to read it from 578 // The notification was removed, so we shouldn't be able to read it from
564 // the database anymore. 579 // the database anymore.
565 EXPECT_FALSE(success()); 580 EXPECT_FALSE(success());
566 } 581 }
567 582
583 TEST_F(PlatformNotificationContextTest, SynchronizeNotificationsDisplayRace) {
584 // This test verifies that a possible race condition where a developer shows
585 // a notification, and then gets all shown notifications before waiting for
586 // acknowledgement (which, in itself, is too optimistic), is made less severe
587 // by remembering the most recently shown notification for a brief period of
588 // time.
589
590 NotificationBrowserClient notification_browser_client;
591 SetBrowserClientForTesting(&notification_browser_client);
592
593 scoped_refptr<PlatformNotificationContextImpl> context =
594 CreatePlatformNotificationContext();
595
596 base::SimpleTestClock* clock = new base::SimpleTestClock();
597 context->clock_ = base::WrapUnique(clock);
598
599 GURL origin("https://example.com");
600 NotificationDatabaseData notification_database_data;
601 notification_database_data.service_worker_registration_id =
602 kFakeServiceWorkerRegistrationId;
603 PlatformNotificationData notification_data;
604 content::NotificationResources notification_resources;
605
606 context->WriteNotificationData(
607 origin, notification_database_data,
608 base::Bind(&PlatformNotificationContextTest::DidWriteNotificationData,
609 base::Unretained(this)));
610
611 base::RunLoop().RunUntilIdle();
612 ASSERT_TRUE(success());
613 EXPECT_FALSE(notification_id().empty());
614
615 // The |notification_data| deliberately has not been dispatched to the
616 // PlatformNotificationService yet. This will cause the mock to return that
617 // no notifications have been displayed, simulating the race condition.
618
619 std::unique_ptr<std::set<std::string>> notifications;
620 bool supports_synchronization = false;
621
622 PlatformNotificationService* service =
623 notification_browser_client.GetPlatformNotificationService();
624 service->GetDisplayedNotifications(
625 browser_context(),
626 base::Bind(&PlatformNotificationContextTest::DidGetDisplayedNotifications,
627 base::Unretained(this), &notifications,
628 &supports_synchronization));
629
630 base::RunLoop().RunUntilIdle();
631 ASSERT_TRUE(supports_synchronization);
632 ASSERT_EQ(notifications->size(), 0u);
633
634 // Reading all notifications should still return the one notification that was
635 // displayed, since it was the most recent one.
636
637 std::vector<NotificationDatabaseData> notification_database_datas;
638 context->ReadAllNotificationDataForServiceWorkerRegistration(
639 origin, kFakeServiceWorkerRegistrationId,
640 base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas,
641 base::Unretained(this), &notification_database_datas));
642
643 base::RunLoop().RunUntilIdle();
644
645 ASSERT_TRUE(success());
646 ASSERT_EQ(1u, notification_database_datas.size());
647
648 // Now forward the time by a minute, which means that the grace period should
649 // have exceeded. Getting the notifications again should ignore it now.
650 clock->Advance(base::TimeDelta::FromMinutes(1));
651
652 context->ReadAllNotificationDataForServiceWorkerRegistration(
653 origin, kFakeServiceWorkerRegistrationId,
654 base::Bind(&PlatformNotificationContextTest::DidReadAllNotificationDatas,
655 base::Unretained(this), &notification_database_datas));
656
657 base::RunLoop().RunUntilIdle();
658
659 ASSERT_TRUE(success());
660 ASSERT_EQ(0u, notification_database_datas.size());
661 }
662
568 } // namespace content 663 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/notifications/platform_notification_context_impl.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698