@@ -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