88 lines
3.5 KiB
Go
88 lines
3.5 KiB
Go
package routes_test
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// Reverse logistics (RTO) gates, over real HTTP. Refusals happen in
|
|
// middleware (or before any query), so no database is needed.
|
|
|
|
var rtoWrites = []struct{ method, path, body string }{
|
|
{http.MethodPost, "/api/v1/admin/consignments/5/rto", `{"reason":"receiver_refused"}`},
|
|
{http.MethodPost, "/api/v1/admin/consignments/5/rto/cancel", `{}`},
|
|
{http.MethodPost, "/api/v1/admin/consignments/5/rto/complete", `{}`},
|
|
}
|
|
|
|
func TestRTONeedsALogin(t *testing.T) {
|
|
app := newApp()
|
|
for _, w := range rtoWrites {
|
|
if code, _ := do(t, app, w.method, w.path, "", w.body); code != http.StatusUnauthorized {
|
|
t.Errorf("%s %s with no token = %d, want 401", w.method, w.path, code)
|
|
}
|
|
}
|
|
if code, _ := do(t, app, http.MethodGet, "/api/v1/admin/returns", "", ""); code != http.StatusUnauthorized {
|
|
t.Errorf("GET /admin/returns with no token = %d, want 401", code)
|
|
}
|
|
}
|
|
|
|
// A client login may read its returns but never start, cancel or close one.
|
|
func TestRTOActionsAreDoormileStaffOnly(t *testing.T) {
|
|
app := newApp()
|
|
client := tenantToken(t, 50, 1, 7)
|
|
for _, w := range rtoWrites {
|
|
code, body := do(t, app, w.method, w.path, client, w.body)
|
|
if code != http.StatusForbidden || !strings.Contains(body, "Doormile staff only") {
|
|
t.Errorf("client %s %s = %d %s, want 403 staff only", w.method, w.path, code, body)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRTORefusesNonConsoleRoles(t *testing.T) {
|
|
app := newApp()
|
|
for _, role := range []int{5, 6, 9} {
|
|
for _, w := range rtoWrites {
|
|
if code, _ := do(t, app, w.method, w.path, token(t, 1, role), w.body); code != http.StatusForbidden {
|
|
t.Errorf("role %d %s %s = %d, want 403", role, w.method, w.path, code)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Staff pass every gate (no database here, so the handler's first query
|
|
// panics and recover answers 500 — proof nothing in front of it refused).
|
|
// A missing reason is refused before any query.
|
|
func TestRTOStaffPassTheGate(t *testing.T) {
|
|
app := newApp()
|
|
staff := token(t, 1, 1)
|
|
for _, w := range rtoWrites {
|
|
if code, _ := do(t, app, w.method, w.path, staff, w.body); code == 401 || code == 403 || code == 404 {
|
|
t.Errorf("staff %s %s = %d; a gate refused or the route is missing", w.method, w.path, code)
|
|
}
|
|
}
|
|
if code, body := do(t, app, http.MethodPost, "/api/v1/admin/consignments/5/rto", staff, `{"reason":"teleported"}`); code != http.StatusBadRequest {
|
|
t.Errorf("unknown reason = %d %s, want 400", code, body)
|
|
}
|
|
if code, body := do(t, app, http.MethodPost, "/api/v1/admin/consignments/5/rto", staff, `{"reason":"other"}`); code != http.StatusBadRequest {
|
|
t.Errorf("other without a note = %d %s, want 400", code, body)
|
|
}
|
|
if code, _ := do(t, app, http.MethodGet, "/api/v1/admin/returns?status=bogus", staff, ""); code != http.StatusBadRequest {
|
|
t.Errorf("bad status filter = %d, want 400", code)
|
|
}
|
|
}
|
|
|
|
// The rider endpoint stays shut until MILER_RTO_FLOW_ENABLED=true — the
|
|
// deployed rider app does not know returns yet.
|
|
func TestRiderReturnIsOffByDefault(t *testing.T) {
|
|
t.Setenv("MILER_RTO_FLOW_ENABLED", "")
|
|
app := newApp()
|
|
code, body := do(t, app, http.MethodPost, "/api/v1/miler/consignments/5/return-complete", token(t, 9, 5), `{}`)
|
|
if code != http.StatusForbidden || !strings.Contains(body, "RTO_FLOW_DISABLED") {
|
|
t.Fatalf("flag off = %d %s, want 403 RTO_FLOW_DISABLED", code, body)
|
|
}
|
|
if code, _ := do(t, app, http.MethodPost, "/api/v1/miler/consignments/5/return-complete", token(t, 1, 1), `{}`); code != http.StatusForbidden {
|
|
t.Fatalf("a console token on the rider route = %d, want 403", code)
|
|
}
|
|
}
|