Skip to content

Commit 6f72588

Browse files
committed
Replacing in-memory setup with standard coderdtest.New
Signed-off-by: Danny Kopping <danny@coder.com>
1 parent 4cc26be commit 6f72588

File tree

6 files changed

+76
-86
lines changed

6 files changed

+76
-86
lines changed

coderd/database/dbauthz/dbauthz.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ var (
250250
rbac.ResourceWorkspaceDormant.Type: {policy.ActionUpdate, policy.ActionDelete, policy.ActionWorkspaceStop},
251251
rbac.ResourceWorkspace.Type: {policy.ActionUpdate, policy.ActionDelete, policy.ActionWorkspaceStart, policy.ActionWorkspaceStop, policy.ActionSSH},
252252
rbac.ResourceWorkspaceProxy.Type: {policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
253+
rbac.ResourceDeploymentConfig.Type: {policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
253254
}),
254255
Org: map[string][]rbac.Permission{},
255256
User: []rbac.Permission{},

coderd/notifications/manager_test.go

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ import (
77
"testing"
88
"time"
99

10+
"github.com/coder/quartz"
11+
"github.com/coder/serpent"
1012
"github.com/google/uuid"
1113
"github.com/stretchr/testify/assert"
1214
"github.com/stretchr/testify/require"
1315
"golang.org/x/xerrors"
1416

15-
"github.com/coder/quartz"
16-
"github.com/coder/serpent"
17-
17+
"github.com/coder/coder/v2/coderd/coderdtest"
1818
"github.com/coder/coder/v2/coderd/database"
19+
"github.com/coder/coder/v2/coderd/database/dbauthz"
1920
"github.com/coder/coder/v2/coderd/database/dbgen"
2021
"github.com/coder/coder/v2/coderd/notifications"
2122
"github.com/coder/coder/v2/coderd/notifications/dispatch"
@@ -27,31 +28,32 @@ func TestBufferedUpdates(t *testing.T) {
2728
t.Parallel()
2829

2930
// setup
30-
ctx, logger, db := setupInMemory(t)
31+
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
32+
_, _, api := coderdtest.NewWithAPI(t, nil)
3133

32-
interceptor := &syncInterceptor{Store: db}
34+
interceptor := &syncInterceptor{Store: api.Database}
3335
santa := &santaHandler{}
3436

3537
cfg := defaultNotificationsConfig(database.NotificationMethodSmtp)
3638
cfg.StoreSyncInterval = serpent.Duration(time.Hour) // Ensure we don't sync the store automatically.
3739

3840
// GIVEN: a manager which will pass or fail notifications based on their "nice" labels
39-
mgr, err := notifications.NewManager(cfg, interceptor, defaultHelpers(), createMetrics(), logger.Named("notifications-manager"))
41+
mgr, err := notifications.NewManager(cfg, interceptor, defaultHelpers(), createMetrics(), api.Logger.Named("notifications-manager"))
4042
require.NoError(t, err)
4143
mgr.WithHandlers(map[database.NotificationMethod]notifications.Handler{
4244
database.NotificationMethodSmtp: santa,
4345
})
44-
enq, err := notifications.NewStoreEnqueuer(cfg, interceptor, defaultHelpers(), logger.Named("notifications-enqueuer"), quartz.NewReal())
46+
enq, err := notifications.NewStoreEnqueuer(cfg, interceptor, defaultHelpers(), api.Logger.Named("notifications-enqueuer"), quartz.NewReal())
4547
require.NoError(t, err)
4648

47-
user := dbgen.User(t, db, database.User{})
49+
user := dbgen.User(t, api.Database, database.User{})
4850

4951
// WHEN: notifications are enqueued which should succeed and fail
50-
_, err = enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"nice": "true"}, "") // Will succeed.
52+
_, err = enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"nice": "true", "i": "0"}, "") // Will succeed.
5153
require.NoError(t, err)
52-
_, err = enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"nice": "true"}, "") // Will succeed.
54+
_, err = enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"nice": "true", "i": "1"}, "") // Will succeed.
5355
require.NoError(t, err)
54-
_, err = enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"nice": "false"}, "") // Will fail.
56+
_, err = enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"nice": "false", "i": "2"}, "") // Will fail.
5557
require.NoError(t, err)
5658

5759
mgr.Run(ctx)
@@ -95,7 +97,8 @@ func TestBuildPayload(t *testing.T) {
9597
t.Parallel()
9698

9799
// SETUP
98-
ctx, logger, db := setupInMemory(t)
100+
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
101+
_, _, api := coderdtest.NewWithAPI(t, nil)
99102

100103
// GIVEN: a set of helpers to be injected into the templates
101104
const label = "Click here!"
@@ -107,7 +110,7 @@ func TestBuildPayload(t *testing.T) {
107110
}
108111

109112
// GIVEN: an enqueue interceptor which returns mock metadata
110-
interceptor := newEnqueueInterceptor(db,
113+
interceptor := newEnqueueInterceptor(api.Database,
111114
// Inject custom message metadata to influence the payload construction.
112115
func() database.FetchNewMessageMetadataRow {
113116
// Inject template actions which use injected help functions.
@@ -129,7 +132,7 @@ func TestBuildPayload(t *testing.T) {
129132
}
130133
})
131134

132-
enq, err := notifications.NewStoreEnqueuer(defaultNotificationsConfig(database.NotificationMethodSmtp), interceptor, helpers, logger.Named("notifications-enqueuer"), quartz.NewReal())
135+
enq, err := notifications.NewStoreEnqueuer(defaultNotificationsConfig(database.NotificationMethodSmtp), interceptor, helpers, api.Logger.Named("notifications-enqueuer"), quartz.NewReal())
133136
require.NoError(t, err)
134137

135138
// WHEN: a notification is enqueued
@@ -149,10 +152,11 @@ func TestStopBeforeRun(t *testing.T) {
149152
t.Parallel()
150153

151154
// SETUP
152-
ctx, logger, db := setupInMemory(t)
155+
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
156+
_, _, api := coderdtest.NewWithAPI(t, nil)
153157

154158
// GIVEN: a standard manager
155-
mgr, err := notifications.NewManager(defaultNotificationsConfig(database.NotificationMethodSmtp), db, defaultHelpers(), createMetrics(), logger.Named("notifications-manager"))
159+
mgr, err := notifications.NewManager(defaultNotificationsConfig(database.NotificationMethodSmtp), api.Database, defaultHelpers(), createMetrics(), api.Logger.Named("notifications-manager"))
156160
require.NoError(t, err)
157161

158162
// THEN: validate that the manager can be stopped safely without Run() having been called yet

coderd/notifications/metrics_test.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ import (
1717

1818
"github.com/coder/serpent"
1919

20+
"github.com/coder/coder/v2/coderd/coderdtest"
2021
"github.com/coder/coder/v2/coderd/database"
22+
"github.com/coder/coder/v2/coderd/database/dbauthz"
2123
"github.com/coder/coder/v2/coderd/database/dbtestutil"
2224
"github.com/coder/coder/v2/coderd/notifications"
2325
"github.com/coder/coder/v2/coderd/notifications/dispatch"
@@ -204,7 +206,8 @@ func TestPendingUpdatesMetric(t *testing.T) {
204206
t.Parallel()
205207

206208
// SETUP
207-
ctx, logger, store := setupInMemory(t)
209+
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
210+
_, _, api := coderdtest.NewWithAPI(t, nil)
208211

209212
reg := prometheus.NewRegistry()
210213
metrics := notifications.NewMetrics(reg)
@@ -218,9 +221,9 @@ func TestPendingUpdatesMetric(t *testing.T) {
218221
cfg.RetryInterval = serpent.Duration(time.Hour) // Delay retries so they don't interfere.
219222
cfg.StoreSyncInterval = serpent.Duration(time.Millisecond * 100)
220223

221-
syncer := &syncInterceptor{Store: store}
224+
syncer := &syncInterceptor{Store: api.Database}
222225
interceptor := newUpdateSignallingInterceptor(syncer)
223-
mgr, err := notifications.NewManager(cfg, interceptor, defaultHelpers(), metrics, logger.Named("manager"))
226+
mgr, err := notifications.NewManager(cfg, interceptor, defaultHelpers(), metrics, api.Logger.Named("manager"))
224227
require.NoError(t, err)
225228
t.Cleanup(func() {
226229
assert.NoError(t, mgr.Stop(ctx))
@@ -230,10 +233,10 @@ func TestPendingUpdatesMetric(t *testing.T) {
230233
method: handler,
231234
})
232235

233-
enq, err := notifications.NewStoreEnqueuer(cfg, store, defaultHelpers(), logger.Named("enqueuer"), quartz.NewReal())
236+
enq, err := notifications.NewStoreEnqueuer(cfg, api.Database, defaultHelpers(), api.Logger.Named("enqueuer"), quartz.NewReal())
234237
require.NoError(t, err)
235238

236-
user := createSampleUser(t, store)
239+
user := createSampleUser(t, api.Database)
237240

238241
// WHEN: 2 notifications are enqueued, one of which will fail and one which will succeed
239242
_, err = enq.Enqueue(ctx, user.ID, template, map[string]string{"type": "success"}, "test") // this will succeed
@@ -279,7 +282,8 @@ func TestInflightDispatchesMetric(t *testing.T) {
279282
t.Parallel()
280283

281284
// SETUP
282-
ctx, logger, store := setupInMemory(t)
285+
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
286+
_, _, api := coderdtest.NewWithAPI(t, nil)
283287

284288
reg := prometheus.NewRegistry()
285289
metrics := notifications.NewMetrics(reg)
@@ -294,7 +298,7 @@ func TestInflightDispatchesMetric(t *testing.T) {
294298
cfg.RetryInterval = serpent.Duration(time.Hour) // Delay retries so they don't interfere.
295299
cfg.StoreSyncInterval = serpent.Duration(time.Millisecond * 100)
296300

297-
mgr, err := notifications.NewManager(cfg, store, defaultHelpers(), metrics, logger.Named("manager"))
301+
mgr, err := notifications.NewManager(cfg, api.Database, defaultHelpers(), metrics, api.Logger.Named("manager"))
298302
require.NoError(t, err)
299303
t.Cleanup(func() {
300304
assert.NoError(t, mgr.Stop(ctx))
@@ -307,10 +311,10 @@ func TestInflightDispatchesMetric(t *testing.T) {
307311
method: delayer,
308312
})
309313

310-
enq, err := notifications.NewStoreEnqueuer(cfg, store, defaultHelpers(), logger.Named("enqueuer"), quartz.NewReal())
314+
enq, err := notifications.NewStoreEnqueuer(cfg, api.Database, defaultHelpers(), api.Logger.Named("enqueuer"), quartz.NewReal())
311315
require.NoError(t, err)
312316

313-
user := createSampleUser(t, store)
317+
user := createSampleUser(t, api.Database)
314318

315319
// WHEN: notifications are enqueued which will succeed (and be delayed during dispatch)
316320
const msgCount = 2

coderd/notifications/notifications_test.go

Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import (
3333

3434
"github.com/coder/coder/v2/coderd/coderdtest"
3535
"github.com/coder/coder/v2/coderd/database"
36+
"github.com/coder/coder/v2/coderd/database/dbauthz"
3637
"github.com/coder/coder/v2/coderd/database/dbgen"
3738
"github.com/coder/coder/v2/coderd/database/dbtestutil"
3839
"github.com/coder/coder/v2/coderd/notifications"
@@ -119,7 +120,8 @@ func TestSMTPDispatch(t *testing.T) {
119120
t.Parallel()
120121

121122
// SETUP
122-
ctx, logger, db := setupInMemory(t)
123+
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
124+
_, _, api := coderdtest.NewWithAPI(t, nil)
123125

124126
// start mock SMTP server
125127
mockSMTPSrv := smtpmock.New(smtpmock.ConfigurationAttr{
@@ -140,17 +142,17 @@ func TestSMTPDispatch(t *testing.T) {
140142
Smarthost: serpent.HostPort{Host: "localhost", Port: fmt.Sprintf("%d", mockSMTPSrv.PortNumber())},
141143
Hello: "localhost",
142144
}
143-
handler := newDispatchInterceptor(dispatch.NewSMTPHandler(cfg.SMTP, defaultHelpers(), logger.Named("smtp")))
144-
mgr, err := notifications.NewManager(cfg, db, defaultHelpers(), createMetrics(), logger.Named("manager"))
145+
handler := newDispatchInterceptor(dispatch.NewSMTPHandler(cfg.SMTP, defaultHelpers(), api.Logger.Named("smtp")))
146+
mgr, err := notifications.NewManager(cfg, api.Database, defaultHelpers(), createMetrics(), api.Logger.Named("manager"))
145147
require.NoError(t, err)
146148
mgr.WithHandlers(map[database.NotificationMethod]notifications.Handler{method: handler})
147149
t.Cleanup(func() {
148150
assert.NoError(t, mgr.Stop(ctx))
149151
})
150-
enq, err := notifications.NewStoreEnqueuer(cfg, db, defaultHelpers(), logger.Named("enqueuer"), quartz.NewReal())
152+
enq, err := notifications.NewStoreEnqueuer(cfg, api.Database, defaultHelpers(), api.Logger.Named("enqueuer"), quartz.NewReal())
151153
require.NoError(t, err)
152154

153-
user := createSampleUser(t, db)
155+
user := createSampleUser(t, api.Database)
154156

155157
// WHEN: a message is enqueued
156158
msgID, err := enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{}, "test")
@@ -177,7 +179,8 @@ func TestWebhookDispatch(t *testing.T) {
177179
t.Parallel()
178180

179181
// SETUP
180-
ctx, logger, db := setupInMemory(t)
182+
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
183+
_, _, api := coderdtest.NewWithAPI(t, nil)
181184

182185
sent := make(chan dispatch.WebhookPayload, 1)
183186
// Mock server to simulate webhook endpoint.
@@ -202,20 +205,20 @@ func TestWebhookDispatch(t *testing.T) {
202205
cfg.Webhook = codersdk.NotificationsWebhookConfig{
203206
Endpoint: *serpent.URLOf(endpoint),
204207
}
205-
mgr, err := notifications.NewManager(cfg, db, defaultHelpers(), createMetrics(), logger.Named("manager"))
208+
mgr, err := notifications.NewManager(cfg, api.Database, defaultHelpers(), createMetrics(), api.Logger.Named("manager"))
206209
require.NoError(t, err)
207210
t.Cleanup(func() {
208211
assert.NoError(t, mgr.Stop(ctx))
209212
})
210-
enq, err := notifications.NewStoreEnqueuer(cfg, db, defaultHelpers(), logger.Named("enqueuer"), quartz.NewReal())
213+
enq, err := notifications.NewStoreEnqueuer(cfg, api.Database, defaultHelpers(), api.Logger.Named("enqueuer"), quartz.NewReal())
211214
require.NoError(t, err)
212215

213216
const (
214217
email = "bob@coder.com"
215218
name = "Robert McBobbington"
216219
username = "bob"
217220
)
218-
user := dbgen.User(t, db, database.User{
221+
user := dbgen.User(t, api.Database, database.User{
219222
Email: email,
220223
Username: username,
221224
Name: name,
@@ -533,7 +536,7 @@ func TestExpiredLeaseIsRequeued(t *testing.T) {
533536
func TestInvalidConfig(t *testing.T) {
534537
t.Parallel()
535538

536-
_, logger, db := setupInMemory(t)
539+
_, _, api := coderdtest.NewWithAPI(t, nil)
537540

538541
// GIVEN: invalid config with dispatch period <= lease period
539542
const (
@@ -545,7 +548,7 @@ func TestInvalidConfig(t *testing.T) {
545548
cfg.DispatchTimeout = serpent.Duration(leasePeriod)
546549

547550
// WHEN: the manager is created with invalid config
548-
_, err := notifications.NewManager(cfg, db, defaultHelpers(), createMetrics(), logger.Named("manager"))
551+
_, err := notifications.NewManager(cfg, api.Database, defaultHelpers(), createMetrics(), api.Logger.Named("manager"))
549552

550553
// THEN: the manager will fail to be created, citing invalid config as error
551554
require.ErrorIs(t, err, notifications.ErrInvalidDispatchTimeout)
@@ -555,55 +558,57 @@ func TestNotifierPaused(t *testing.T) {
555558
t.Parallel()
556559

557560
// setup
558-
ctx, logger, db := setupInMemory(t)
561+
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
562+
_, _, api := coderdtest.NewWithAPI(t, nil)
559563

560564
// Prepare the test
561565
handler := &fakeHandler{}
562566
method := database.NotificationMethodSmtp
563-
user := createSampleUser(t, db)
567+
user := createSampleUser(t, api.Database)
564568

569+
const fetchInterval = time.Millisecond * 100
565570
cfg := defaultNotificationsConfig(method)
566-
mgr, err := notifications.NewManager(cfg, db, defaultHelpers(), createMetrics(), logger.Named("manager"))
571+
cfg.FetchInterval = serpent.Duration(fetchInterval)
572+
mgr, err := notifications.NewManager(cfg, api.Database, defaultHelpers(), createMetrics(), api.Logger.Named("manager"))
567573
require.NoError(t, err)
568574
mgr.WithHandlers(map[database.NotificationMethod]notifications.Handler{method: handler})
569575
t.Cleanup(func() {
570576
assert.NoError(t, mgr.Stop(ctx))
571577
})
572-
enq, err := notifications.NewStoreEnqueuer(cfg, db, defaultHelpers(), logger.Named("enqueuer"), quartz.NewReal())
578+
enq, err := notifications.NewStoreEnqueuer(cfg, api.Database, defaultHelpers(), api.Logger.Named("enqueuer"), quartz.NewReal())
573579
require.NoError(t, err)
574580

575581
mgr.Run(ctx)
576582

577-
// Notifier is on, enqueue the first message.
578-
sid, err := enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"type": "success"}, "test")
579-
require.NoError(t, err)
580-
require.Eventually(t, func() bool {
581-
handler.mu.RLock()
582-
defer handler.mu.RUnlock()
583-
return slices.Contains(handler.succeeded, sid.String())
584-
}, testutil.WaitShort, testutil.IntervalFast)
585-
586583
// Pause the notifier.
587584
settingsJSON, err := json.Marshal(&codersdk.NotificationsSettings{NotifierPaused: true})
588585
require.NoError(t, err)
589-
err = db.UpsertNotificationsSettings(ctx, string(settingsJSON))
586+
err = api.Database.UpsertNotificationsSettings(ctx, string(settingsJSON))
590587
require.NoError(t, err)
591588

592589
// Notifier is paused, enqueue the next message.
593-
sid, err = enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"type": "success"}, "test")
590+
sid, err := enq.Enqueue(ctx, user.ID, notifications.TemplateWorkspaceDeleted, map[string]string{"type": "success", "i": "1"}, "test")
594591
require.NoError(t, err)
592+
593+
// Sleep for a few fetch intervals to be sure we aren't getting false-positives in the next step.
594+
// TODO: use quartz instead.
595+
time.Sleep(fetchInterval*5)
596+
597+
// Ensure we have a pending message and it's the expected one.
595598
require.Eventually(t, func() bool {
596-
pendingMessages, err := db.GetNotificationMessagesByStatus(ctx, database.GetNotificationMessagesByStatusParams{
599+
pendingMessages, err := api.Database.GetNotificationMessagesByStatus(ctx, database.GetNotificationMessagesByStatusParams{
597600
Status: database.NotificationMessageStatusPending,
601+
Limit: 10,
598602
})
599603
assert.NoError(t, err)
600-
return len(pendingMessages) == 1
604+
return len(pendingMessages) == 1 &&
605+
pendingMessages[0].ID.String() == sid.String()
601606
}, testutil.WaitShort, testutil.IntervalFast)
602607

603608
// Unpause the notifier.
604609
settingsJSON, err = json.Marshal(&codersdk.NotificationsSettings{NotifierPaused: false})
605610
require.NoError(t, err)
606-
err = db.UpsertNotificationsSettings(ctx, string(settingsJSON))
611+
err = api.Database.UpsertNotificationsSettings(ctx, string(settingsJSON))
607612
require.NoError(t, err)
608613

609614
// Notifier is running again, message should be dequeued.
@@ -723,19 +728,6 @@ func TestNotificationTemplatesCanRender(t *testing.T) {
723728
},
724729
},
725730
},
726-
{
727-
name: "TemplateWorkspaceMarkedForDeletionInOneWeek",
728-
id: notifications.TemplateWorkspaceMarkedForDeletion,
729-
payload: types.MessagePayload{
730-
UserName: "bobby",
731-
Labels: map[string]string{
732-
"name": "bobby-workspace",
733-
"reason": "template updated to new dormancy policy",
734-
"dormancyHours": "168", // 168 hours = 7 days = 1 week
735-
"timeTilDormant": "1 week",
736-
},
737-
},
738-
},
739731
{
740732
name: "TemplateUserAccountCreated",
741733
id: notifications.TemplateUserAccountCreated,
@@ -1048,7 +1040,7 @@ func TestNotificationsTemplates(t *testing.T) {
10481040
t.Skip("This test requires postgres; it relies on business-logic only implemented in the database")
10491041
}
10501042

1051-
ctx := testutil.Context(t, testutil.WaitLong)
1043+
ctx := dbauthz.AsSystemRestricted(testutil.Context(t, testutil.WaitSuperLong))
10521044
api := coderdtest.New(t, createOpts(t))
10531045

10541046
// GIVEN: the first user (owner) and a regular member

0 commit comments

Comments
 (0)