213 lines
7 KiB
Go
213 lines
7 KiB
Go
package main
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestShiftsCRUDHandler(t *testing.T) {
|
|
app := testApp(t)
|
|
admin := testAdminUser(t, app)
|
|
token := testToken(t, app, admin)
|
|
mux := testMux(app)
|
|
|
|
dept, _ := app.createDepartment(Department{Name: "Gate"})
|
|
|
|
// Create
|
|
req := testAuthRequest("POST", "/api/shifts", map[string]any{
|
|
"department_id": dept.ID,
|
|
"name": "Morning",
|
|
"day": "2026-03-15",
|
|
"start_time": "08:00",
|
|
"end_time": "12:00",
|
|
"capacity": 5,
|
|
}, token)
|
|
w := httptest.NewRecorder()
|
|
mux.ServeHTTP(w, req)
|
|
if w.Code != http.StatusCreated {
|
|
t.Fatalf("create: status = %d\nbody: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
// List
|
|
req = testAuthRequest("GET", "/api/shifts", nil, token)
|
|
w = httptest.NewRecorder()
|
|
mux.ServeHTTP(w, req)
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("list: status = %d", w.Code)
|
|
}
|
|
|
|
// Delete
|
|
req = testAuthRequest("DELETE", "/api/shifts/1", nil, token)
|
|
w = httptest.NewRecorder()
|
|
mux.ServeHTTP(w, req)
|
|
if w.Code != http.StatusNoContent {
|
|
t.Errorf("delete: status = %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestShiftAssignVolunteer(t *testing.T) {
|
|
app := testApp(t)
|
|
admin := testAdminUser(t, app)
|
|
token := testToken(t, app, admin)
|
|
mux := testMux(app)
|
|
|
|
dept, _ := app.createDepartment(Department{Name: "Gate"})
|
|
deptID := dept.ID
|
|
app.createShift(Shift{DepartmentID: deptID, Name: "AM", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00"})
|
|
p, _ := app.createParticipant(Participant{PreferredName: "Titania", Email: "titania@test.com"})
|
|
app.createVolunteer(Volunteer{ParticipantID: p.ID, DepartmentID: &deptID})
|
|
|
|
// Assign
|
|
req := testAuthRequest("POST", "/api/shifts/1/volunteers", map[string]any{
|
|
"volunteer_id": 1,
|
|
}, token)
|
|
w := httptest.NewRecorder()
|
|
mux.ServeHTTP(w, req)
|
|
if w.Code != http.StatusNoContent {
|
|
t.Fatalf("assign: status = %d\nbody: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
// Unassign
|
|
req = testAuthRequest("DELETE", "/api/shifts/1/volunteers/1", nil, token)
|
|
w = httptest.NewRecorder()
|
|
mux.ServeHTTP(w, req)
|
|
if w.Code != http.StatusNoContent {
|
|
t.Errorf("unassign: status = %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestShiftAssignConflict(t *testing.T) {
|
|
app := testApp(t)
|
|
admin := testAdminUser(t, app)
|
|
token := testToken(t, app, admin)
|
|
mux := testMux(app)
|
|
|
|
dept, _ := app.createDepartment(Department{Name: "Gate"})
|
|
deptID := dept.ID
|
|
app.createShift(Shift{DepartmentID: deptID, Name: "AM", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00"})
|
|
app.createShift(Shift{DepartmentID: deptID, Name: "Overlap", Day: "2026-03-15", StartTime: "10:00", EndTime: "14:00"})
|
|
p, _ := app.createParticipant(Participant{PreferredName: "Titania", Email: "titania@test.com"})
|
|
app.createVolunteer(Volunteer{ParticipantID: p.ID, DepartmentID: &deptID})
|
|
|
|
// Assign to first shift
|
|
app.assignShift(1, 1)
|
|
|
|
// Try to assign to overlapping shift — should get 409
|
|
req := testAuthRequest("POST", "/api/shifts/2/volunteers", map[string]any{
|
|
"volunteer_id": 1,
|
|
}, token)
|
|
w := httptest.NewRecorder()
|
|
mux.ServeHTTP(w, req)
|
|
if w.Code != http.StatusConflict {
|
|
t.Fatalf("conflict: status = %d, want 409", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestCoLeadDeleteShiftOtherDept(t *testing.T) {
|
|
app := testApp(t)
|
|
mux := testMux(app)
|
|
|
|
deptA, _ := app.createDepartment(Department{Name: "Gate"})
|
|
deptB, _ := app.createDepartment(Department{Name: "Build"})
|
|
colead := testUserWithRoles(t, app, "Hermia", []string{"colead"}, []int{deptA.ID})
|
|
tok := testToken(t, app, colead)
|
|
|
|
s, _ := app.createShift(Shift{DepartmentID: deptB.ID, Name: "AM", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00"})
|
|
|
|
w := httptest.NewRecorder()
|
|
mux.ServeHTTP(w, testAuthRequest("DELETE", "/api/shifts/"+itoa(s.ID), nil, tok))
|
|
if w.Code != http.StatusForbidden {
|
|
t.Errorf("expected 403 for other dept, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestCoLeadDeleteShiftOwnDept(t *testing.T) {
|
|
app := testApp(t)
|
|
mux := testMux(app)
|
|
|
|
deptA, _ := app.createDepartment(Department{Name: "Gate"})
|
|
colead := testUserWithRoles(t, app, "Hermia", []string{"colead"}, []int{deptA.ID})
|
|
tok := testToken(t, app, colead)
|
|
|
|
s, _ := app.createShift(Shift{DepartmentID: deptA.ID, Name: "AM", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00"})
|
|
|
|
w := httptest.NewRecorder()
|
|
mux.ServeHTTP(w, testAuthRequest("DELETE", "/api/shifts/"+itoa(s.ID), nil, tok))
|
|
if w.Code != http.StatusNoContent {
|
|
t.Errorf("expected 204 for own dept, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestCoLeadAssignShiftVolunteerOtherDept(t *testing.T) {
|
|
app := testApp(t)
|
|
mux := testMux(app)
|
|
|
|
deptA, _ := app.createDepartment(Department{Name: "Gate"})
|
|
deptB, _ := app.createDepartment(Department{Name: "Build"})
|
|
colead := testUserWithRoles(t, app, "Hermia", []string{"colead"}, []int{deptA.ID})
|
|
tok := testToken(t, app, colead)
|
|
|
|
s, _ := app.createShift(Shift{DepartmentID: deptB.ID, Name: "AM", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00"})
|
|
deptBID := deptB.ID
|
|
p, _ := app.createParticipant(Participant{PreferredName: "Puck", Email: "puck@test.com"})
|
|
v, _ := app.createVolunteer(Volunteer{ParticipantID: p.ID, DepartmentID: &deptBID})
|
|
|
|
w := httptest.NewRecorder()
|
|
mux.ServeHTTP(w, testAuthRequest("POST", "/api/shifts/"+itoa(s.ID)+"/volunteers", map[string]any{
|
|
"volunteer_id": v.ID,
|
|
}, tok))
|
|
if w.Code != http.StatusForbidden {
|
|
t.Errorf("expected 403 for other dept, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestCoLeadReorderShiftsOtherDept(t *testing.T) {
|
|
app := testApp(t)
|
|
mux := testMux(app)
|
|
|
|
deptA, _ := app.createDepartment(Department{Name: "Gate"})
|
|
deptB, _ := app.createDepartment(Department{Name: "Build"})
|
|
colead := testUserWithRoles(t, app, "Hermia", []string{"colead"}, []int{deptA.ID})
|
|
tok := testToken(t, app, colead)
|
|
|
|
s1, _ := app.createShift(Shift{DepartmentID: deptB.ID, Name: "A", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00"})
|
|
s2, _ := app.createShift(Shift{DepartmentID: deptB.ID, Name: "B", Day: "2026-03-15", StartTime: "12:00", EndTime: "16:00"})
|
|
|
|
w := httptest.NewRecorder()
|
|
mux.ServeHTTP(w, testAuthRequest("POST", "/api/shifts/reorder", []map[string]int{
|
|
{"id": s1.ID, "position": 2},
|
|
{"id": s2.ID, "position": 1},
|
|
}, tok))
|
|
if w.Code != http.StatusForbidden {
|
|
t.Errorf("expected 403 for other dept reorder, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestShiftReorder(t *testing.T) {
|
|
app := testApp(t)
|
|
admin := testAdminUser(t, app)
|
|
token := testToken(t, app, admin)
|
|
mux := testMux(app)
|
|
|
|
dept, _ := app.createDepartment(Department{Name: "Gate"})
|
|
deptID := dept.ID
|
|
app.createShift(Shift{DepartmentID: deptID, Name: "A", Day: "2026-03-15", StartTime: "08:00", EndTime: "12:00"})
|
|
app.createShift(Shift{DepartmentID: deptID, Name: "B", Day: "2026-03-15", StartTime: "12:00", EndTime: "16:00"})
|
|
|
|
req := testAuthRequest("POST", "/api/shifts/reorder", []map[string]int{
|
|
{"id": 1, "position": 2},
|
|
{"id": 2, "position": 1},
|
|
}, token)
|
|
w := httptest.NewRecorder()
|
|
mux.ServeHTTP(w, req)
|
|
if w.Code != http.StatusNoContent {
|
|
t.Errorf("reorder: status = %d\nbody: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
s1, _ := app.getShift(1)
|
|
s2, _ := app.getShift(2)
|
|
if s1.Position != 2 || s2.Position != 1 {
|
|
t.Errorf("positions: s1=%d, s2=%d, want 2,1", s1.Position, s2.Position)
|
|
}
|
|
}
|