refactor(backend): update test files for PoolProxy and per-test transactions

Migrate all test files from SetupTestDB/db.DB pattern to per-test transactions:

- Replace SetupTestDB(t) with SetupTestTx(t) for context + transaction
- Replace db.DB.Query/QueryRow/Exec with tx.Query/QueryRow/Exec
- Replace context.Background() with context from SetupTestTx
- Replace defer rows.Close() pattern with explicit rows.Close()
- Add testdb.SeedBaseline(pool) to all TestMain functions
- Wire db.Conn = db.NewPoolProxy(pool) in all TestMain functions

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-06-21 19:29:24 +01:00
co-authored by Sisyphus
parent 3d0e2afc4c
commit 220a0ef6e8
57 changed files with 5911 additions and 6235 deletions
+29 -25
View File
@@ -29,10 +29,9 @@ import (
)
// createUserWithDOB creates a test user with specified date of birth
func createUserWithDOB(dob string) (string, error) {
ctx := context.Background()
func createUserWithDOB(ctx context.Context, q db.Querier, dob string) (string, error) {
var userID string
err := db.DB.QueryRow(ctx, `
err := q.QueryRow(ctx, `
INSERT INTO users (n_first_name, n_last_name, email, phone, date_of_birth, password_hash, account_role, account_type)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
RETURNING id
@@ -40,7 +39,7 @@ func createUserWithDOB(dob string) (string, error) {
return userID, err
}
func makeRequest(handler http.HandlerFunc, method, path string, body interface{}) *httptest.ResponseRecorder {
func makeRequest(handler http.HandlerFunc, method, path string, body interface{}, ctx context.Context) *httptest.ResponseRecorder {
var req *http.Request
if body != nil {
bodyBytes, _ := json.Marshal(body)
@@ -49,18 +48,19 @@ func makeRequest(handler http.HandlerFunc, method, path string, body interface{}
} else {
req = httptest.NewRequest(method, path, nil)
}
return makeRequestWithContext(handler, req)
return makeRequestWithContext(handler, req, ctx)
}
// makeRequestWithContext executes request with chi routing context for path params
func makeRequestWithContext(handler http.HandlerFunc, req *http.Request) *httptest.ResponseRecorder {
// Set up chi routing context for path params
func makeRequestWithContext(handler http.HandlerFunc, req *http.Request, ctx context.Context) *httptest.ResponseRecorder {
// Set up chi routing context for path params on top of the tx context
rctx := chi.NewRouteContext()
if id, paramName := extractIDFromPath(req.URL.Path); id != "" {
rctx.URLParams.Add(paramName, id)
}
ctx := context.WithValue(req.Context(), chi.RouteCtxKey, rctx)
req = req.WithContext(ctx)
chiCtx := context.WithValue(ctx, chi.RouteCtxKey, rctx)
req = req.WithContext(chiCtx)
w := httptest.NewRecorder()
handler.ServeHTTP(w, req)
@@ -95,9 +95,10 @@ func findLastSegment(path, prefix string) int {
// TestServices_ListAll verifies that listing all services returns only active services,
// filtering out inactive services from the response.
func TestServices_ListAll(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
_, err := db.DB.Exec(context.Background(), `
_, err := tx.Exec(ctx, `
INSERT INTO services (name, description, price, duration_minutes, is_active, minimum_age_required)
VALUES
('Manicure', 'Basic manicure', 25.00, 30, true, 0),
@@ -109,7 +110,7 @@ func TestServices_ListAll(t *testing.T) {
}
handler := http.HandlerFunc(ServicesHandler)
w := makeRequest(handler, "GET", "/api/services", nil)
w := makeRequest(handler, "GET", "/api/services", nil, ctx)
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
@@ -142,15 +143,16 @@ func TestServices_ListAll(t *testing.T) {
// TestServices_EligibleForUser_AgeFilter verifies that eligible services are filtered based on the user's age,
// excluding services with minimum_age_required higher than the user's age.
func TestServices_EligibleForUser_AgeFilter(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
dob := "2006-01-01" // Age 20 in Feb 2026
userID, err := createUserWithDOB(dob)
userID, err := createUserWithDOB(ctx, tx, dob)
if err != nil {
t.Fatalf("failed to create user: %v", err)
}
_, err = db.DB.Exec(context.Background(), `
_, err = tx.Exec(ctx, `
INSERT INTO services (name, description, price, duration_minutes, is_active, minimum_age_required)
VALUES
('Under 18 Service', 'For minors', 20.00, 30, true, 16),
@@ -163,7 +165,7 @@ func TestServices_EligibleForUser_AgeFilter(t *testing.T) {
handler := http.HandlerFunc(ServicesEligibleForUserHandler)
req := httptest.NewRequest("GET", "/api/services/eligible-for/"+userID, nil)
w := makeRequestWithContext(handler, req)
w := makeRequestWithContext(handler, req, ctx)
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
@@ -196,16 +198,17 @@ func TestServices_EligibleForUser_AgeFilter(t *testing.T) {
// TestServices_EligibleForUser_PatchTest verifies that services requiring patch tests include a
// PatchTestStatus field set to 'ok' when the user has completed a valid patch test for that service.
func TestServices_EligibleForUser_PatchTest(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
dob := "2000-01-01"
userID, err := createUserWithDOB(dob)
userID, err := createUserWithDOB(ctx, tx, dob)
if err != nil {
t.Fatalf("failed to create user: %v", err)
}
// Create a regular service (no patch test required)
_, err = db.DB.Exec(context.Background(), `
_, err = tx.Exec(ctx, `
INSERT INTO services (name, description, price, duration_minutes, is_active, minimum_age_required)
VALUES ('Regular Service', 'No patch test needed', 30.00, 30, true, 0)
`)
@@ -215,7 +218,7 @@ func TestServices_EligibleForUser_PatchTest(t *testing.T) {
// Create a service that will require a patch test
var patchTestSvcID string
err = db.DB.QueryRow(context.Background(), `
err = tx.QueryRow(ctx, `
INSERT INTO services (name, description, price, duration_minutes, is_active, minimum_age_required)
VALUES ('Patch Test Required', 'Requires patch test', 75.00, 60, true, 0)
RETURNING id
@@ -226,7 +229,7 @@ func TestServices_EligibleForUser_PatchTest(t *testing.T) {
// Create a patch test that links to this service
var patchTestID string
err = db.DB.QueryRow(context.Background(), `
err = tx.QueryRow(ctx, `
INSERT INTO patch_tests (name, description, notice_duration_hours, expiry_months, service_ids)
VALUES ('Allergy Test', 'Patch test for gel products', 24, 6, $1)
RETURNING id
@@ -236,7 +239,7 @@ func TestServices_EligibleForUser_PatchTest(t *testing.T) {
}
// Create a valid user patch test record (tested 24+ hours ago, within expiry)
_, err = db.DB.Exec(context.Background(), `
_, err = tx.Exec(ctx, `
INSERT INTO user_patch_tests (user_id, patch_test_id, tested_at)
VALUES ($1, $2, NOW() - INTERVAL '48 hours')
`, userID, patchTestID)
@@ -246,7 +249,7 @@ func TestServices_EligibleForUser_PatchTest(t *testing.T) {
handler := http.HandlerFunc(ServicesEligibleForUserHandler)
req := httptest.NewRequest("GET", "/api/services/eligible-for/"+userID, nil)
w := makeRequestWithContext(handler, req)
w := makeRequestWithContext(handler, req, ctx)
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
@@ -290,9 +293,10 @@ func TestServices_EligibleForUser_PatchTest(t *testing.T) {
// TestContact_ReturnsInfo verifies that the contact info endpoint returns the salon's contact
// details (name, phone, email, role) from the first admin user in the database.
func TestContact_ReturnsInfo(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
_, err := db.DB.Exec(context.Background(), `
_, err := tx.Exec(ctx, `
INSERT INTO users (n_first_name, n_last_name, email, phone, date_of_birth, password_hash, account_role, account_type)
VALUES ('John', 'Smith', 'john@test.com', '+447700000001', '1990-01-01', 'hash', 'admin', 'email')
`)
@@ -301,7 +305,7 @@ func TestContact_ReturnsInfo(t *testing.T) {
}
handler := http.HandlerFunc(user.GetContactInfoHandler)
w := makeRequest(handler, "GET", "/api/contact", nil)
w := makeRequest(handler, "GET", "/api/contact", nil, ctx)
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())