@@ -576,7 +576,7 @@ func TestNotifierPaused(t *testing.T) {
576576 ctx := dbauthz .AsSystemRestricted (testutil .Context (t , testutil .WaitSuperLong ))
577577 _ , _ , api := coderdtest .NewWithAPI (t , nil )
578578
579- // Prepare the test
579+ // Prepare the test.
580580 handler := & fakeHandler {}
581581 method := database .NotificationMethodSmtp
582582 user := createSampleUser (t , api .Database )
@@ -593,32 +593,39 @@ func TestNotifierPaused(t *testing.T) {
593593 enq , err := notifications .NewStoreEnqueuer (cfg , api .Database , defaultHelpers (), api .Logger .Named ("enqueuer" ), quartz .NewReal ())
594594 require .NoError (t , err )
595595
596- mgr .Run (ctx )
597-
598596 // Pause the notifier.
599597 settingsJSON , err := json .Marshal (& codersdk.NotificationsSettings {NotifierPaused : true })
600598 require .NoError (t , err )
601599 err = api .Database .UpsertNotificationsSettings (ctx , string (settingsJSON ))
602600 require .NoError (t , err )
603601
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+
604607 // Notifier is paused, enqueue the next message.
605608 sid , err := enq .Enqueue (ctx , user .ID , notifications .TemplateWorkspaceDeleted , map [string ]string {"type" : "success" , "i" : "1" }, "test" )
606609 require .NoError (t , err )
607610
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-
612611 // 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.
613623 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 )
622629
623630 // Unpause the notifier.
624631 settingsJSON , err = json .Marshal (& codersdk.NotificationsSettings {NotifierPaused : false })
@@ -627,11 +634,12 @@ func TestNotifierPaused(t *testing.T) {
627634 require .NoError (t , err )
628635
629636 // Notifier is running again, message should be dequeued.
637+ // nolint:gocritic // These magic numbers are fine.
630638 require .Eventually (t , func () bool {
631639 handler .mu .RLock ()
632640 defer handler .mu .RUnlock ()
633641 return slices .Contains (handler .succeeded , sid .String ())
634- }, testutil . WaitShort , testutil .IntervalFast )
642+ }, fetchInterval * 5 , testutil .IntervalFast )
635643}
636644
637645//go:embed events.go
0 commit comments