@@ -576,7 +576,7 @@ func TestNotifierPaused(t *testing.T) {
576
576
ctx := dbauthz .AsSystemRestricted (testutil .Context (t , testutil .WaitSuperLong ))
577
577
_ , _ , api := coderdtest .NewWithAPI (t , nil )
578
578
579
- // Prepare the test
579
+ // Prepare the test.
580
580
handler := & fakeHandler {}
581
581
method := database .NotificationMethodSmtp
582
582
user := createSampleUser (t , api .Database )
@@ -593,32 +593,39 @@ func TestNotifierPaused(t *testing.T) {
593
593
enq , err := notifications .NewStoreEnqueuer (cfg , api .Database , defaultHelpers (), api .Logger .Named ("enqueuer" ), quartz .NewReal ())
594
594
require .NoError (t , err )
595
595
596
- mgr .Run (ctx )
597
-
598
596
// Pause the notifier.
599
597
settingsJSON , err := json .Marshal (& codersdk.NotificationsSettings {NotifierPaused : true })
600
598
require .NoError (t , err )
601
599
err = api .Database .UpsertNotificationsSettings (ctx , string (settingsJSON ))
602
600
require .NoError (t , err )
603
601
602
+ // Start the manager so that notifications are processed, except it will be paused at this point.
603
+ // If it is started before pausing, there's a TOCTOU possibility between checking whether the notifier is paused or
604
+ // not, and processing the messages (see notifier.run).
605
+ mgr .Run (ctx )
606
+
604
607
// Notifier is paused, enqueue the next message.
605
608
sid , err := enq .Enqueue (ctx , user .ID , notifications .TemplateWorkspaceDeleted , map [string ]string {"type" : "success" , "i" : "1" }, "test" )
606
609
require .NoError (t , err )
607
610
608
- // Sleep for a few fetch intervals to be sure we aren't getting false-positives in the next step.
609
- // TODO: use quartz instead.
610
- time .Sleep (fetchInterval * 5 )
611
-
612
611
// Ensure we have a pending message and it's the expected one.
612
+ pendingMessages , err := api .Database .GetNotificationMessagesByStatus (ctx , database.GetNotificationMessagesByStatusParams {
613
+ Status : database .NotificationMessageStatusPending ,
614
+ Limit : 10 ,
615
+ })
616
+ require .NoError (t , err )
617
+ require .Len (t , pendingMessages , 1 )
618
+ require .Equal (t , pendingMessages [0 ].ID .String (), sid .String ())
619
+
620
+ // Wait a few fetch intervals to be sure that no new notifications are being sent.
621
+ // TODO: use quartz instead.
622
+ // nolint:gocritic // These magic numbers are fine.
613
623
require .Eventually (t , func () bool {
614
- pendingMessages , err := api .Database .GetNotificationMessagesByStatus (ctx , database.GetNotificationMessagesByStatusParams {
615
- Status : database .NotificationMessageStatusPending ,
616
- Limit : 10 ,
617
- })
618
- assert .NoError (t , err )
619
- return len (pendingMessages ) == 1 &&
620
- pendingMessages [0 ].ID .String () == sid .String ()
621
- }, testutil .WaitShort , testutil .IntervalFast )
624
+ handler .mu .RLock ()
625
+ defer handler .mu .RUnlock ()
626
+
627
+ return len (handler .succeeded )+ len (handler .failed ) == 0
628
+ }, fetchInterval * 5 , testutil .IntervalFast )
622
629
623
630
// Unpause the notifier.
624
631
settingsJSON , err = json .Marshal (& codersdk.NotificationsSettings {NotifierPaused : false })
@@ -627,11 +634,12 @@ func TestNotifierPaused(t *testing.T) {
627
634
require .NoError (t , err )
628
635
629
636
// Notifier is running again, message should be dequeued.
637
+ // nolint:gocritic // These magic numbers are fine.
630
638
require .Eventually (t , func () bool {
631
639
handler .mu .RLock ()
632
640
defer handler .mu .RUnlock ()
633
641
return slices .Contains (handler .succeeded , sid .String ())
634
- }, testutil . WaitShort , testutil .IntervalFast )
642
+ }, fetchInterval * 5 , testutil .IntervalFast )
635
643
}
636
644
637
645
//go:embed events.go
0 commit comments