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:
@@ -24,7 +24,6 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"crussell/db"
|
||||
"crussell/testutils"
|
||||
"crussell/mw"
|
||||
"crussell/testutils/fixtures"
|
||||
@@ -34,11 +33,10 @@ import (
|
||||
|
||||
// testAdminID is set by each test after creating an admin user via fixtures,
|
||||
// so that handlers referencing created_by (which has a FK to users) work correctly.
|
||||
var testAdminID string
|
||||
|
||||
// makeCustomServiceRequest creates an admin request with chi URL params for custom-services paths.
|
||||
// Uses testAdminID (must be set by the calling test).
|
||||
func makeCustomServiceRequest(handler http.Handler, method, path string, body interface{}) *httptest.ResponseRecorder {
|
||||
func makeCustomServiceRequest(handler http.Handler, method, path string, body interface{}, adminID string, ctx context.Context) *httptest.ResponseRecorder {
|
||||
var req *http.Request
|
||||
if body != nil {
|
||||
bodyBytes, _ := json.Marshal(body)
|
||||
@@ -58,8 +56,8 @@ func makeCustomServiceRequest(handler http.Handler, method, path string, body in
|
||||
}
|
||||
}
|
||||
|
||||
ctx := context.WithValue(req.Context(), chi.RouteCtxKey, rctx)
|
||||
ctx = context.WithValue(ctx, mw.UserIDKey, testAdminID)
|
||||
ctx = context.WithValue(ctx, chi.RouteCtxKey, rctx)
|
||||
ctx = context.WithValue(ctx, mw.UserIDKey, adminID)
|
||||
ctx = context.WithValue(ctx, mw.UserRoleKey, "admin")
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
@@ -75,28 +73,28 @@ func makeCustomServiceRequest(handler http.Handler, method, path string, body in
|
||||
// TestCustomServices_List verifies that an admin can list all custom services
|
||||
// with pagination metadata.
|
||||
func TestCustomServices_List(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
csID1, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID1, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service 1: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID1)
|
||||
defer fixtures.DeleteCustomService(tx, csID1)
|
||||
|
||||
csID2, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID2, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service 2: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID2)
|
||||
defer fixtures.DeleteCustomService(tx, csID2)
|
||||
|
||||
handler := http.HandlerFunc(GetCustomServices)
|
||||
w := makeAdminRequest(handler, "GET", "/api/admin/custom-services", nil)
|
||||
w := makeAdminRequest(handler, "GET", "/api/admin/custom-services", nil, ctx)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -119,22 +117,22 @@ func TestCustomServices_List(t *testing.T) {
|
||||
// TestCustomServices_List_Search verifies search filtering via the q parameter,
|
||||
// including case-insensitive matching and no-results scenarios.
|
||||
func TestCustomServices_List_Search(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
csID, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID)
|
||||
defer fixtures.DeleteCustomService(tx, csID)
|
||||
|
||||
// Set a unique name for search testing
|
||||
_, err = db.DB.Exec(context.Background(),
|
||||
_, err = tx.Exec(context.Background(),
|
||||
"UPDATE custom_services SET name = 'SearchableServiceName' WHERE id = $1", csID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to update custom service name: %v", err)
|
||||
@@ -143,7 +141,7 @@ func TestCustomServices_List_Search(t *testing.T) {
|
||||
handler := http.HandlerFunc(GetCustomServices)
|
||||
|
||||
// Matching search (case-insensitive)
|
||||
w := makeAdminRequest(handler, "GET", "/api/admin/custom-services?q=searchableservicename", nil)
|
||||
w := makeAdminRequest(handler, "GET", "/api/admin/custom-services?q=searchableservicename", nil, ctx)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
@@ -162,7 +160,7 @@ func TestCustomServices_List_Search(t *testing.T) {
|
||||
}
|
||||
|
||||
// Non-matching search
|
||||
w = makeAdminRequest(handler, "GET", "/api/admin/custom-services?q=NONEXISTENT_QUERY_XYZ", nil)
|
||||
w = makeAdminRequest(handler, "GET", "/api/admin/custom-services?q=NONEXISTENT_QUERY_XYZ", nil, ctx)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d", w.Code)
|
||||
}
|
||||
@@ -183,35 +181,35 @@ func TestCustomServices_List_Search(t *testing.T) {
|
||||
// TestCustomServices_List_Popular verifies the popular flag returns custom services
|
||||
// ordered by usage_count, limited to the specified number.
|
||||
func TestCustomServices_List_Popular(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
csID1, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID1, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service 1: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID1)
|
||||
defer fixtures.DeleteCustomService(tx, csID1)
|
||||
|
||||
csID2, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID2, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service 2: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID2)
|
||||
defer fixtures.DeleteCustomService(tx, csID2)
|
||||
|
||||
// Set usage counts via direct DB to have services with usage_count > 0
|
||||
_, err = db.DB.Exec(context.Background(),
|
||||
_, err = tx.Exec(context.Background(),
|
||||
"UPDATE custom_services SET usage_count = 5, last_used_at = NOW() WHERE id = $1", csID1)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set usage count: %v", err)
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(GetCustomServices)
|
||||
w := makeAdminRequest(handler, "GET", "/api/admin/custom-services?popular=3", nil)
|
||||
w := makeAdminRequest(handler, "GET", "/api/admin/custom-services?popular=3", nil, ctx)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -237,18 +235,18 @@ func TestCustomServices_List_Popular(t *testing.T) {
|
||||
|
||||
// TestCustomServices_List_Pagination verifies page and per_page query parameters.
|
||||
func TestCustomServices_List_Pagination(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
// Create 3 custom services
|
||||
csIDs := make([]string, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
csID, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service %d: %v", i+1, err)
|
||||
}
|
||||
@@ -256,13 +254,13 @@ func TestCustomServices_List_Pagination(t *testing.T) {
|
||||
}
|
||||
defer func() {
|
||||
for _, id := range csIDs {
|
||||
fixtures.DeleteCustomService(db.DB, id)
|
||||
fixtures.DeleteCustomService(tx, id)
|
||||
}
|
||||
}()
|
||||
|
||||
handler := http.HandlerFunc(GetCustomServices)
|
||||
|
||||
w := makeAdminRequest(handler, "GET", "/api/admin/custom-services?per_page=2", nil)
|
||||
w := makeAdminRequest(handler, "GET", "/api/admin/custom-services?per_page=2", nil, ctx)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
}
|
||||
@@ -296,13 +294,13 @@ func TestCustomServices_List_Pagination(t *testing.T) {
|
||||
// TestCustomServices_Create verifies that an admin can create a new custom service
|
||||
// with name, description, price, duration, minimum age, and notes.
|
||||
func TestCustomServices_Create(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
handler := http.HandlerFunc(CreateCustomService)
|
||||
|
||||
@@ -315,7 +313,7 @@ func TestCustomServices_Create(t *testing.T) {
|
||||
Notes: stringPtr("Custom service notes"),
|
||||
}
|
||||
|
||||
w := makeRequestWithContext(handler, "POST", "/api/admin/custom-services", createReq, adminID, "admin")
|
||||
w := makeRequestWithContext(handler, "POST", "/api/admin/custom-services", createReq, adminID, "admin", ctx)
|
||||
|
||||
if w.Code != http.StatusCreated {
|
||||
t.Errorf("expected status 201, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -354,13 +352,13 @@ func TestCustomServices_Create(t *testing.T) {
|
||||
// TestCustomServices_Create_Validation verifies that validation errors return
|
||||
// HTTP 400 for various invalid inputs.
|
||||
func TestCustomServices_Create_Validation(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -420,7 +418,7 @@ func TestCustomServices_Create_Validation(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
handler := http.HandlerFunc(CreateCustomService)
|
||||
w := makeRequestWithContext(handler, "POST", "/api/admin/custom-services", tt.req, adminID, "admin")
|
||||
w := makeRequestWithContext(handler, "POST", "/api/admin/custom-services", tt.req, adminID, "admin", ctx)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("expected status 400, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -435,23 +433,22 @@ func TestCustomServices_Create_Validation(t *testing.T) {
|
||||
|
||||
// TestCustomServices_Get verifies that an admin can retrieve a single custom service by ID.
|
||||
func TestCustomServices_Get(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
csID, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID)
|
||||
defer fixtures.DeleteCustomService(tx, csID)
|
||||
|
||||
handler := http.HandlerFunc(GetCustomService)
|
||||
w := makeCustomServiceRequest(handler, "GET", "/api/admin/custom-services/"+csID, nil)
|
||||
w := makeCustomServiceRequest(handler, "GET", "/api/admin/custom-services/"+csID, nil, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -477,17 +474,16 @@ func TestCustomServices_Get(t *testing.T) {
|
||||
|
||||
// TestCustomServices_Get_NotFound verifies that requesting a non-existent custom service returns 404.
|
||||
func TestCustomServices_Get_NotFound(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
handler := http.HandlerFunc(GetCustomService)
|
||||
w := makeCustomServiceRequest(handler, "GET", "/api/admin/custom-services/nonexistent-id", nil)
|
||||
w := makeCustomServiceRequest(handler, "GET", "/api/admin/custom-services/nonexistent-id", nil, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("expected status 404, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -500,20 +496,19 @@ func TestCustomServices_Get_NotFound(t *testing.T) {
|
||||
|
||||
// TestCustomServices_Update verifies that an admin can update a custom service's fields.
|
||||
func TestCustomServices_Update(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
csID, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID)
|
||||
defer fixtures.DeleteCustomService(tx, csID)
|
||||
|
||||
newName := "Updated Custom Name"
|
||||
updateReq := UpdateCustomServiceRequest{
|
||||
@@ -521,7 +516,7 @@ func TestCustomServices_Update(t *testing.T) {
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(UpdateCustomService)
|
||||
w := makeCustomServiceRequest(handler, "PUT", "/api/admin/custom-services/"+csID, updateReq)
|
||||
w := makeCustomServiceRequest(handler, "PUT", "/api/admin/custom-services/"+csID, updateReq, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -538,7 +533,7 @@ func TestCustomServices_Update(t *testing.T) {
|
||||
|
||||
// Verify the update persisted
|
||||
var dbName string
|
||||
err = db.DB.QueryRow(context.Background(),
|
||||
err = tx.QueryRow(context.Background(),
|
||||
"SELECT name FROM custom_services WHERE id = $1", csID).Scan(&dbName)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to query custom service: %v", err)
|
||||
@@ -551,14 +546,13 @@ func TestCustomServices_Update(t *testing.T) {
|
||||
|
||||
// TestCustomServices_Update_NotFound verifies that updating a non-existent custom service returns 404.
|
||||
func TestCustomServices_Update_NotFound(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
newName := "Updated Name"
|
||||
updateReq := UpdateCustomServiceRequest{
|
||||
@@ -566,7 +560,7 @@ func TestCustomServices_Update_NotFound(t *testing.T) {
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(UpdateCustomService)
|
||||
w := makeCustomServiceRequest(handler, "PUT", "/api/admin/custom-services/nonexistent-id", updateReq)
|
||||
w := makeCustomServiceRequest(handler, "PUT", "/api/admin/custom-services/nonexistent-id", updateReq, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("expected status 404, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -576,25 +570,24 @@ func TestCustomServices_Update_NotFound(t *testing.T) {
|
||||
// TestCustomServices_Update_NoFields verifies that sending an update with no fields
|
||||
// returns 400 Bad Request.
|
||||
func TestCustomServices_Update_NoFields(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
csID, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID)
|
||||
defer fixtures.DeleteCustomService(tx, csID)
|
||||
|
||||
updateReq := UpdateCustomServiceRequest{}
|
||||
|
||||
handler := http.HandlerFunc(UpdateCustomService)
|
||||
w := makeCustomServiceRequest(handler, "PUT", "/api/admin/custom-services/"+csID, updateReq)
|
||||
w := makeCustomServiceRequest(handler, "PUT", "/api/admin/custom-services/"+csID, updateReq, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Errorf("expected status 400, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -608,22 +601,21 @@ func TestCustomServices_Update_NoFields(t *testing.T) {
|
||||
// TestCustomServices_Promote verifies that promoting a custom service creates a
|
||||
// regular service, migrates data, and deletes the original custom service.
|
||||
func TestCustomServices_Promote(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
csID, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service: %v", err)
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(PromoteCustomService)
|
||||
w := makeCustomServiceRequest(handler, "POST", "/api/admin/custom-services/"+csID+"/promote", nil)
|
||||
w := makeCustomServiceRequest(handler, "POST", "/api/admin/custom-services/"+csID+"/promote", nil, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -645,7 +637,7 @@ func TestCustomServices_Promote(t *testing.T) {
|
||||
|
||||
// Verify the custom service was deleted
|
||||
var count int
|
||||
err = db.DB.QueryRow(context.Background(),
|
||||
err = tx.QueryRow(context.Background(),
|
||||
"SELECT COUNT(*) FROM custom_services WHERE id = $1", csID).Scan(&count)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to query custom service: %v", err)
|
||||
@@ -656,7 +648,7 @@ func TestCustomServices_Promote(t *testing.T) {
|
||||
|
||||
// Verify the new regular service was created
|
||||
var serviceName string
|
||||
err = db.DB.QueryRow(context.Background(),
|
||||
err = tx.QueryRow(context.Background(),
|
||||
"SELECT name FROM services WHERE id = $1", newServiceID).Scan(&serviceName)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to query promoted service: %v", err)
|
||||
@@ -666,22 +658,21 @@ func TestCustomServices_Promote(t *testing.T) {
|
||||
}
|
||||
|
||||
// Clean up: delete the promoted service
|
||||
defer fixtures.DeleteService(db.DB, newServiceID)
|
||||
defer fixtures.DeleteService(tx, newServiceID)
|
||||
}
|
||||
|
||||
// TestCustomServices_Promote_NotFound verifies that promoting a non-existent custom service returns 404.
|
||||
func TestCustomServices_Promote_NotFound(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
handler := http.HandlerFunc(PromoteCustomService)
|
||||
w := makeCustomServiceRequest(handler, "POST", "/api/admin/custom-services/nonexistent-id/promote", nil)
|
||||
w := makeCustomServiceRequest(handler, "POST", "/api/admin/custom-services/nonexistent-id/promote", nil, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("expected status 404, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -694,22 +685,21 @@ func TestCustomServices_Promote_NotFound(t *testing.T) {
|
||||
|
||||
// TestCustomServices_Delete verifies that an admin can delete an unused custom service.
|
||||
func TestCustomServices_Delete(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
csID, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service: %v", err)
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(DeleteCustomService)
|
||||
w := makeCustomServiceRequest(handler, "DELETE", "/api/admin/custom-services/"+csID, nil)
|
||||
w := makeCustomServiceRequest(handler, "DELETE", "/api/admin/custom-services/"+csID, nil, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -726,7 +716,7 @@ func TestCustomServices_Delete(t *testing.T) {
|
||||
|
||||
// Verify it's gone from the DB
|
||||
var count int
|
||||
err = db.DB.QueryRow(context.Background(),
|
||||
err = tx.QueryRow(context.Background(),
|
||||
"SELECT COUNT(*) FROM custom_services WHERE id = $1", csID).Scan(&count)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to query custom service: %v", err)
|
||||
@@ -738,17 +728,16 @@ func TestCustomServices_Delete(t *testing.T) {
|
||||
|
||||
// TestCustomServices_Delete_NotFound verifies that deleting a non-existent custom service returns 404.
|
||||
func TestCustomServices_Delete_NotFound(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
handler := http.HandlerFunc(DeleteCustomService)
|
||||
w := makeCustomServiceRequest(handler, "DELETE", "/api/admin/custom-services/nonexistent-id", nil)
|
||||
w := makeCustomServiceRequest(handler, "DELETE", "/api/admin/custom-services/nonexistent-id", nil, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("expected status 404, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -758,30 +747,29 @@ func TestCustomServices_Delete_NotFound(t *testing.T) {
|
||||
// TestCustomServices_Delete_Conflict verifies that deleting a custom service with
|
||||
// usage_count > 0 returns 409 Conflict.
|
||||
func TestCustomServices_Delete_Conflict(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
adminID, err := fixtures.CreateTestAdminUser(db.DB)
|
||||
adminID, err := fixtures.CreateTestAdminUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create admin user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, adminID)
|
||||
testAdminID = adminID
|
||||
defer fixtures.DeleteUser(tx, adminID)
|
||||
|
||||
csID, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID)
|
||||
defer fixtures.DeleteCustomService(tx, csID)
|
||||
|
||||
// Simulate usage to trigger conflict
|
||||
_, err = db.DB.Exec(context.Background(),
|
||||
_, err = tx.Exec(context.Background(),
|
||||
"UPDATE custom_services SET usage_count = 3 WHERE id = $1", csID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to set usage count: %v", err)
|
||||
}
|
||||
|
||||
handler := http.HandlerFunc(DeleteCustomService)
|
||||
w := makeCustomServiceRequest(handler, "DELETE", "/api/admin/custom-services/"+csID, nil)
|
||||
w := makeCustomServiceRequest(handler, "DELETE", "/api/admin/custom-services/"+csID, nil, adminID, ctx)
|
||||
|
||||
if w.Code != http.StatusConflict {
|
||||
t.Errorf("expected status 409, got %d. body: %s", w.Code, w.Body.String())
|
||||
@@ -795,27 +783,27 @@ func TestCustomServices_Delete_Conflict(t *testing.T) {
|
||||
// TestCustomServices_NonAdmin verifies that non-admin users receive HTTP 403
|
||||
// Forbidden when attempting to access any admin custom services endpoint.
|
||||
func TestCustomServices_NonAdmin(t *testing.T) {
|
||||
testutils.SetupTestDB(t)
|
||||
ctx, tx := testutils.SetupTestTx(t)
|
||||
|
||||
_, err := fixtures.CreateTestUser(db.DB)
|
||||
_, err := fixtures.CreateTestUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create user: %v", err)
|
||||
}
|
||||
|
||||
userID, err := fixtures.CreateTestUser(db.DB)
|
||||
userID, err := fixtures.CreateTestUser(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create test user: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteUser(db.DB, userID)
|
||||
defer fixtures.DeleteUser(tx, userID)
|
||||
|
||||
csID, err := fixtures.CreateTestCustomService(db.DB)
|
||||
csID, err := fixtures.CreateTestCustomService(tx)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create custom service: %v", err)
|
||||
}
|
||||
defer fixtures.DeleteCustomService(db.DB, csID)
|
||||
defer fixtures.DeleteCustomService(tx, csID)
|
||||
|
||||
// Test LIST
|
||||
w := makeUserRequest(mw.RequireAdmin(http.HandlerFunc(GetCustomServices)), "GET", "/api/admin/custom-services", nil)
|
||||
w := makeUserRequest(mw.RequireAdmin(http.HandlerFunc(GetCustomServices)), "GET", "/api/admin/custom-services", nil, ctx)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("LIST: expected status 403, got %d", w.Code)
|
||||
}
|
||||
@@ -826,32 +814,32 @@ func TestCustomServices_NonAdmin(t *testing.T) {
|
||||
Price: 50.00,
|
||||
DurationMinutes: 60,
|
||||
}
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(CreateCustomService)), "POST", "/api/admin/custom-services", createReq)
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(CreateCustomService)), "POST", "/api/admin/custom-services", createReq, ctx)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("CREATE: expected status 403, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Test GET
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(GetCustomService)), "GET", "/api/admin/custom-services/"+csID, nil)
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(GetCustomService)), "GET", "/api/admin/custom-services/"+csID, nil, ctx)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("GET: expected status 403, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Test UPDATE
|
||||
updateReq := UpdateCustomServiceRequest{}
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(UpdateCustomService)), "PUT", "/api/admin/custom-services/"+csID, updateReq)
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(UpdateCustomService)), "PUT", "/api/admin/custom-services/"+csID, updateReq, ctx)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("UPDATE: expected status 403, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Test PROMOTE
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(PromoteCustomService)), "POST", "/api/admin/custom-services/"+csID+"/promote", nil)
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(PromoteCustomService)), "POST", "/api/admin/custom-services/"+csID+"/promote", nil, ctx)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("PROMOTE: expected status 403, got %d", w.Code)
|
||||
}
|
||||
|
||||
// Test DELETE
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(DeleteCustomService)), "DELETE", "/api/admin/custom-services/"+csID, nil)
|
||||
w = makeUserRequest(mw.RequireAdmin(http.HandlerFunc(DeleteCustomService)), "DELETE", "/api/admin/custom-services/"+csID, nil, ctx)
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Errorf("DELETE: expected status 403, got %d", w.Code)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user