Added tests, shift 'delete'. Fixed overnight shifts, sync, error handling.
This commit is contained in:
parent
9d0fa1f0af
commit
f9c4facad6
21 changed files with 2522 additions and 40 deletions
167
handle_kiosk_test.go
Normal file
167
handle_kiosk_test.go
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func setupKiosk(t *testing.T) (*App, *http.ServeMux, string) {
|
||||
t.Helper()
|
||||
app := testApp(t)
|
||||
mux := testMux(app)
|
||||
|
||||
dept, _ := app.createDepartment(Department{Name: "Gate"})
|
||||
deptID := dept.ID
|
||||
|
||||
// Create attendee with token
|
||||
a, _ := app.createAttendee(Attendee{Name: "Titania", Email: "titania@test.com"})
|
||||
token, _ := app.generateUniqueToken()
|
||||
app.db.Exec(`UPDATE attendees SET volunteer_token = ? WHERE id = ?`, token, a.ID)
|
||||
|
||||
// Create linked volunteer
|
||||
app.createVolunteer(Volunteer{Name: "Titania", AttendeeID: &a.ID, DepartmentID: &deptID})
|
||||
|
||||
// Create shifts
|
||||
app.createShift(Shift{DepartmentID: deptID, Name: "Morning", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00", Capacity: 2})
|
||||
app.createShift(Shift{DepartmentID: deptID, Name: "Afternoon", Day: "2026-03-15", StartTime: "14:00", EndTime: "18:00", Capacity: 1})
|
||||
|
||||
return app, mux, token
|
||||
}
|
||||
|
||||
func TestKioskGetValid(t *testing.T) {
|
||||
_, mux, token := setupKiosk(t)
|
||||
|
||||
req := httptest.NewRequest("GET", "/api/v/"+token, nil)
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("status = %d\nbody: %s", w.Code, w.Body.String())
|
||||
}
|
||||
result := parseJSON(t, w)
|
||||
if result["volunteer"] == nil {
|
||||
t.Error("missing volunteer")
|
||||
}
|
||||
available := result["available"].([]any)
|
||||
if len(available) != 2 {
|
||||
t.Errorf("available = %d, want 2", len(available))
|
||||
}
|
||||
}
|
||||
|
||||
func TestKioskGetInvalidToken(t *testing.T) {
|
||||
_, mux, _ := setupKiosk(t)
|
||||
|
||||
req := httptest.NewRequest("GET", "/api/v/BADTOKEN", nil)
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusNotFound {
|
||||
t.Errorf("status = %d, want 404", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKioskClaimShift(t *testing.T) {
|
||||
_, mux, token := setupKiosk(t)
|
||||
|
||||
req := httptest.NewRequest("POST", "/api/v/"+token+"/shifts/1", nil)
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("claim: status = %d\nbody: %s", w.Code, w.Body.String())
|
||||
}
|
||||
result := parseJSON(t, w)
|
||||
shifts := result["shifts"].([]any)
|
||||
if len(shifts) != 1 {
|
||||
t.Errorf("assigned shifts = %d, want 1", len(shifts))
|
||||
}
|
||||
}
|
||||
|
||||
func TestKioskClaimConflict(t *testing.T) {
|
||||
app, mux, token := setupKiosk(t)
|
||||
|
||||
dept, _ := app.createDepartment(Department{Name: "Build"})
|
||||
deptID := dept.ID
|
||||
// Create overlapping shift
|
||||
app.createShift(Shift{DepartmentID: deptID, Name: "Overlap", Day: "2026-03-15", StartTime: "10:00", EndTime: "14:00"})
|
||||
|
||||
// Claim morning (08:00-12:00)
|
||||
req := httptest.NewRequest("POST", "/api/v/"+token+"/shifts/1", nil)
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("first claim: status = %d", w.Code)
|
||||
}
|
||||
|
||||
// Claim overlapping shift (10:00-14:00) — should get 409
|
||||
req = httptest.NewRequest("POST", "/api/v/"+token+"/shifts/3", nil)
|
||||
w = httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusConflict {
|
||||
t.Fatalf("conflict: status = %d, want 409\nbody: %s", w.Code, w.Body.String())
|
||||
}
|
||||
result := parseJSON(t, w)
|
||||
if result["conflict"] != true {
|
||||
t.Error("missing conflict flag")
|
||||
}
|
||||
}
|
||||
|
||||
func TestKioskClaimForce(t *testing.T) {
|
||||
app, mux, token := setupKiosk(t)
|
||||
|
||||
dept, _ := app.createDepartment(Department{Name: "Build"})
|
||||
deptID := dept.ID
|
||||
app.createShift(Shift{DepartmentID: deptID, Name: "Overlap", Day: "2026-03-15", StartTime: "10:00", EndTime: "14:00"})
|
||||
|
||||
// Claim morning
|
||||
req := httptest.NewRequest("POST", "/api/v/"+token+"/shifts/1", nil)
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
|
||||
// Force-claim overlapping shift
|
||||
req = httptest.NewRequest("POST", "/api/v/"+token+"/shifts/3?force=true", nil)
|
||||
w = httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("force: status = %d, want 200", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKioskClaimFull(t *testing.T) {
|
||||
app, mux, token := setupKiosk(t)
|
||||
|
||||
// Shift 2 has capacity 1. Fill it with another volunteer.
|
||||
dept, _ := app.createDepartment(Department{Name: "Build"})
|
||||
deptID := dept.ID
|
||||
other, _ := app.createVolunteer(Volunteer{Name: "Other", DepartmentID: &deptID})
|
||||
app.assignShift(other.ID, 2) // fills the capacity-1 shift
|
||||
|
||||
req := httptest.NewRequest("POST", "/api/v/"+token+"/shifts/2", nil)
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusConflict {
|
||||
t.Errorf("full: status = %d, want 409\nbody: %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestKioskUnclaim(t *testing.T) {
|
||||
_, mux, token := setupKiosk(t)
|
||||
|
||||
// Claim then unclaim
|
||||
req := httptest.NewRequest("POST", "/api/v/"+token+"/shifts/1", nil)
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
|
||||
req = httptest.NewRequest("DELETE", "/api/v/"+token+"/shifts/1", nil)
|
||||
w = httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, req)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Errorf("unclaim: status = %d", w.Code)
|
||||
}
|
||||
result := parseJSON(t, w)
|
||||
shifts := result["shifts"].([]any)
|
||||
if len(shifts) != 0 {
|
||||
t.Errorf("after unclaim: shifts = %d, want 0", len(shifts))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue