Files
Crussell/backend/handlers/admin/bookings_extra_test.go
T
popertotsandSisyphus e4b9003439 refactor(handlers): migrate remaining backend handlers to clock.Now() and transaction patterns
Apply clock.Now() migration, transaction wrapping, and minor refactors across admin, scheduling, today, user, auth handler, notifications, webhooks, services, portfolio, ratelimit, testutils, and main.go.

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

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-06-24 23:43:50 +01:00

148 lines
4.2 KiB
Go

//go:build test
// +build test
package admin
import (
"net/http"
"testing"
"time"
"crussell/clock"
"crussell/testutils"
"crussell/handlers/bookings"
"crussell/testutils/fixtures"
)
// TestGetOverlappingBookingsByTime verifies the new overlapping bookings endpoint
func TestGetOverlappingBookingsByTime(t *testing.T) {
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
_, err := fixtures.CreateTestAdminUser(tx)
if err != nil {
t.Fatalf("failed to create admin user: %v", err)
}
userID, err := fixtures.CreateTestUser(tx)
if err != nil {
t.Fatalf("failed to create test user: %v", err)
}
serviceID, err := fixtures.CreateTestService(tx)
if err != nil {
t.Fatalf("failed to create test service: %v", err)
}
startTime := time.Date(2026, 3, 16, 10, 0, 0, 0, time.UTC)
_, err = fixtures.CreateTestBookingAtTime(tx, userID, serviceID, startTime)
if err != nil {
t.Fatalf("failed to create test booking: %v", err)
}
handler := http.HandlerFunc(bookings.GetOverlappingBookingsByTimeHandler)
w := makeAdminRequest(handler, "GET", "/api/admin/bookings/overlapping?start=2026-03-16T09:00:00Z&end=2026-03-16T11:00:00Z", nil, ctx)
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
}
var resp bookings.OverlappingBookingsResponse
if err := parseResponseBody(w, &resp); err != nil {
t.Fatalf("failed to parse response: %v", err)
}
if len(resp.Bookings) != 1 {
t.Errorf("expected 1 overlapping booking, got %d", len(resp.Bookings))
}
}
// TestGetBookingsByDateRange verifies the new bookings by date range endpoint
func TestGetBookingsByDateRange(t *testing.T) {
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
_, err := fixtures.CreateTestAdminUser(tx)
if err != nil {
t.Fatalf("failed to create admin user: %v", err)
}
userID, err := fixtures.CreateTestUser(tx)
if err != nil {
t.Fatalf("failed to create test user: %v", err)
}
serviceID, err := fixtures.CreateTestService(tx)
if err != nil {
t.Fatalf("failed to create test service: %v", err)
}
startTime := time.Date(2026, 3, 16, 10, 0, 0, 0, time.UTC)
_, err = fixtures.CreateTestBookingAtTime(tx, userID, serviceID, startTime)
if err != nil {
t.Fatalf("failed to create test booking: %v", err)
}
handler := http.HandlerFunc(bookings.GetBookingsByDateRangeHandler)
w := makeAdminRequest(handler, "GET", "/api/admin/bookings/by-date-range?start=2026-03-16&end=2026-03-16", nil, ctx)
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
}
var resp bookings.OverlappingBookingsResponse
if err := parseResponseBody(w, &resp); err != nil {
t.Fatalf("failed to parse response: %v", err)
}
if len(resp.Bookings) != 1 {
t.Errorf("expected 1 booking, got %d", len(resp.Bookings))
}
}
// TestAdminRescheduleBooking verifies the new reschedule endpoint
func TestAdminRescheduleBooking(t *testing.T) {
t.Parallel()
ctx, tx := testutils.SetupTestTx(t)
_, err := fixtures.CreateTestAdminUser(tx)
if err != nil {
t.Fatalf("failed to create admin user: %v", err)
}
userID, err := fixtures.CreateTestUser(tx)
if err != nil {
t.Fatalf("failed to create test user: %v", err)
}
serviceID, err := fixtures.CreateTestService(tx)
if err != nil {
t.Fatalf("failed to create test service: %v", err)
}
startTime := clock.Now().Add(48 * time.Hour).Truncate(time.Second)
bookingID, err := fixtures.CreateTestBookingAtTime(tx, userID, serviceID, startTime)
if err != nil {
t.Fatalf("failed to create test booking: %v", err)
}
newStartTime := startTime.Add(2 * time.Hour)
req := map[string]interface{}{
"start_time": newStartTime.Format(time.RFC3339),
}
handler := http.HandlerFunc(bookings.AdminRescheduleBookingHandler)
w := makeAdminRequest(handler, "PUT", "/api/admin/bookings/"+bookingID+"/reschedule", req, ctx)
if w.Code != http.StatusOK {
t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
}
var dbStartTime time.Time
err = tx.QueryRow(ctx,
"SELECT start_time FROM bookings WHERE id = $1", bookingID).Scan(&dbStartTime)
if err != nil {
t.Fatalf("failed to query booking: %v", err)
}
if !dbStartTime.Truncate(time.Second).Equal(newStartTime.Truncate(time.Second)) {
t.Errorf("expected booking start_time %v, got %v", newStartTime, dbStartTime)
}
}