test(10-05): cover every Phase 10 Go change with branch-level tests

- bouncer TestPhase10CookieGuard: cookie read without Bearer, Bearer wins,
  empty cookie, frontend audience and blacklisted jti rejected
- boardwalk TestPhase10BoardwalkServing: HEAD, query strings, encoded
  traversal, index by name, nested prefix, MIME fallback, constructor errors
- cabana TestPhase10Coverage: mounted unsafe routes vs the CSRF walk, option
  and filter edges, read-only labels, relation message defaults, bundle
  fallback locale, cookie refresh of an expired token in the refresh window
- phrasebook override precedence, new locale, Bundle merge order, Forms shapes
- surf prefix collision for deeper paths and the default /backend prefix
- swagger2openapi TestUnionRewrite and converter branch tests
- framework tests no longer name the application (acme fixtures instead)
This commit is contained in:
Jakub Zych
2026-09-27 18:05:28 +02:00
parent 1c2a66df45
commit ef448da1cc
14 changed files with 1055 additions and 35 deletions

View File

@@ -315,3 +315,141 @@ func TestSecurityHeadersOnEveryResponse(t *testing.T) {
}
}
}
// TestPhase10BoardwalkServing covers the remaining serving branches: HEAD,
// query strings, encoded traversal, the index requested by name, a nested
// prefix, deep client routes, MIME fallback for unknown extensions and the
// constructor's error paths.
func TestPhase10BoardwalkServing(t *testing.T) {
h, spy := newTestHandler(t)
t.Run("HEAD answers headers without a body", func(t *testing.T) {
for _, target := range []string{testPrefix, testPrefix + "/acme/demo/widgets"} {
rec := httptest.NewRecorder()
h.ServeHTTP(rec, httptest.NewRequest(http.MethodHead, target, nil))
if rec.Code != http.StatusOK || rec.Body.Len() != 0 || !strings.HasPrefix(rec.Header().Get("Content-Type"), "text/html") {
t.Fatalf("HEAD %s: status=%d len=%d type=%q", target, rec.Code, rec.Body.Len(), rec.Header().Get("Content-Type"))
}
if rec.Header().Get("Content-Length") == "" || rec.Header().Get("X-Frame-Options") != "DENY" {
t.Fatalf("HEAD %s headers = %v", target, rec.Header())
}
}
})
t.Run("query strings do not change what is served", func(t *testing.T) {
root, err := Dist()
if err != nil {
t.Fatal(err)
}
entries, err := fs.ReadDir(root, "assets")
if err != nil || len(entries) == 0 {
t.Fatalf("assets: %v", err)
}
asset := get(h, testPrefix+"/assets/"+entries[0].Name()+"?v=2")
if asset.Code != http.StatusOK || asset.Header().Get("Cache-Control") != "public, max-age=31536000, immutable" {
t.Fatalf("asset with query: status=%d headers=%v", asset.Code, asset.Header())
}
route := get(h, testPrefix+"/acme/demo/widgets?search=blue&page=2")
if route.Code != http.StatusOK || !strings.Contains(route.Body.String(), "summer-admin-base") {
t.Fatalf("client route with query: status=%d", route.Code)
}
before := spy.calls
if rec := get(h, testPrefix+"/api/v1/nope?x=1"); rec.Code != http.StatusNotFound || spy.calls != before+1 {
t.Fatalf("api with query not delegated: %d", rec.Code)
}
})
t.Run("encoded traversal never escapes the build", func(t *testing.T) {
for _, target := range []string{
testPrefix + "/%2e%2e/%2e%2e/go.mod",
testPrefix + "/assets/..%2f..%2fboardwalk.go",
testPrefix + "/%2E%2E%2F%2E%2E%2Fgo.sum",
} {
rec := get(h, target)
body := rec.Body.String()
if rec.Code != http.StatusNotFound || strings.Contains(body, "module ") || strings.Contains(body, "package boardwalk") {
t.Fatalf("%s status=%d body=%.80s", target, rec.Code, body)
}
}
})
t.Run("index.html by name is the rewritten index", func(t *testing.T) {
byName := get(h, testPrefix+"/index.html")
root := get(h, testPrefix+"/")
if byName.Code != http.StatusOK || byName.Body.String() != root.Body.String() {
t.Fatalf("index.html differs from the root index")
}
if strings.Contains(byName.Body.String(), BaseToken) || byName.Header().Get("Cache-Control") != "no-store" {
t.Fatalf("index.html served raw or cacheable: %v", byName.Header())
}
})
t.Run("nested prefix with a trailing slash", func(t *testing.T) {
nested, err := Handler("/ops/admin/", &apiSpy{})
if err != nil {
t.Fatal(err)
}
rec := get(nested, "/ops/admin/acme/demo/widgets/12")
body := rec.Body.String()
if rec.Code != http.StatusOK || !strings.Contains(body, `content="/ops/admin"`) || !strings.Contains(body, `src="/ops/admin/assets/`) {
t.Fatalf("nested prefix index: %d %s", rec.Code, body)
}
if rec := get(nested, "/ops/admin/api/v1/x"); rec.Code != http.StatusNotFound || strings.Contains(rec.Body.String(), "<html") {
t.Fatalf("nested prefix api not delegated: %d", rec.Code)
}
})
t.Run("deep extensionless paths are client routes", func(t *testing.T) {
for _, target := range []string{testPrefix + "/a/b/c/d/e/f", testPrefix + "/settings/mail", testPrefix + "/assets"} {
rec := get(h, target)
if rec.Code != http.StatusOK || !strings.Contains(rec.Body.String(), "summer-admin-base") {
t.Fatalf("%s status=%d", target, rec.Code)
}
}
})
t.Run("unknown extensions fall back to the mime table, then octet-stream", func(t *testing.T) {
root := fstest.MapFS{
"index.html": &fstest.MapFile{Data: []byte(`<meta content="` + BaseToken + `">`)},
"robots.txt": &fstest.MapFile{Data: []byte("User-agent: *\n")},
"assets/logo.png": &fstest.MapFile{Data: []byte("\x89PNG")},
"assets/blob.zzzext": &fstest.MapFile{Data: []byte("x")},
}
mapped, err := newHandler(root, testPrefix, &apiSpy{})
if err != nil {
t.Fatal(err)
}
for target, want := range map[string]string{
"/robots.txt": "text/plain; charset=utf-8",
"/assets/logo.png": "image/png",
"/assets/blob.zzzext": "application/octet-stream",
} {
rec := get(mapped, testPrefix+target)
if rec.Code != http.StatusOK || rec.Header().Get("Content-Type") != want {
t.Fatalf("%s type=%q, want %q", target, rec.Header().Get("Content-Type"), want)
}
}
if cc := get(mapped, testPrefix+"/robots.txt").Header().Get("Cache-Control"); cc != "no-cache" {
t.Fatalf("non-asset file Cache-Control=%q, want no-cache", cc)
}
if got := contentType("UPPER.JS"); got != "text/javascript; charset=utf-8" {
t.Fatalf("extension case: %q", got)
}
})
t.Run("constructor rejects a nil API handler, a relative prefix and a build without index", func(t *testing.T) {
if _, err := Handler(testPrefix, nil); err == nil {
t.Fatal("nil notFoundAPI accepted")
}
if _, err := Handler("backend", &apiSpy{}); err == nil {
t.Fatal("relative prefix accepted")
}
if _, err := newHandler(fstest.MapFS{}, testPrefix, &apiSpy{}); err == nil || !strings.Contains(err.Error(), "index.html") {
t.Fatalf("missing index: %v", err)
}
stale := fstest.MapFS{"index.html": &fstest.MapFile{Data: []byte("<html></html>")}}
if _, err := newHandler(stale, testPrefix, &apiSpy{}); err == nil || !strings.Contains(err.Error(), BaseToken) {
t.Fatalf("stale index: %v", err)
}
})
}