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:
@@ -28,6 +28,8 @@ func TestPhase10AdminPrefixCollision(t *testing.T) {
|
||||
{"exact prefix", http.MethodGet, "/acme-admin", false},
|
||||
{"under prefix", http.MethodPost, "/acme-admin/hook", false},
|
||||
{"raw under api", http.MethodGet, "/acme-admin/api/v1/extra", true},
|
||||
{"deeper path", http.MethodGet, "/acme-admin/a/b/c", false},
|
||||
{"exact prefix raw", http.MethodPost, "/acme-admin", true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
app := adminPrefixApp(t)
|
||||
@@ -57,9 +59,52 @@ func TestPhase10AdminPrefixCollision(t *testing.T) {
|
||||
t.Fatalf("sibling path rejected: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("default /backend prefix", func(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
path string
|
||||
collide bool
|
||||
}{
|
||||
{"/backend", true},
|
||||
{"/backend/deep/hook", true},
|
||||
{"/backendx", false},
|
||||
{"/back", false},
|
||||
{"/api/backend", false},
|
||||
} {
|
||||
app := adminPrefixAppWith(t, "")
|
||||
plugins := []party.Plugin{
|
||||
adminPrefixPlugin{},
|
||||
prefixRoutePlugin{id: "acme.intruder", method: http.MethodGet, path: tc.path},
|
||||
}
|
||||
_, err := BuildRouter(app, plugins)
|
||||
if tc.collide && (err == nil || !strings.Contains(err.Error(), "/backend")) {
|
||||
t.Fatalf("%s under the default prefix: err=%v", tc.path, err)
|
||||
}
|
||||
if !tc.collide && err != nil {
|
||||
t.Fatalf("%s rejected next to the default prefix: %v", tc.path, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("no admin means no prefix check", func(t *testing.T) {
|
||||
app := adminPrefixApp(t)
|
||||
plugins := []party.Plugin{prefixRoutePlugin{id: "acme.site", method: http.MethodGet, path: "/acme-admin"}}
|
||||
if _, err := BuildRouter(app, plugins); err != nil {
|
||||
t.Fatalf("a route at the prefix without admin controllers was rejected: %v", err)
|
||||
}
|
||||
if err := (&Router{}).checkAdminPrefix(""); err != nil {
|
||||
t.Fatalf("empty prefix: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func adminPrefixApp(t *testing.T) *backpack.App {
|
||||
t.Helper()
|
||||
return adminPrefixAppWith(t, "/acme-admin")
|
||||
}
|
||||
|
||||
// adminPrefixAppWith configures backend.uri; an empty uri keeps the default.
|
||||
func adminPrefixAppWith(t *testing.T, uri string) *backpack.App {
|
||||
t.Helper()
|
||||
dir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(dir, "app.yaml"), []byte("name: admin-prefix\n"), 0o644); err != nil {
|
||||
@@ -68,8 +113,10 @@ func adminPrefixApp(t *testing.T) *backpack.App {
|
||||
if err := os.WriteFile(filepath.Join(dir, "http.yaml"), []byte("body_limits:\n default_bytes: 1024\n upload_bytes: 1024\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(dir, "backend.yaml"), []byte("uri: /acme-admin\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
if uri != "" {
|
||||
if err := os.WriteFile(filepath.Join(dir, "backend.yaml"), []byte("uri: "+uri+"\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
cfg, err := compass.Open(compass.Options{
|
||||
Dir: dir,
|
||||
|
||||
@@ -7,10 +7,10 @@ import (
|
||||
)
|
||||
|
||||
// Gap (d): pathScopedCORS with a path matching NONE of the configured
|
||||
// globs. TestCORSPathScopedHeaders already covers the two named fonoteka
|
||||
// globs. TestCORSPathScopedHeaders already covers the two named acme
|
||||
// groups; this fixture is framework-only (/healthz vs api/*).
|
||||
|
||||
func TestCORSPathScopedNoMatchIndependentOfFonoteka(t *testing.T) {
|
||||
func TestCORSPathScopedNoMatchIndependentOfAcme(t *testing.T) {
|
||||
cfg := CORSConfig{
|
||||
Paths: []string{"api/*", "oauth/mcp/*"},
|
||||
AllowedMethods: []string{"*"},
|
||||
|
||||
@@ -14,11 +14,11 @@ import (
|
||||
|
||||
func TestCORSLaravelGlobMatchesNestedPaths(t *testing.T) {
|
||||
re := compileLaravelGlob("api/*")
|
||||
if re == nil || !re.MatchString("api/v1/fonoteka/genres") {
|
||||
t.Fatal("api/* must match api/v1/fonoteka/genres (Laravel Str::is, not Go path.Match)")
|
||||
if re == nil || !re.MatchString("api/v1/acme/genres") {
|
||||
t.Fatal("api/* must match api/v1/acme/genres (Laravel Str::is, not Go path.Match)")
|
||||
}
|
||||
if re.MatchString("_fonoteka/api/v1/genres") {
|
||||
t.Fatal("api/* must not match _fonoteka/api/v1/genres")
|
||||
if re.MatchString("_acme/api/v1/genres") {
|
||||
t.Fatal("api/* must not match _acme/api/v1/genres")
|
||||
}
|
||||
mcp := compileLaravelGlob("oauth/mcp/*")
|
||||
if mcp == nil || !mcp.MatchString("oauth/mcp/token") {
|
||||
@@ -34,22 +34,22 @@ func TestCORSPathScopedHeaders(t *testing.T) {
|
||||
AllowedHeaders: []string{"*"},
|
||||
}
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("GET /api/v1/fonoteka/genres", func(w http.ResponseWriter, r *http.Request) {
|
||||
mux.HandleFunc("GET /api/v1/acme/genres", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
mux.HandleFunc("GET /_fonoteka/api/v1/genres", func(w http.ResponseWriter, r *http.Request) {
|
||||
mux.HandleFunc("GET /_acme/api/v1/genres", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
})
|
||||
h := pathScopedCORS(cfg, mux)
|
||||
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/v1/fonoteka/genres", nil))
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/api/v1/acme/genres", nil))
|
||||
if rec.Header().Get("Access-Control-Allow-Origin") != "*" {
|
||||
t.Fatalf("token group ACAO = %q", rec.Header().Get("Access-Control-Allow-Origin"))
|
||||
}
|
||||
|
||||
rec = httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/_fonoteka/api/v1/genres", nil))
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/_acme/api/v1/genres", nil))
|
||||
if got := rec.Header().Get("Access-Control-Allow-Origin"); got != "" {
|
||||
t.Fatalf("JWT group ACAO = %q, want empty", got)
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ func TestPipelineOrderRecoverCORSLocaleAuthPasswordOrgRateHandler(t *testing.T)
|
||||
if err := r.RegisterMiddleware("golem15.user", "jwt.auth", record("jwt.auth")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := r.RegisterMiddleware("golem15.fonoteka", "inv.must-change-password", record("inv.must-change-password")); err != nil {
|
||||
if err := r.RegisterMiddleware("golem15.acme", "inv.must-change-password", record("inv.must-change-password")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r.BindPlugin("golem15.demo")
|
||||
|
||||
@@ -436,7 +436,7 @@ func TestMiddlewareFactoryReceivesParam(t *testing.T) {
|
||||
r := New(nil)
|
||||
var gotParam string
|
||||
ran := false
|
||||
if err := r.RegisterMiddlewareFactory("golem15.fonoteka", "inv.scope", func(param string) pact.Middleware {
|
||||
if err := r.RegisterMiddlewareFactory("golem15.acme", "inv.scope", func(param string) pact.Middleware {
|
||||
gotParam = param
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
@@ -472,11 +472,11 @@ func TestDuplicateMiddlewareFactoryNamesPluginAndName(t *testing.T) {
|
||||
fn := func(string) pact.Middleware {
|
||||
return func(next http.Handler) http.Handler { return next }
|
||||
}
|
||||
if err := r.RegisterMiddlewareFactory("golem15.fonoteka", "inv.scope", fn); err != nil {
|
||||
if err := r.RegisterMiddlewareFactory("golem15.acme", "inv.scope", fn); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err := r.RegisterMiddlewareFactory("golem15.other", "inv.scope", fn)
|
||||
if err == nil || !strings.Contains(err.Error(), "golem15.fonoteka") || !strings.Contains(err.Error(), "inv.scope") {
|
||||
if err == nil || !strings.Contains(err.Error(), "golem15.acme") || !strings.Contains(err.Error(), "inv.scope") {
|
||||
t.Fatalf("want plugin and factory name in error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user