Files
o11y/pkg/query-service/app/publish_wiring_test.go
zooqueenandHanzo Dev 0efe2171b0 The gate reads Go 1.27 and zip 1.37 as they answer
Every release since v1.5.72 died in this gate on three tests pinned to answers
the toolchain no longer gives, so no image or site was published for any of them:

- binding: from Go 1.27 encoding/json names a field from the value whose
  UnmarshalJSON failed, so a nested custom type reports 'a', not 's.a'.
- publish: zip 1.37 answers a miss or a refused method with an RFC 9457 problem
  document, and /mcp with plain application/json, protocol 2026-07-28 and the
  jsonrpc member first.
- wiring: the console catch-all is registered through app.Raw(zip.MethodAll,
  "/*", …) now, so the order check finds it by its "/*" path, not by the verb.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-24 05:58:50 -07:00

130 lines
4.3 KiB
Go

package app
// THE LINK, NOT THE FUNCTION.
//
// publish_test.go proves what publish DOES: mount it on a bare zip.App and 319
// operations and 319 MCP tools appear. Every assertion it makes calls publish
// directly — which is precisely the shape of the original defect. 319 typed ops
// once shipped in files nothing called; the package built, the route arithmetic
// added up, and the running server published nothing. A test that calls the
// function itself cannot see that, because the thing that was missing was the
// CALL.
//
// Deleting `publish(app)` from createPublicServer leaves the entire o11y suite
// green — measured, not assumed. The only evidence that the link exists was
// `go tool nm` on ./cmd/community, run by hand, in no CI.
//
// So state the invariant where it can fail. createPublicServer is the
// composition root for this service's surface, and two facts about it are load-
// bearing:
//
// - it calls publish, or the document, the MCP tool list and the call plane are
// all empty in the process that serves them;
// - it calls publish BEFORE the console catch-all — the one route registered
// at "/*", app.Raw(zip.MethodAll, "/*", …) — because the router matches in
// registration order and a terminal route registered first would swallow
// every published path.
//
// Constructing a real Server to observe this would need the whole module graph —
// stores, telemetry, licensing — so the wiring is read from the source, which is
// where the defect lives and the only place it is visible at all.
import (
"go/ast"
"go/parser"
"go/token"
"io/fs"
"strings"
"testing"
)
// catchAll names a registration at "/*" by its path rather than by the verb that
// registers it, so the assertion survives the verb changing (app.All became
// app.Raw(zip.MethodAll, …)) and fails only if the route itself goes.
const catchAll = `"/*"`
// compositionRoot returns the ordered list of calls createPublicServer makes, as
// "receiver.Selector" / "function" names, and catchAll for any call registering
// the "/*" path.
func compositionRoot(t *testing.T) []string {
t.Helper()
fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, ".", func(fi fs.FileInfo) bool {
return !strings.HasSuffix(fi.Name(), "_test.go")
}, 0)
if err != nil {
t.Fatalf("parse package: %v", err)
}
for _, pkg := range pkgs {
for _, file := range pkg.Files {
for _, decl := range file.Decls {
fn, ok := decl.(*ast.FuncDecl)
if !ok || fn.Name.Name != "createPublicServer" || fn.Body == nil {
continue
}
var calls []string
ast.Inspect(fn.Body, func(n ast.Node) bool {
call, ok := n.(*ast.CallExpr)
if !ok {
return true
}
for _, arg := range call.Args {
if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING && lit.Value == catchAll {
calls = append(calls, catchAll)
return true
}
}
switch fun := call.Fun.(type) {
case *ast.Ident:
calls = append(calls, fun.Name)
case *ast.SelectorExpr:
if id, ok := fun.X.(*ast.Ident); ok {
calls = append(calls, id.Name+"."+fun.Sel.Name)
} else {
calls = append(calls, fun.Sel.Name)
}
}
return true
})
return calls
}
}
}
t.Fatal("createPublicServer not found — this test is measuring the wrong thing")
return nil
}
func TestCreatePublicServerPublishesTheSurface(t *testing.T) {
calls := compositionRoot(t)
publishAt, catchAllAt := -1, -1
for i, name := range calls {
switch name {
case "publish":
if publishAt < 0 {
publishAt = i
}
case catchAll:
if catchAllAt < 0 {
catchAllAt = i
}
}
}
if publishAt < 0 {
t.Fatal("createPublicServer does not call publish — the running server registers no typed " +
"operations, publishes no OpenAPI document and exposes no MCP tools, and every test " +
"in this package still passes because they all call publish themselves")
}
if catchAllAt < 0 {
t.Fatal("createPublicServer no longer registers the console catch-all at \"/*\"; " +
"this test's ordering assertion is measuring something that moved")
}
if publishAt > catchAllAt {
t.Fatalf("publish is called at position %d, after the console catch-all at %d — the router "+
"matches in registration order, so the SPA shell would answer every published path",
publishAt, catchAllAt)
}
}