//go:build test package admin // Package admin contains tests for admin custom services management endpoints. // // Test Coverage: // - GetCustomServices: GET /api/admin/custom-services - List all custom services // - CreateCustomService: POST /api/admin/custom-services - Create custom service // - GetCustomService: GET /api/admin/custom-services/{id} - Get single custom service // - UpdateCustomService: PUT /api/admin/custom-services/{id} - Update custom service // - PromoteCustomService: POST /api/admin/custom-services/{id}/promote - Promote to regular service // - DeleteCustomService: DELETE /api/admin/custom-services/{id} - Delete custom service // // Authentication: All endpoints require admin role (403 for non-admins). import ( "bytes" "context" "encoding/json" "net/http" "net/http/httptest" "strings" "testing" "crussell/mw" "crussell/testutils" "crussell/testutils/fixtures" "github.com/go-chi/chi/v5" ) // 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. // 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{}, adminID string, ctx context.Context) *httptest.ResponseRecorder { var req *http.Request if body != nil { bodyBytes, _ := json.Marshal(body) req = httptest.NewRequest(method, path, bytes.NewReader(bodyBytes)) req.Header.Set("Content-Type", "application/json") } else { req = httptest.NewRequest(method, path, nil) } rctx := chi.NewRouteContext() if strings.HasPrefix(path, "/api/admin/custom-services/") { suffix := path[len("/api/admin/custom-services/"):] if slashIdx := strings.Index(suffix, "/"); slashIdx >= 0 { rctx.URLParams.Add("id", suffix[:slashIdx]) } else { rctx.URLParams.Add("id", suffix) } } 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) w := httptest.NewRecorder() handler.ServeHTTP(w, req) return w } // ============================================================================= // List Custom Services Tests // ============================================================================= // TestCustomServices_List verifies that an admin can list all custom services // with pagination metadata. func TestCustomServices_List(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) csID1, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service 1: %v", err) } defer fixtures.DeleteCustomService(tx, csID1) csID2, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service 2: %v", err) } defer fixtures.DeleteCustomService(tx, csID2) handler := http.HandlerFunc(GetCustomServices) 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()) } var resp CustomServiceListResponse if err := parseResponseBody(w, &resp); err != nil { t.Fatalf("failed to parse response: %v", err) } if resp.Total != 2 { t.Errorf("expected total 2, got %d", resp.Total) } if len(resp.Services) != 2 { t.Errorf("expected 2 services, got %d", len(resp.Services)) } } // 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) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) csID, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service: %v", err) } defer fixtures.DeleteCustomService(tx, csID) // Set a unique name for search testing _, 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) } handler := http.HandlerFunc(GetCustomServices) // Matching search (case-insensitive) 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()) } var resp CustomServiceListResponse if err := parseResponseBody(w, &resp); err != nil { t.Fatalf("failed to parse response: %v", err) } if len(resp.Services) != 1 { t.Errorf("expected 1 service matching search, got %d", len(resp.Services)) } if resp.Total != 1 { t.Errorf("expected total 1, got %d", resp.Total) } // Non-matching search 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) } if err := parseResponseBody(w, &resp); err != nil { t.Fatalf("failed to parse response: %v", err) } if len(resp.Services) != 0 { t.Errorf("expected 0 services for non-matching search, got %d", len(resp.Services)) } if resp.Total != 0 { t.Errorf("expected total 0, got %d", resp.Total) } } // 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) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) csID1, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service 1: %v", err) } defer fixtures.DeleteCustomService(tx, csID1) csID2, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service 2: %v", err) } defer fixtures.DeleteCustomService(tx, csID2) // Set usage counts via direct DB to have services with usage_count > 0 _, 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, ctx) if w.Code != http.StatusOK { t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String()) } // Popular mode returns a plain array, not the list response struct var services []CustomService if err := parseResponseBody(w, &services); err != nil { t.Fatalf("failed to parse response: %v", err) } if len(services) == 0 { t.Errorf("expected at least 1 popular service, got 0") } // Verify the returned service has usage_count > 0 for _, s := range services { if s.UsageCount <= 0 { t.Errorf("expected usage_count > 0 for popular service %s, got %d", s.ID, s.UsageCount) } } } // TestCustomServices_List_Pagination verifies page and per_page query parameters. func TestCustomServices_List_Pagination(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) // Create 3 custom services csIDs := make([]string, 3) for i := 0; i < 3; i++ { csID, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service %d: %v", i+1, err) } csIDs[i] = csID } defer func() { for _, id := range csIDs { fixtures.DeleteCustomService(tx, id) } }() handler := http.HandlerFunc(GetCustomServices) 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()) } var resp CustomServiceListResponse if err := parseResponseBody(w, &resp); err != nil { t.Fatalf("failed to parse response: %v", err) } if resp.PerPage != 2 { t.Errorf("expected per_page 2, got %d", resp.PerPage) } if resp.Total != 3 { t.Errorf("expected total 3, got %d", resp.Total) } if len(resp.Services) != 2 { t.Errorf("expected 2 services on first page, got %d", len(resp.Services)) } if resp.NextCursor == nil { t.Fatal("expected next_cursor when items remain") } } // ============================================================================= // Create Custom Service Tests // ============================================================================= // 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) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) handler := http.HandlerFunc(CreateCustomService) createReq := CreateCustomServiceRequest{ Name: "Custom French Manicure", Description: stringPtr("A custom french manicure service"), Price: 45.00, DurationMinutes: 60, MinimumAgeRequired: 16, Notes: stringPtr("Custom service notes"), } 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()) } var cs CustomService if err := parseResponseBody(w, &cs); err != nil { t.Fatalf("failed to parse response: %v", err) } if cs.Name != "Custom French Manicure" { t.Errorf("expected name 'Custom French Manicure', got %s", cs.Name) } if cs.Price != 45.00 { t.Errorf("expected price 45.00, got %f", cs.Price) } if cs.DurationMinutes != 60 { t.Errorf("expected duration 60, got %d", cs.DurationMinutes) } if cs.MinimumAgeRequired != 16 { t.Errorf("expected minimum_age_required 16, got %d", cs.MinimumAgeRequired) } if cs.UsageCount != 0 { t.Errorf("expected usage_count 0 for new custom service, got %d", cs.UsageCount) } if cs.ID == "" { t.Error("expected non-empty ID for created custom service") } } // TestCustomServices_Create_Validation verifies that validation errors return // HTTP 400 for various invalid inputs. func TestCustomServices_Create_Validation(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) tests := []struct { name string req CreateCustomServiceRequest }{ { name: "empty name", req: CreateCustomServiceRequest{ Name: "", Price: 50.00, DurationMinutes: 60, }, }, { name: "zero price", req: CreateCustomServiceRequest{ Name: "Test Service", Price: 0, DurationMinutes: 60, }, }, { name: "negative price", req: CreateCustomServiceRequest{ Name: "Test Service", Price: -10.00, DurationMinutes: 60, }, }, { name: "zero duration", req: CreateCustomServiceRequest{ Name: "Test Service", Price: 50.00, DurationMinutes: 0, }, }, { name: "excessive duration", req: CreateCustomServiceRequest{ Name: "Test Service", Price: 50.00, DurationMinutes: 481, }, }, { name: "negative minimum age", req: CreateCustomServiceRequest{ Name: "Test Service", Price: 50.00, DurationMinutes: 60, MinimumAgeRequired: -1, }, }, } 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", ctx) if w.Code != http.StatusBadRequest { t.Errorf("expected status 400, got %d. body: %s", w.Code, w.Body.String()) } }) } } // ============================================================================= // Get Single Custom Service Tests // ============================================================================= // TestCustomServices_Get verifies that an admin can retrieve a single custom service by ID. func TestCustomServices_Get(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) csID, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service: %v", err) } defer fixtures.DeleteCustomService(tx, csID) handler := http.HandlerFunc(GetCustomService) 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()) } var cs CustomService if err := parseResponseBody(w, &cs); err != nil { t.Fatalf("failed to parse response: %v", err) } if cs.ID != csID { t.Errorf("expected ID %s, got %s", csID, cs.ID) } if cs.Name == "" { t.Error("expected non-empty name") } if cs.Price <= 0 { t.Errorf("expected positive price, got %f", cs.Price) } } // TestCustomServices_Get_NotFound verifies that requesting a non-existent custom service returns 404. func TestCustomServices_Get_NotFound(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) handler := http.HandlerFunc(GetCustomService) 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()) } } // ============================================================================= // Update Custom Service Tests // ============================================================================= // TestCustomServices_Update verifies that an admin can update a custom service's fields. func TestCustomServices_Update(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) csID, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service: %v", err) } defer fixtures.DeleteCustomService(tx, csID) newName := "Updated Custom Name" updateReq := UpdateCustomServiceRequest{ Name: &newName, } handler := http.HandlerFunc(UpdateCustomService) 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()) } var resp map[string]string if err := parseResponseBody(w, &resp); err != nil { t.Fatalf("failed to parse response: %v", err) } if resp["message"] != "Custom service updated" { t.Errorf("expected 'Custom service updated' message, got %s", resp["message"]) } // Verify the update persisted var dbName string 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) } if dbName != newName { t.Errorf("expected name '%s' in DB, got %s", newName, dbName) } } // TestCustomServices_Update_NotFound verifies that updating a non-existent custom service returns 404. func TestCustomServices_Update_NotFound(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) newName := "Updated Name" updateReq := UpdateCustomServiceRequest{ Name: &newName, } handler := http.HandlerFunc(UpdateCustomService) 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()) } } // TestCustomServices_Update_NoFields verifies that sending an update with no fields // returns 400 Bad Request. func TestCustomServices_Update_NoFields(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) csID, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service: %v", err) } defer fixtures.DeleteCustomService(tx, csID) updateReq := UpdateCustomServiceRequest{} handler := http.HandlerFunc(UpdateCustomService) 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()) } } // ============================================================================= // Promote Custom Service Tests // ============================================================================= // 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) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) 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, adminID, ctx) if w.Code != http.StatusOK { t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String()) } var resp map[string]string if err := parseResponseBody(w, &resp); err != nil { t.Fatalf("failed to parse response: %v", err) } newServiceID := resp["new_service_id"] if newServiceID == "" { t.Error("expected non-empty new_service_id in response") } if resp["custom_service_id"] != csID { t.Errorf("expected custom_service_id %s, got %s", csID, resp["custom_service_id"]) } // Verify the custom service was deleted var count int 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) } if count != 0 { t.Errorf("expected custom service to be deleted, but it still exists") } // Verify the new regular service was created var serviceName string 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) } if serviceName == "" { t.Error("expected non-empty service name") } // Clean up: delete the promoted service 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) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) handler := http.HandlerFunc(PromoteCustomService) 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()) } } // ============================================================================= // Delete Custom Service Tests // ============================================================================= // TestCustomServices_Delete verifies that an admin can delete an unused custom service. func TestCustomServices_Delete(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) 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, adminID, ctx) if w.Code != http.StatusOK { t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String()) } var resp map[string]string if err := parseResponseBody(w, &resp); err != nil { t.Fatalf("failed to parse response: %v", err) } if resp["message"] != "Custom service deleted" { t.Errorf("expected 'Custom service deleted' message, got %s", resp["message"]) } // Verify it's gone from the DB var count int 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) } if count != 0 { t.Error("expected custom service to be deleted from database") } } // TestCustomServices_Delete_NotFound verifies that deleting a non-existent custom service returns 404. func TestCustomServices_Delete_NotFound(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) handler := http.HandlerFunc(DeleteCustomService) 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()) } } // TestCustomServices_Delete_Conflict verifies that deleting a custom service with // usage_count > 0 returns 409 Conflict. func TestCustomServices_Delete_Conflict(t *testing.T) { ctx, tx := testutils.SetupTestTx(t) adminID, err := fixtures.CreateTestAdminUser(tx) if err != nil { t.Fatalf("failed to create admin user: %v", err) } defer fixtures.DeleteUser(tx, adminID) csID, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service: %v", err) } defer fixtures.DeleteCustomService(tx, csID) // Simulate usage to trigger conflict _, 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, adminID, ctx) if w.Code != http.StatusConflict { t.Errorf("expected status 409, got %d. body: %s", w.Code, w.Body.String()) } } // ============================================================================= // Non-Admin Tests // ============================================================================= // 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) { ctx, tx := testutils.SetupTestTx(t) _, err := fixtures.CreateTestUser(tx) if err != nil { t.Fatalf("failed to create user: %v", err) } userID, err := fixtures.CreateTestUser(tx) if err != nil { t.Fatalf("failed to create test user: %v", err) } defer fixtures.DeleteUser(tx, userID) csID, err := fixtures.CreateTestCustomService(tx) if err != nil { t.Fatalf("failed to create custom service: %v", err) } defer fixtures.DeleteCustomService(tx, csID) // Test LIST 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) } // Test CREATE createReq := CreateCustomServiceRequest{ Name: "Test Service", Price: 50.00, DurationMinutes: 60, } 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, 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, 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, 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, ctx) if w.Code != http.StatusForbidden { t.Errorf("DELETE: expected status 403, got %d", w.Code) } }