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
+2 -1
View File
@@ -14,8 +14,9 @@ import (
func TestMain(m *testing.M) {
pool := testdb.CreateTestDatabase("crussell_test_handlers_today")
db.DB = pool
db.Conn = db.NewPoolProxy(pool)
jwt.Init()
testdb.SeedBaseline(pool)
code := m.Run()
testdb.DestroyTestDatabase(pool, "crussell_test_handlers_today")
os.Exit(code)
+56 -39
View File
@@ -9,16 +9,17 @@ import (
"net/http"
"net/http/httptest"
"testing"
"time"
"crussell/db"
"crussell/testutils"
"crussell/testutils/fixtures"
)
func createTodayService(t *testing.T) string {
func createTodayService(t *testing.T, ctx context.Context, q db.Querier) string {
t.Helper()
var svcID string
err := db.DB.QueryRow(context.Background(), `
err := q.QueryRow(ctx, `
INSERT INTO services (name, description, price, duration_minutes, is_active, minimum_age_required)
VALUES ('Test Service', 'Description', 50.00, 60, true, 16)
RETURNING id
@@ -29,9 +30,9 @@ func createTodayService(t *testing.T) string {
return svcID
}
func addBookingService(t *testing.T, bookingID, serviceID string) {
func addBookingService(t *testing.T, ctx context.Context, q db.Querier, bookingID, serviceID string) {
t.Helper()
_, err := db.DB.Exec(context.Background(), `
_, err := q.Exec(ctx, `
INSERT INTO booking_services (booking_id, service_id)
VALUES ($1, $2)
`, bookingID, serviceID)
@@ -41,20 +42,21 @@ func addBookingService(t *testing.T, bookingID, serviceID string) {
}
func TestGetTodayAppointments_ShowsPreviousNameInAppointment(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
userID, err := fixtures.CreateTestUser(db.DB)
userID, err := fixtures.CreateTestUser(tx)
if err != nil {
t.Fatalf("failed to create user: %v", err)
}
var origFirstName, origLastName string
err = db.DB.QueryRow(context.Background(), `SELECT n_first_name, n_last_name FROM users WHERE id = $1`, userID).Scan(&origFirstName, &origLastName)
err = tx.QueryRow(ctx, `SELECT n_first_name, n_last_name FROM users WHERE id = $1`, userID).Scan(&origFirstName, &origLastName)
if err != nil {
t.Fatalf("failed to query user name: %v", err)
}
_, err = db.DB.Exec(context.Background(), `
_, err = tx.Exec(ctx, `
INSERT INTO name_history (user_id, previous_first_name, previous_last_name)
VALUES ($1, 'OldFirst', 'OldLast')
`, userID)
@@ -62,20 +64,23 @@ func TestGetTodayAppointments_ShowsPreviousNameInAppointment(t *testing.T) {
t.Fatalf("failed to insert name_history: %v", err)
}
svcID := createTodayService(t)
svcID := createTodayService(t, ctx, tx)
var bookingID string
err = db.DB.QueryRow(context.Background(), `
now := time.Now()
bookingStart := time.Date(now.Year(), now.Month(), now.Day(), 10, 0, 0, 0, now.Location())
err = tx.QueryRow(ctx, `
INSERT INTO bookings (user_id, start_time, status)
VALUES ($1, NOW() + INTERVAL '5 minutes', 'in_progress')
VALUES ($1, $2, 'in_progress')
RETURNING id
`, userID).Scan(&bookingID)
`, userID, bookingStart).Scan(&bookingID)
if err != nil {
t.Fatalf("failed to create booking: %v", err)
}
addBookingService(t, bookingID, svcID)
addBookingService(t, ctx, tx, bookingID, svcID)
req := httptest.NewRequest(http.MethodGet, "/api/admin/today/appointments", nil)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
GetTodayAppointmentsHandler(rr, req)
@@ -110,23 +115,25 @@ func TestGetTodayAppointments_ShowsPreviousNameInAppointment(t *testing.T) {
}
func TestGetTodayAppointments_OmitsPreviousNameWhenNoHistory(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
userID, err := fixtures.CreateTestUser(db.DB)
userID, err := fixtures.CreateTestUser(tx)
if err != nil {
t.Fatalf("failed to create user: %v", err)
}
svcID := createTodayService(t)
svcID := createTodayService(t, ctx, tx)
var bookingID string
err = db.DB.QueryRow(context.Background(), `
err = tx.QueryRow(ctx, `
INSERT INTO bookings (user_id, start_time, status)
VALUES ($1, NOW() + INTERVAL '5 minutes', 'in_progress')
RETURNING id
`, userID).Scan(&bookingID)
addBookingService(t, bookingID, svcID)
addBookingService(t, ctx, tx, bookingID, svcID)
req := httptest.NewRequest(http.MethodGet, "/api/admin/today/appointments", nil)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
GetTodayAppointmentsHandler(rr, req)
@@ -152,9 +159,11 @@ func TestGetTodayAppointments_OmitsPreviousNameWhenNoHistory(t *testing.T) {
}
func TestGetTodayAppointments_Empty(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, _ := testutils.SetupTestTx(t)
req := httptest.NewRequest(http.MethodGet, "/api/admin/today/appointments", nil)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
GetTodayAppointmentsHandler(rr, req)
@@ -176,20 +185,21 @@ func TestGetTodayAppointments_Empty(t *testing.T) {
}
func TestGetPendingApprovals_ShowsPreviousName(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
userID, err := fixtures.CreateTestUser(db.DB)
userID, err := fixtures.CreateTestUser(tx)
if err != nil {
t.Fatalf("failed to create user: %v", err)
}
var origFirstName, origLastName string
err = db.DB.QueryRow(context.Background(), `SELECT n_first_name, n_last_name FROM users WHERE id = $1`, userID).Scan(&origFirstName, &origLastName)
err = tx.QueryRow(ctx, `SELECT n_first_name, n_last_name FROM users WHERE id = $1`, userID).Scan(&origFirstName, &origLastName)
if err != nil {
t.Fatalf("failed to query user name: %v", err)
}
_, err = db.DB.Exec(context.Background(), `
_, err = tx.Exec(ctx, `
INSERT INTO name_history (user_id, previous_first_name, previous_last_name)
VALUES ($1, 'OldFirst', 'OldLast')
`, userID)
@@ -197,9 +207,9 @@ func TestGetPendingApprovals_ShowsPreviousName(t *testing.T) {
t.Fatalf("failed to insert name_history: %v", err)
}
svcID := createTodayService(t)
svcID := createTodayService(t, ctx, tx)
var bookingID string
err = db.DB.QueryRow(context.Background(), `
err = tx.QueryRow(ctx, `
INSERT INTO bookings (user_id, start_time, status)
VALUES ($1, NOW() + INTERVAL '1 day', 'pending')
RETURNING id
@@ -207,9 +217,10 @@ func TestGetPendingApprovals_ShowsPreviousName(t *testing.T) {
if err != nil {
t.Fatalf("failed to create booking: %v", err)
}
addBookingService(t, bookingID, svcID)
addBookingService(t, ctx, tx, bookingID, svcID)
req := httptest.NewRequest(http.MethodGet, "/api/admin/today/pending-approvals", nil)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
GetPendingApprovalsHandler(rr, req)
@@ -244,23 +255,25 @@ func TestGetPendingApprovals_ShowsPreviousName(t *testing.T) {
}
func TestGetPendingApprovals_OmitsPreviousNameWhenNoHistory(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
userID, err := fixtures.CreateTestUser(db.DB)
userID, err := fixtures.CreateTestUser(tx)
if err != nil {
t.Fatalf("failed to create user: %v", err)
}
svcID := createTodayService(t)
svcID := createTodayService(t, ctx, tx)
var bookingID string
err = db.DB.QueryRow(context.Background(), `
err = tx.QueryRow(ctx, `
INSERT INTO bookings (user_id, start_time, status)
VALUES ($1, NOW() + INTERVAL '1 day', 'pending')
RETURNING id
`, userID).Scan(&bookingID)
addBookingService(t, bookingID, svcID)
addBookingService(t, ctx, tx, bookingID, svcID)
req := httptest.NewRequest(http.MethodGet, "/api/admin/today/pending-approvals", nil)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
GetPendingApprovalsHandler(rr, req)
@@ -286,9 +299,11 @@ func TestGetPendingApprovals_OmitsPreviousNameWhenNoHistory(t *testing.T) {
}
func TestGetPendingApprovals_Empty(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, _ := testutils.SetupTestTx(t)
req := httptest.NewRequest(http.MethodGet, "/api/admin/today/pending-approvals", nil)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
GetPendingApprovalsHandler(rr, req)
@@ -307,14 +322,15 @@ func TestGetPendingApprovals_Empty(t *testing.T) {
}
func TestGetCurrentNext_ShowsPreviousNameInAppointment(t *testing.T) {
testutils.SetupTestDB(t)
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
userID, err := fixtures.CreateTestUser(db.DB)
userID, err := fixtures.CreateTestUser(tx)
if err != nil {
t.Fatalf("failed to create user: %v", err)
}
_, err = db.DB.Exec(context.Background(), `
_, err = tx.Exec(ctx, `
INSERT INTO name_history (user_id, previous_first_name, previous_last_name)
VALUES ($1, 'OldFirst', 'OldLast')
`, userID)
@@ -322,11 +338,11 @@ func TestGetCurrentNext_ShowsPreviousNameInAppointment(t *testing.T) {
t.Fatalf("failed to insert name_history: %v", err)
}
svcID := createTodayService(t)
svcID := createTodayService(t, ctx, tx)
// Ensure working hours for all weekdays
for wd := 0; wd <= 6; wd++ {
db.DB.Exec(context.Background(), `
tx.Exec(ctx, `
INSERT INTO working_hours (weekday, start_time, end_time, is_open)
VALUES ($1, '09:00', '17:00', true)
ON CONFLICT (weekday) DO UPDATE SET start_time = '09:00', end_time = '17:00', is_open = true
@@ -334,7 +350,7 @@ func TestGetCurrentNext_ShowsPreviousNameInAppointment(t *testing.T) {
}
var bookingID2 string
err = db.DB.QueryRow(context.Background(), `
err = tx.QueryRow(ctx, `
INSERT INTO bookings (user_id, start_time, status)
VALUES ($1, NOW(), 'confirmed')
RETURNING id
@@ -342,9 +358,10 @@ func TestGetCurrentNext_ShowsPreviousNameInAppointment(t *testing.T) {
if err != nil {
t.Fatalf("failed to create booking: %v", err)
}
addBookingService(t, bookingID2, svcID)
addBookingService(t, ctx, tx, bookingID2, svcID)
req := httptest.NewRequest(http.MethodGet, "/api/admin/today/current-next", nil)
req = req.WithContext(ctx)
rr := httptest.NewRecorder()
GetCurrentAndNextHandler(rr, req)