TestBasicNotificationRoundtrip enqueues a message to the store, waits for it to be acquired by a notifier, passes it off to a fake handler, and ensures the results are synchronized to the store.
(t *testing.T)
| 62 | // TestBasicNotificationRoundtrip enqueues a message to the store, waits for it to be acquired by a notifier, |
| 63 | // passes it off to a fake handler, and ensures the results are synchronized to the store. |
| 64 | func TestBasicNotificationRoundtrip(t *testing.T) { |
| 65 | t.Parallel() |
| 66 | |
| 67 | ctx := dbauthz.AsNotifier(testutil.Context(t, testutil.WaitSuperLong)) |
| 68 | store, pubsub := dbtestutil.NewDB(t) |
| 69 | logger := testutil.Logger(t) |
| 70 | method := database.NotificationMethodSmtp |
| 71 | |
| 72 | // GIVEN: a manager with standard config but a faked dispatch handler |
| 73 | handler := &fakeHandler{} |
| 74 | interceptor := &syncInterceptor{Store: store} |
| 75 | cfg := defaultNotificationsConfig(method) |
| 76 | cfg.RetryInterval = serpent.Duration(time.Hour) // Ensure retries don't interfere with the test |
| 77 | mgr, err := notifications.NewManager(cfg, interceptor, pubsub, defaultHelpers(), createMetrics(), logger.Named("manager")) |
| 78 | require.NoError(t, err) |
| 79 | mgr.WithHandlers(map[database.NotificationMethod]notifications.Handler{ |
| 80 | method: handler, |
| 81 | database.NotificationMethodInbox: &fakeHandler{}, |
| 82 | }) |
| 83 | t.Cleanup(func() { |
| 84 | assert.NoError(t, mgr.Stop(ctx)) |
| 85 | }) |
| 86 | enq, err := notifications.NewStoreEnqueuer(cfg, store, defaultHelpers(), logger.Named("enqueuer"), quartz.NewReal()) |
| 87 | require.NoError(t, err) |
| 88 | |
| 89 | user := createSampleUser(t, store) |
| 90 | |
| 91 | // WHEN: 2 messages are enqueued |
| 92 | sid, err := enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"type": "success"}, "test") |
| 93 | require.NoError(t, err) |
| 94 | fid, err := enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"type": "failure"}, "test") |
| 95 | require.NoError(t, err) |
| 96 | |
| 97 | mgr.Run(ctx) |
| 98 | |
| 99 | // THEN: we expect that the handler will have received the notifications for dispatch |
| 100 | require.Eventually(t, func() bool { |
| 101 | handler.mu.RLock() |
| 102 | defer handler.mu.RUnlock() |
| 103 | return slices.Contains(handler.succeeded, sid[0].String()) && |
| 104 | slices.Contains(handler.failed, fid[0].String()) |
| 105 | }, testutil.WaitLong, testutil.IntervalFast) |
| 106 | |
| 107 | // THEN: we expect the store to be called with the updates of the earlier dispatches |
| 108 | require.Eventually(t, func() bool { |
| 109 | return interceptor.sent.Load() == 2 && |
| 110 | interceptor.failed.Load() == 2 |
| 111 | }, testutil.WaitLong, testutil.IntervalFast) |
| 112 | |
| 113 | // THEN: we verify that the store contains notifications in their expected state |
| 114 | success, err := store.GetNotificationMessagesByStatus(ctx, database.GetNotificationMessagesByStatusParams{ |
| 115 | Status: database.NotificationMessageStatusSent, |
| 116 | Limit: 10, |
| 117 | }) |
| 118 | require.NoError(t, err) |
| 119 | require.Len(t, success, 2) |
| 120 | failed, err := store.GetNotificationMessagesByStatus(ctx, database.GetNotificationMessagesByStatusParams{ |
| 121 | Status: database.NotificationMessageStatusTemporaryFailure, |
nothing calls this directly
no test coverage detected