// Package openapitest holds a cross-module guard: it registers every module // into one Huma API and generates the spec. Huma names OpenAPI schemas by Go // type name alone (not package-qualified), so two modules declaring an // identically named response type (e.g. two "ListOutput"s) collide only when // registered together - a failure invisible to per-package `go build`/`go test`. package openapitest import ( "net/http" "path/filepath" "testing" "nadir/internal/auditlog" "nadir/internal/auth" "nadir/internal/meta" "nadir/internal/module" "nadir/internal/modules/groups" "nadir/internal/modules/networking" "nadir/internal/modules/packages" "nadir/internal/modules/services" "nadir/internal/modules/storage" "nadir/internal/modules/system" "nadir/internal/modules/users" "nadir/internal/rbac" "github.com/danielgtaylor/huma/v2" "github.com/danielgtaylor/huma/v2/adapters/humago" ) type auditModule struct{} func (auditModule) ID() string { return "audit" } func (auditModule) Permissions() []rbac.Permission { return []rbac.Permission{rbac.Read} } func (auditModule) Register(huma.API) {} func TestOpenAPISchemaNoCollisions(t *testing.T) { auditStore, err := auditlog.New(filepath.Join(t.TempDir(), "audit.db")) if err != nil { t.Fatal(err) } sessions, err := auth.NewSessionStore(filepath.Join(t.TempDir(), "sessions.db")) if err != nil { t.Fatal(err) } roles := rbac.New() // Mirror cmd/server.go's registration so this catches real collisions. mods := []module.Module{ system.New(), services.New(nil), users.New(nil), groups.New(), packages.New(), networking.New(), storage.New(), auditModule{}, } mux := http.NewServeMux() api := humago.New(mux, huma.DefaultConfig("test", "1.0.0")) for _, m := range mods { m.Register(api) // huma panics here on a duplicate schema name } meta.Register(api, mods) meta.RegisterHealth(api, sessions) meta.RegisterWhoami(api, sessions, nil, roles, mods) meta.RegisterAudit(api, auditStore) auth.RegisterLogin(api, sessions, auditStore, true) auth.RegisterLogout(api, sessions, true) // Force full schema resolution. if _, err := api.OpenAPI().YAML(); err != nil { t.Fatalf("OpenAPI generation failed: %v", err) } }