108 lines
3.2 KiB
Go
108 lines
3.2 KiB
Go
package modulecontrol
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
func httptestJSONBody(s string) *strings.Reader {
|
|
return strings.NewReader(s)
|
|
}
|
|
|
|
func newTestApp(h *Handler) *fiber.App {
|
|
app := fiber.New()
|
|
app.Use(h.Middleware())
|
|
app.Get("/health", func(c *fiber.Ctx) error { return c.JSON(fiber.Map{"ok": true}) })
|
|
app.Get("/api/orders", func(c *fiber.Ctx) error { return c.JSON(fiber.Map{"ok": true}) })
|
|
app.Post("/api/module-control/restart", h.Restart)
|
|
app.Post("/api/module-control/maintenance", h.SetMaintenance)
|
|
return app
|
|
}
|
|
|
|
func TestAuthRejectsEmptyConfiguredToken(t *testing.T) {
|
|
h := &Handler{controlToken: ""}
|
|
app := newTestApp(h)
|
|
|
|
req := httptest.NewRequest("POST", "/api/module-control/restart", nil)
|
|
req.Header.Set("X-Control-Token", "anything")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != 401 {
|
|
t.Errorf("status = %d, want 401 (empty configured token must never authenticate)", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestAuthRejectsWrongToken(t *testing.T) {
|
|
h := &Handler{controlToken: "correct-secret"}
|
|
app := newTestApp(h)
|
|
|
|
req := httptest.NewRequest("POST", "/api/module-control/maintenance", httptestJSONBody(`{"enabled":true}`))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("X-Control-Token", "wrong-secret")
|
|
resp, err := app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != 401 {
|
|
t.Errorf("status = %d, want 401", resp.StatusCode)
|
|
}
|
|
if h.Maintenance() {
|
|
t.Error("maintenance flag must not change on a rejected request")
|
|
}
|
|
}
|
|
|
|
func TestMaintenanceMiddlewareBlocksAndExemptsHealthAndControl(t *testing.T) {
|
|
h := &Handler{controlToken: "secret"}
|
|
app := newTestApp(h)
|
|
|
|
// Turn maintenance on via the real endpoint.
|
|
req := httptest.NewRequest("POST", "/api/module-control/maintenance", httptestJSONBody(`{"enabled":true}`))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("X-Control-Token", "secret")
|
|
if _, err := app.Test(req); err != nil {
|
|
t.Fatalf("enabling maintenance: %v", err)
|
|
}
|
|
if !h.Maintenance() {
|
|
t.Fatal("maintenance should now be on")
|
|
}
|
|
|
|
// An ordinary route is blocked.
|
|
resp, err := app.Test(httptest.NewRequest("GET", "/api/orders", nil))
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != 503 {
|
|
t.Errorf("ordinary route status = %d, want 503 while in maintenance", resp.StatusCode)
|
|
}
|
|
|
|
// /health stays reachable.
|
|
resp, err = app.Test(httptest.NewRequest("GET", "/health", nil))
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != 200 {
|
|
t.Errorf("/health status = %d, want 200 even in maintenance", resp.StatusCode)
|
|
}
|
|
|
|
// The control route itself must stay reachable — a maintenance flag
|
|
// that blocks its own toggle would be a one-way door.
|
|
req = httptest.NewRequest("POST", "/api/module-control/maintenance", httptestJSONBody(`{"enabled":false}`))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
req.Header.Set("X-Control-Token", "secret")
|
|
resp, err = app.Test(req)
|
|
if err != nil {
|
|
t.Fatalf("app.Test: %v", err)
|
|
}
|
|
if resp.StatusCode != 200 {
|
|
t.Errorf("disabling maintenance status = %d, want 200", resp.StatusCode)
|
|
}
|
|
if h.Maintenance() {
|
|
t.Error("maintenance should now be off")
|
|
}
|
|
}
|