mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-10-28 15:51:15 +00:00
- Finish Paddle-to-Stripe billing migration; drop paddle/stripe libs - Renumber migrations; add 00012 memberships+manage_token, 00013 location_type_capacity - Add tests: admin, auth, bookings customer service - Remove graphify-out artifacts and stale env files Authored By: TDvorak <[email protected]> Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
114 lines
4.0 KiB
Go
114 lines
4.0 KiB
Go
package bookings
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"bookra/apps/backend/internal/db"
|
|
"bookra/apps/backend/internal/domain"
|
|
)
|
|
|
|
func newBookingFixture(t *testing.T, repo *db.MemoryRepository) db.BookingRecord {
|
|
t.Helper()
|
|
created, err := repo.CreateBooking(context.Background(), db.CreateBookingParams{
|
|
TenantID: "5d6b3551-0a3e-4b86-bdf0-e9df20a47148",
|
|
CustomerName: "Test Customer",
|
|
CustomerEmail: "[email protected]",
|
|
StartsAt: time.Now().Add(24 * time.Hour),
|
|
EndsAt: time.Now().Add(25 * time.Hour),
|
|
Status: "confirmed",
|
|
Reference: "BOK-TEST-1",
|
|
ManageToken: "secret-manage-token",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("create booking: %v", err)
|
|
}
|
|
booking, err := repo.GetBookingByReference(context.Background(), created.Reference)
|
|
if err != nil {
|
|
t.Fatalf("get booking: %v", err)
|
|
}
|
|
return booking
|
|
}
|
|
|
|
func TestGetBookingRequiresManageToken(t *testing.T) {
|
|
repo := db.NewMemoryRepository()
|
|
booking := newBookingFixture(t, repo)
|
|
svc := NewCustomerService(repo, nil, "http://localhost:3000")
|
|
|
|
if _, err := svc.GetBookingByReference(context.Background(), booking.Reference, ""); err != ErrUnauthorized {
|
|
t.Fatalf("expected ErrUnauthorized for missing token, got %v", err)
|
|
}
|
|
if _, err := svc.GetBookingByReference(context.Background(), booking.Reference, "wrong"); err != ErrUnauthorized {
|
|
t.Fatalf("expected ErrUnauthorized for wrong token, got %v", err)
|
|
}
|
|
view, err := svc.GetBookingByReference(context.Background(), booking.Reference, "secret-manage-token")
|
|
if err != nil {
|
|
t.Fatalf("expected authorized view, got %v", err)
|
|
}
|
|
if view.Reference != booking.Reference {
|
|
t.Fatalf("expected reference %s, got %s", booking.Reference, view.Reference)
|
|
}
|
|
}
|
|
|
|
func TestRescheduleRequiresManageToken(t *testing.T) {
|
|
repo := db.NewMemoryRepository()
|
|
booking := newBookingFixture(t, repo)
|
|
svc := NewCustomerService(repo, nil, "http://localhost:3000")
|
|
|
|
req := domain.RescheduleBookingRequest{
|
|
NewStartsAt: time.Now().Add(48 * time.Hour).Format(time.RFC3339),
|
|
NewEndsAt: time.Now().Add(49 * time.Hour).Format(time.RFC3339),
|
|
}
|
|
if err := svc.RescheduleBooking(context.Background(), booking.Reference, req, ""); err != ErrUnauthorized {
|
|
t.Fatalf("expected ErrUnauthorized, got %v", err)
|
|
}
|
|
if err := svc.RescheduleBooking(context.Background(), booking.Reference, req, "wrong"); err != ErrUnauthorized {
|
|
t.Fatalf("expected ErrUnauthorized, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCancelRequiresManageToken(t *testing.T) {
|
|
repo := db.NewMemoryRepository()
|
|
booking := newBookingFixture(t, repo)
|
|
svc := NewCustomerService(repo, nil, "http://localhost:3000")
|
|
|
|
if err := svc.CancelBooking(context.Background(), booking.Reference, ""); err != ErrUnauthorized {
|
|
t.Fatalf("expected ErrUnauthorized, got %v", err)
|
|
}
|
|
if err := svc.CancelBooking(context.Background(), booking.Reference, "wrong"); err != ErrUnauthorized {
|
|
t.Fatalf("expected ErrUnauthorized, got %v", err)
|
|
}
|
|
if err := svc.CancelBooking(context.Background(), booking.Reference, "secret-manage-token"); err != nil {
|
|
t.Fatalf("expected successful cancel, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestRescheduleRejectsConflictingSlot(t *testing.T) {
|
|
repo := db.NewMemoryRepository()
|
|
svc := NewCustomerService(repo, nil, "http://localhost:3000")
|
|
base := time.Now().Add(48 * time.Hour)
|
|
|
|
// Existing booking in the same tenant occupying the target slot.
|
|
_, err := repo.CreateBooking(context.Background(), db.CreateBookingParams{
|
|
TenantID: "5d6b3551-0a3e-4b86-bdf0-e9df20a47148",
|
|
StartsAt: base,
|
|
EndsAt: base.Add(time.Hour),
|
|
Status: "confirmed",
|
|
Reference: "BOK-OCCUPIED",
|
|
ManageToken: "token-a",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("create occupying booking: %v", err)
|
|
}
|
|
|
|
booking := newBookingFixture(t, repo)
|
|
err = svc.RescheduleBooking(context.Background(), booking.Reference, domain.RescheduleBookingRequest{
|
|
NewStartsAt: base.Add(30 * time.Minute).Format(time.RFC3339), // overlaps BOK-OCCUPIED
|
|
NewEndsAt: base.Add(90 * time.Minute).Format(time.RFC3339),
|
|
}, "secret-manage-token")
|
|
if err != ErrBookingConflict {
|
|
t.Fatalf("expected ErrBookingConflict, got %v", err)
|
|
}
|
|
}
|