agent-orchestrator/backend/internal/httpd/apispec/apispec_test.go

72 lines
2.5 KiB
Go

package apispec_test
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/aoagents/agent-orchestrator/backend/internal/httpd/apispec"
)
// TestDefaultLoadsEmbeddedSpec is the smoke test for //go:embed wiring:
// the default Spec must parse the embedded YAML without panicking and
// recognise a known operation.
func TestDefaultLoadsEmbeddedSpec(t *testing.T) {
op := apispec.Default().Operation("GET", "/api/v1/projects")
if op == nil {
t.Fatal("Default().Operation(GET, /api/v1/projects) = nil; embed broken or path missing")
}
if got, _ := op["operationId"].(string); got != "listProjects" {
t.Errorf("operationId = %q, want listProjects", got)
}
}
// TestOperation_MissingPath returns nil for unknown paths — that's how the
// controller-side test catches "route registered without spec coverage".
func TestOperation_MissingPath(t *testing.T) {
if op := apispec.Default().Operation("GET", "/api/v1/no-such-route"); op != nil {
t.Errorf("unknown path returned %v, want nil", op)
}
}
// TestOperation_MissingMethod returns nil for known path / unknown method.
func TestOperation_MissingMethod(t *testing.T) {
if op := apispec.Default().Operation("HEAD", "/api/v1/projects"); op != nil {
t.Errorf("HEAD on a GET-only path returned %v, want nil", op)
}
}
// TestOperation_InheritsPathParameters covers the bit of behaviour that
// would silently rot otherwise: parameters declared at the path level
// (e.g. the {id} path param shared by GET/PATCH/DELETE) must show up on
// every operation's slice so the 501 response is self-contained.
func TestOperation_InheritsPathParameters(t *testing.T) {
op := apispec.Default().Operation("GET", "/api/v1/projects/{id}")
if op == nil {
t.Fatal("expected operation slice")
}
params, ok := op["parameters"].([]any)
if !ok || len(params) == 0 {
t.Fatalf("expected inherited path-level parameters, got %#v", op["parameters"])
}
}
// TestServeYAML serves the raw embedded document; tooling fetches it
// whole rather than reconstructing it from per-operation slices.
func TestServeYAML(t *testing.T) {
rec := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/api/v1/openapi.yaml", nil)
apispec.ServeYAML(rec, req)
if rec.Code != 200 {
t.Fatalf("status = %d, want 200", rec.Code)
}
if ct := rec.Header().Get("Content-Type"); !strings.HasPrefix(ct, "application/yaml") {
t.Errorf("Content-Type = %q, want application/yaml*", ct)
}
if !strings.Contains(rec.Body.String(), "openapi: 3.1.0") {
t.Errorf("body did not begin with an OpenAPI 3.1 doc")
}
}