Skip to content

Commit 4f7309e

Browse files
committed
Use apitest.InvokeHandler in the test suite
Modify the test suite to invoke endpoints with `apitest.InvokeHandler` proposed in [1]. This isn't too different than invoking them raw, but provides a couple extra niceties like validating input request structs and returning realistic looking API errors in case of a problem. [1] riverqueue/apiframe#3
1 parent c1d45ff commit 4f7309e

3 files changed

Lines changed: 39 additions & 34 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ toolchain go1.24.1
77
require (
88
github.com/google/uuid v1.6.0
99
github.com/jackc/pgx/v5 v5.7.2
10-
github.com/riverqueue/apiframe v0.0.0-20250310051455-203f3fd8260f
10+
github.com/riverqueue/apiframe v0.0.0-20250310054829-19e112904670
1111
github.com/riverqueue/river v0.18.0
1212
github.com/riverqueue/river/riverdriver v0.18.0
1313
github.com/riverqueue/river/riverdriver/riverpgxv5 v0.18.0

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
3737
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
3838
github.com/riverqueue/apiframe v0.0.0-20250310051455-203f3fd8260f h1:Pr3+ERes1GkCJnw/gpi9yVx9tN7VCcPjuZCFN/OBaZg=
3939
github.com/riverqueue/apiframe v0.0.0-20250310051455-203f3fd8260f/go.mod h1:ko/9b4SeomWrHTr4WU0i21peq90Qk2Mm8MgOqPrTcHA=
40+
github.com/riverqueue/apiframe v0.0.0-20250310054829-19e112904670 h1:c2t1Rgb/VC07gUXEO4OnPBKRd6Oct5yECyhxtVyIO1M=
41+
github.com/riverqueue/apiframe v0.0.0-20250310054829-19e112904670/go.mod h1:ko/9b4SeomWrHTr4WU0i21peq90Qk2Mm8MgOqPrTcHA=
42+
github.com/riverqueue/apiframe v0.0.0-20250310055546-28a3f81b743f h1:LzrDfxieq6nT71TovkyLSTYhUzTbRoV0U2llKxFUtnA=
43+
github.com/riverqueue/apiframe v0.0.0-20250310055546-28a3f81b743f/go.mod h1:ko/9b4SeomWrHTr4WU0i21peq90Qk2Mm8MgOqPrTcHA=
4044
github.com/riverqueue/river v0.18.0 h1:sGHeTOL9MR8+pMIVHRm59fzet8Ron/xjF3Yq/PSGb78=
4145
github.com/riverqueue/river v0.18.0/go.mod h1:oapX5xb/L2YnkE801QubDZ0COHxVxEGVY37icPzghhU=
4246
github.com/riverqueue/river/riverdriver v0.18.0 h1:a2haR5I0MQLHjLCSVFpUEeJALCLemRl5zCztucysm1E=

handler_api_endpoint_test.go

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/stretchr/testify/require"
1212

1313
"github.com/riverqueue/apiframe/apierror"
14+
"github.com/riverqueue/apiframe/apitest"
1415
"github.com/riverqueue/river"
1516
"github.com/riverqueue/river/riverdriver"
1617
"github.com/riverqueue/river/rivershared/riversharedtest"
@@ -68,7 +69,7 @@ func TestHandlerHealthCheckGetEndpoint(t *testing.T) {
6869

6970
endpoint, _ := setupEndpoint(ctx, t, newHealthCheckGetEndpoint)
7071

71-
resp, err := endpoint.Execute(ctx, &healthCheckGetRequest{Name: healthCheckNameComplete})
72+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &healthCheckGetRequest{Name: healthCheckNameComplete})
7273
require.NoError(t, err)
7374
require.Equal(t, statusResponseOK, resp)
7475
})
@@ -81,7 +82,7 @@ func TestHandlerHealthCheckGetEndpoint(t *testing.T) {
8182
// Roll back prematurely so we get a database error.
8283
require.NoError(t, bundle.tx.Rollback(ctx))
8384

84-
_, err := endpoint.Execute(ctx, &healthCheckGetRequest{Name: healthCheckNameComplete})
85+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &healthCheckGetRequest{Name: healthCheckNameComplete})
8586
requireAPIError(t, apierror.WithInternalError(
8687
apierror.NewServiceUnavailable("Unable to query database. Check logs for details."),
8788
pgx.ErrTxClosed,
@@ -93,7 +94,7 @@ func TestHandlerHealthCheckGetEndpoint(t *testing.T) {
9394

9495
endpoint, _ := setupEndpoint(ctx, t, newHealthCheckGetEndpoint)
9596

96-
resp, err := endpoint.Execute(ctx, &healthCheckGetRequest{Name: healthCheckNameMinimal})
97+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &healthCheckGetRequest{Name: healthCheckNameMinimal})
9798
require.NoError(t, err)
9899
require.Equal(t, statusResponseOK, resp)
99100
})
@@ -103,7 +104,7 @@ func TestHandlerHealthCheckGetEndpoint(t *testing.T) {
103104

104105
endpoint, _ := setupEndpoint(ctx, t, newHealthCheckGetEndpoint)
105106

106-
_, err := endpoint.Execute(ctx, &healthCheckGetRequest{Name: "other"})
107+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &healthCheckGetRequest{Name: "other"})
107108
requireAPIError(t, apierror.NewNotFoundf("Health check %q not found. Use either `complete` or `minimal`.", "other"), err)
108109
})
109110
}
@@ -121,7 +122,7 @@ func TestJobCancelEndpoint(t *testing.T) {
121122
job1 := testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{})
122123
job2 := testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{})
123124

124-
resp, err := endpoint.Execute(ctx, &jobCancelRequest{JobIDs: []int64String{int64String(job1.ID), int64String(job2.ID)}})
125+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobCancelRequest{JobIDs: []int64String{int64String(job1.ID), int64String(job2.ID)}})
125126
require.NoError(t, err)
126127
require.Equal(t, statusResponseOK, resp)
127128

@@ -139,7 +140,7 @@ func TestJobCancelEndpoint(t *testing.T) {
139140

140141
endpoint, _ := setupEndpoint(ctx, t, newJobCancelEndpoint)
141142

142-
_, err := endpoint.Execute(ctx, &jobCancelRequest{JobIDs: []int64String{123}})
143+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobCancelRequest{JobIDs: []int64String{123}})
143144
requireAPIError(t, NewNotFoundJob(123), err)
144145
})
145146
}
@@ -157,7 +158,7 @@ func TestJobDeleteEndpoint(t *testing.T) {
157158
job1 := testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{})
158159
job2 := testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{})
159160

160-
resp, err := endpoint.Execute(ctx, &jobDeleteRequest{JobIDs: []int64String{int64String(job1.ID), int64String(job2.ID)}})
161+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobDeleteRequest{JobIDs: []int64String{int64String(job1.ID), int64String(job2.ID)}})
161162
require.NoError(t, err)
162163
require.Equal(t, statusResponseOK, resp)
163164

@@ -173,7 +174,7 @@ func TestJobDeleteEndpoint(t *testing.T) {
173174

174175
endpoint, _ := setupEndpoint(ctx, t, newJobDeleteEndpoint)
175176

176-
_, err := endpoint.Execute(ctx, &jobDeleteRequest{JobIDs: []int64String{123}})
177+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobDeleteRequest{JobIDs: []int64String{123}})
177178
requireAPIError(t, NewNotFoundJob(123), err)
178179
})
179180
}
@@ -190,7 +191,7 @@ func TestJobGetEndpoint(t *testing.T) {
190191

191192
job := testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{})
192193

193-
resp, err := endpoint.Execute(ctx, &jobGetRequest{JobID: job.ID})
194+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobGetRequest{JobID: job.ID})
194195
require.NoError(t, err)
195196
require.Equal(t, job.ID, resp.ID)
196197
})
@@ -200,7 +201,7 @@ func TestJobGetEndpoint(t *testing.T) {
200201

201202
endpoint, _ := setupEndpoint(ctx, t, newJobGetEndpoint)
202203

203-
_, err := endpoint.Execute(ctx, &jobGetRequest{JobID: 123})
204+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobGetRequest{JobID: 123})
204205
requireAPIError(t, NewNotFoundJob(123), err)
205206
})
206207
}
@@ -226,7 +227,7 @@ func TestAPIHandlerJobList(t *testing.T) {
226227
_ = testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{State: ptrutil.Ptr(rivertype.JobStatePending)})
227228
_ = testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{State: ptrutil.Ptr(rivertype.JobStateScheduled)})
228229

229-
resp, err := endpoint.Execute(ctx, &jobListRequest{})
230+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobListRequest{})
230231
require.NoError(t, err)
231232
require.Len(t, resp.Data, 2)
232233
require.Equal(t, job1.ID, resp.Data[0].ID)
@@ -241,7 +242,7 @@ func TestAPIHandlerJobList(t *testing.T) {
241242
job1 := testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{State: ptrutil.Ptr(rivertype.JobStateRunning)})
242243
_ = testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{})
243244

244-
resp, err := endpoint.Execute(ctx, &jobListRequest{Limit: ptrutil.Ptr(1)})
245+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobListRequest{Limit: ptrutil.Ptr(1)})
245246
require.NoError(t, err)
246247
require.Len(t, resp.Data, 1)
247248
require.Equal(t, job1.ID, resp.Data[0].ID)
@@ -258,7 +259,7 @@ func TestAPIHandlerJobList(t *testing.T) {
258259
// Other states excluded.
259260
_ = testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{State: ptrutil.Ptr(rivertype.JobStateAvailable)})
260261

261-
resp, err := endpoint.Execute(ctx, &jobListRequest{State: ptrutil.Ptr(rivertype.JobStateCompleted)})
262+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobListRequest{State: ptrutil.Ptr(rivertype.JobStateCompleted)})
262263
require.NoError(t, err)
263264
require.Len(t, resp.Data, 2)
264265
require.Equal(t, job2.ID, resp.Data[0].ID) // order inverted
@@ -276,7 +277,7 @@ func TestAPIHandlerJobList(t *testing.T) {
276277
// Other states excluded.
277278
_ = testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{State: ptrutil.Ptr(rivertype.JobStateScheduled)})
278279

279-
resp, err := endpoint.Execute(ctx, &jobListRequest{State: ptrutil.Ptr(rivertype.JobStateAvailable)})
280+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobListRequest{State: ptrutil.Ptr(rivertype.JobStateAvailable)})
280281
require.NoError(t, err)
281282
require.Len(t, resp.Data, 2)
282283
require.Equal(t, job1.ID, resp.Data[0].ID)
@@ -303,7 +304,7 @@ func TestJobRetryEndpoint(t *testing.T) {
303304
State: ptrutil.Ptr(rivertype.JobStateDiscarded),
304305
})
305306

306-
resp, err := endpoint.Execute(ctx, &jobRetryRequest{JobIDs: []int64String{int64String(job1.ID), int64String(job2.ID)}})
307+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobRetryRequest{JobIDs: []int64String{int64String(job1.ID), int64String(job2.ID)}})
307308
require.NoError(t, err)
308309
require.Equal(t, statusResponseOK, resp)
309310

@@ -321,7 +322,7 @@ func TestJobRetryEndpoint(t *testing.T) {
321322

322323
endpoint, _ := setupEndpoint(ctx, t, newJobRetryEndpoint)
323324

324-
_, err := endpoint.Execute(ctx, &jobRetryRequest{JobIDs: []int64String{123}})
325+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &jobRetryRequest{JobIDs: []int64String{123}})
325326
requireAPIError(t, NewNotFoundJob(123), err)
326327
})
327328
}
@@ -341,7 +342,7 @@ func TestAPIHandlerQueueGet(t *testing.T) {
341342
_, err := bundle.client.InsertTx(ctx, bundle.tx, &noOpArgs{}, &river.InsertOpts{Queue: queue.Name})
342343
require.NoError(t, err)
343344

344-
resp, err := endpoint.Execute(ctx, &queueGetRequest{Name: queue.Name})
345+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &queueGetRequest{Name: queue.Name})
345346
require.NoError(t, err)
346347
require.Equal(t, 1, resp.CountAvailable)
347348
require.Equal(t, queue.Name, resp.Name)
@@ -352,7 +353,7 @@ func TestAPIHandlerQueueGet(t *testing.T) {
352353

353354
endpoint, _ := setupEndpoint(ctx, t, newQueueGetEndpoint)
354355

355-
_, err := endpoint.Execute(ctx, &queueGetRequest{Name: "does_not_exist"})
356+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &queueGetRequest{Name: "does_not_exist"})
356357
requireAPIError(t, NewNotFoundQueue("does_not_exist"), err)
357358
})
358359
}
@@ -373,7 +374,7 @@ func TestAPIHandlerQueueList(t *testing.T) {
373374
_ = testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{Queue: &queue1.Name})
374375
_ = testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{Queue: &queue2.Name})
375376

376-
resp, err := endpoint.Execute(ctx, &queueListRequest{})
377+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &queueListRequest{})
377378
require.NoError(t, err)
378379
require.Len(t, resp.Data, 2)
379380
require.Equal(t, 1, resp.Data[0].CountAvailable)
@@ -390,7 +391,7 @@ func TestAPIHandlerQueueList(t *testing.T) {
390391
queue1 := testfactory.Queue(ctx, t, bundle.exec, nil)
391392
_ = testfactory.Queue(ctx, t, bundle.exec, nil)
392393

393-
resp, err := endpoint.Execute(ctx, &queueListRequest{Limit: ptrutil.Ptr(1)})
394+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &queueListRequest{Limit: ptrutil.Ptr(1)})
394395
require.NoError(t, err)
395396
require.Len(t, resp.Data, 1)
396397
require.Equal(t, queue1.Name, resp.Data[0].Name)
@@ -409,7 +410,7 @@ func TestAPIHandlerQueuePause(t *testing.T) {
409410

410411
queue := testfactory.Queue(ctx, t, bundle.exec, nil)
411412

412-
resp, err := endpoint.Execute(ctx, &queuePauseRequest{Name: queue.Name})
413+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &queuePauseRequest{Name: queue.Name})
413414
require.NoError(t, err)
414415
require.Equal(t, statusResponseOK, resp)
415416
})
@@ -419,7 +420,7 @@ func TestAPIHandlerQueuePause(t *testing.T) {
419420

420421
endpoint, _ := setupEndpoint(ctx, t, newQueuePauseEndpoint)
421422

422-
_, err := endpoint.Execute(ctx, &queuePauseRequest{Name: "does_not_exist"})
423+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &queuePauseRequest{Name: "does_not_exist"})
423424
requireAPIError(t, NewNotFoundQueue("does_not_exist"), err)
424425
})
425426
}
@@ -438,7 +439,7 @@ func TestAPIHandlerQueueResume(t *testing.T) {
438439
PausedAt: ptrutil.Ptr(time.Now()),
439440
})
440441

441-
resp, err := endpoint.Execute(ctx, &queueResumeRequest{Name: queue.Name})
442+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &queueResumeRequest{Name: queue.Name})
442443
require.NoError(t, err)
443444
require.Equal(t, statusResponseOK, resp)
444445
})
@@ -448,7 +449,7 @@ func TestAPIHandlerQueueResume(t *testing.T) {
448449

449450
endpoint, _ := setupEndpoint(ctx, t, newQueueResumeEndpoint)
450451

451-
_, err := endpoint.Execute(ctx, &queueResumeRequest{Name: "does_not_exist"})
452+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &queueResumeRequest{Name: "does_not_exist"})
452453
requireAPIError(t, NewNotFoundQueue("does_not_exist"), err)
453454
})
454455
}
@@ -493,7 +494,7 @@ func TestStateAndCountGetEndpoint(t *testing.T) {
493494
_ = testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{State: ptrutil.Ptr(rivertype.JobStateScheduled)})
494495
}
495496

496-
resp, err := endpoint.Execute(ctx, &stateAndCountGetRequest{})
497+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &stateAndCountGetRequest{})
497498
require.NoError(t, err)
498499
require.Equal(t, &stateAndCountGetResponse{
499500
Available: 1,
@@ -520,7 +521,7 @@ func TestStateAndCountGetEndpoint(t *testing.T) {
520521
_, err := endpoint.queryCacher.RunQuery(ctx)
521522
require.NoError(t, err)
522523

523-
resp, err := endpoint.Execute(ctx, &stateAndCountGetRequest{})
524+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &stateAndCountGetRequest{})
524525
require.NoError(t, err)
525526
require.Equal(t, &stateAndCountGetResponse{
526527
Available: queryCacheSkipThreshold + 1,
@@ -540,7 +541,7 @@ func TestStateAndCountGetEndpoint(t *testing.T) {
540541
_, err := endpoint.queryCacher.RunQuery(ctx)
541542
require.NoError(t, err)
542543

543-
resp, err := endpoint.Execute(ctx, &stateAndCountGetRequest{})
544+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &stateAndCountGetRequest{})
544545
require.NoError(t, err)
545546
require.Equal(t, &stateAndCountGetResponse{
546547
Available: queryCacheSkipThreshold - 1,
@@ -562,7 +563,7 @@ func TestAPIHandlerWorkflowGet(t *testing.T) {
562563
job1 := testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{Metadata: mustMarshalJSON(t, map[string]uuid.UUID{"workflow_id": workflowID})})
563564
job2 := testfactory.Job(ctx, t, bundle.exec, &testfactory.JobOpts{Metadata: mustMarshalJSON(t, map[string]uuid.UUID{"workflow_id": workflowID})})
564565

565-
resp, err := endpoint.Execute(ctx, &workflowGetRequest{ID: workflowID.String()})
566+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &workflowGetRequest{ID: workflowID.String()})
566567
require.NoError(t, err)
567568
require.Len(t, resp.Tasks, 2)
568569
require.Equal(t, job1.ID, resp.Tasks[0].ID)
@@ -576,7 +577,7 @@ func TestAPIHandlerWorkflowGet(t *testing.T) {
576577

577578
workflowID := uuid.New()
578579

579-
_, err := endpoint.Execute(ctx, &workflowGetRequest{ID: workflowID.String()})
580+
_, err := apitest.InvokeHandler(ctx, endpoint.Execute, &workflowGetRequest{ID: workflowID.String()})
580581
requireAPIError(t, NewNotFoundWorkflow(workflowID.String()), err)
581582
})
582583
}
@@ -607,7 +608,7 @@ func TestAPIHandlerWorkflowList(t *testing.T) {
607608
})
608609

609610
t.Run("All", func(t *testing.T) {
610-
resp, err := endpoint.Execute(ctx, &workflowListRequest{})
611+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &workflowListRequest{})
611612
require.NoError(t, err)
612613
require.Len(t, resp.Data, 2)
613614
require.Equal(t, 1, resp.Data[0].CountCancelled)
@@ -629,7 +630,7 @@ func TestAPIHandlerWorkflowList(t *testing.T) {
629630
})
630631

631632
t.Run("Active", func(t *testing.T) {
632-
resp, err := endpoint.Execute(ctx, &workflowListRequest{State: "active"})
633+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &workflowListRequest{State: "active"})
633634
require.NoError(t, err)
634635
require.Len(t, resp.Data, 1)
635636
require.Equal(t, 0, resp.Data[0].CountAvailable)
@@ -646,7 +647,7 @@ func TestAPIHandlerWorkflowList(t *testing.T) {
646647
})
647648

648649
t.Run("Inactive", func(t *testing.T) {
649-
resp, err := endpoint.Execute(ctx, &workflowListRequest{State: "inactive"})
650+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &workflowListRequest{State: "inactive"})
650651
require.NoError(t, err)
651652
require.Len(t, resp.Data, 1)
652653
require.Equal(t, 1, resp.Data[0].CountCompleted)
@@ -671,7 +672,7 @@ func TestAPIHandlerWorkflowList(t *testing.T) {
671672
State: ptrutil.Ptr(rivertype.JobStateScheduled),
672673
})
673674

674-
resp, err := endpoint.Execute(ctx, &workflowListRequest{Limit: ptrutil.Ptr(1)})
675+
resp, err := apitest.InvokeHandler(ctx, endpoint.Execute, &workflowListRequest{Limit: ptrutil.Ptr(1)})
675676
require.NoError(t, err)
676677
require.Len(t, resp.Data, 1)
677678
require.Equal(t, "2", resp.Data[0].ID) // DESC order means last one gets returned

0 commit comments

Comments
 (0)