From 687540e0ce2d3386f335086968896940472cc152 Mon Sep 17 00:00:00 2001 From: Frederic BIDON Date: Sun, 16 Aug 2026 17:10:19 +0200 Subject: [PATCH] test(normalize): rebase remote refs against a local httptest server The remote ref cases used a hardcoded https://example.com base, a domain we don't control. They now rebase against an httptest TLS server, so the base URL is locally owned and carries a port, a shape the previous fixture never covered. A closing check fetches the rebased ref to confirm it resolves against that server. Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Frederic BIDON --- internal/flatten/normalize/normalize_test.go | 106 +++++++++++++------ 1 file changed, 75 insertions(+), 31 deletions(-) diff --git a/internal/flatten/normalize/normalize_test.go b/internal/flatten/normalize/normalize_test.go index 680147c..f52baa5 100644 --- a/internal/flatten/normalize/normalize_test.go +++ b/internal/flatten/normalize/normalize_test.go @@ -4,6 +4,9 @@ package normalize import ( + "io" + "net/http" + "net/http/httptest" "net/url" "path/filepath" "runtime" @@ -12,13 +15,13 @@ import ( _ "github.com/go-openapi/analysis/internal/antest" "github.com/go-openapi/spec" "github.com/go-openapi/testify/v2/assert" + "github.com/go-openapi/testify/v2/require" ) const ( definitionA = "#/definitions/A" definitionABC = "#/definitions/abc" definitionBase = "#/definitions/base" - exampleBase = "https://example.com/base" ) func TestNormalize_Path(t *testing.T) { @@ -42,36 +45,77 @@ func TestNormalize_Path(t *testing.T) { func TestNormalize_RebaseRef(t *testing.T) { t.Parallel() - assert.EqualT(t, definitionABC, RebaseRef(definitionBase, definitionABC)) - assert.EqualT(t, definitionABC, RebaseRef("", definitionABC)) - assert.EqualT(t, definitionABC, RebaseRef(".", definitionABC)) - assert.EqualT(t, "otherfile"+definitionABC, RebaseRef("file"+definitionBase, "otherfile"+definitionABC)) - assert.EqualT(t, - wrapWindowsPath("../otherfile")+definitionABC, - RebaseRef(wrapWindowsPath("../file")+definitionBase, wrapWindowsPath("./otherfile")+definitionABC), - ) - assert.EqualT(t, - wrapWindowsPath("../otherfile")+definitionABC, - RebaseRef(wrapWindowsPath("../file")+definitionBase, wrapWindowsPath("otherfile")+definitionABC), - ) - assert.EqualT(t, - wrapWindowsPath("local/remote/otherfile")+definitionABC, - RebaseRef(wrapWindowsPath("local/file")+definitionBase, wrapWindowsPath("remote/otherfile")+definitionABC), - ) - assert.EqualT(t, - wrapWindowsPath("local/remote/otherfile.yaml"), - RebaseRef(wrapWindowsPath("local/file.yaml"), wrapWindowsPath("remote/otherfile.yaml")), - ) - - assert.EqualT(t, "file#/definitions/abc", RebaseRef("file#/definitions/base", definitionABC)) - - // with remote - assert.EqualT(t, exampleBase+definitionABC, RebaseRef(exampleBase, exampleBase+definitionABC)) - assert.EqualT(t, exampleBase+definitionABC, RebaseRef(exampleBase, definitionABC)) - assert.EqualT(t, exampleBase+"#/dir/definitions/abc", RebaseRef(exampleBase, "#/dir/definitions/abc")) - assert.EqualT(t, exampleBase+"/dir/definitions/abc", RebaseRef(exampleBase+"/spec.yaml", "dir/definitions/abc")) - assert.EqualT(t, exampleBase+"/dir/definitions/abc", RebaseRef(exampleBase+"/", "dir/definitions/abc")) - assert.EqualT(t, "https://example.com/dir/definitions/abc", RebaseRef(exampleBase, "dir/definitions/abc")) + t.Run("with local refs", func(t *testing.T) { + t.Parallel() + + assert.EqualT(t, definitionABC, RebaseRef(definitionBase, definitionABC)) + assert.EqualT(t, definitionABC, RebaseRef("", definitionABC)) + assert.EqualT(t, definitionABC, RebaseRef(".", definitionABC)) + assert.EqualT(t, "otherfile"+definitionABC, RebaseRef("file"+definitionBase, "otherfile"+definitionABC)) + assert.EqualT(t, + wrapWindowsPath("../otherfile")+definitionABC, + RebaseRef(wrapWindowsPath("../file")+definitionBase, wrapWindowsPath("./otherfile")+definitionABC), + ) + assert.EqualT(t, + wrapWindowsPath("../otherfile")+definitionABC, + RebaseRef(wrapWindowsPath("../file")+definitionBase, wrapWindowsPath("otherfile")+definitionABC), + ) + assert.EqualT(t, + wrapWindowsPath("local/remote/otherfile")+definitionABC, + RebaseRef(wrapWindowsPath("local/file")+definitionBase, wrapWindowsPath("remote/otherfile")+definitionABC), + ) + assert.EqualT(t, + wrapWindowsPath("local/remote/otherfile.yaml"), + RebaseRef(wrapWindowsPath("local/file.yaml"), wrapWindowsPath("remote/otherfile.yaml")), + ) + + assert.EqualT(t, "file#/definitions/abc", RebaseRef("file#/definitions/base", definitionABC)) + }) + + t.Run("with remote refs", func(t *testing.T) { + t.Parallel() + + server := remoteSpecServer(t) + remoteBase := server.URL + "/base" + + assert.EqualT(t, remoteBase+definitionABC, RebaseRef(remoteBase, remoteBase+definitionABC)) + assert.EqualT(t, remoteBase+definitionABC, RebaseRef(remoteBase, definitionABC)) + assert.EqualT(t, remoteBase+"#/dir/definitions/abc", RebaseRef(remoteBase, "#/dir/definitions/abc")) + assert.EqualT(t, remoteBase+"/dir/definitions/abc", RebaseRef(remoteBase+"/spec.yaml", "dir/definitions/abc")) + assert.EqualT(t, remoteBase+"/dir/definitions/abc", RebaseRef(remoteBase+"/", "dir/definitions/abc")) + assert.EqualT(t, server.URL+"/dir/definitions/abc", RebaseRef(remoteBase, "dir/definitions/abc")) + + t.Run("rebased ref should point to a reachable document", func(t *testing.T) { + rebased := RebaseRef(remoteBase, "dir/definitions/abc") + + req, err := http.NewRequestWithContext(t.Context(), http.MethodGet, rebased, nil) + require.NoError(t, err) + + resp, err := server.Client().Do(req) + require.NoError(t, err) + t.Cleanup(func() { _ = resp.Body.Close() }) + + assert.EqualT(t, http.StatusOK, resp.StatusCode) + }) + }) +} + +// remoteSpecServer starts a local TLS server standing in for a remote spec host. +// +// It serves a stub document at any path, so that refs rebased against it +// resolve to a real, locally owned origin instead of a domain we don't control. +func remoteSpecServer(t testing.TB) *httptest.Server { + t.Helper() + + const stub = `{"definitions":{"abc":{"type":"string"}}}` + + server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("Content-Type", "application/json") + _, _ = io.WriteString(w, stub) + })) + t.Cleanup(server.Close) + + return server } // wrapWindowsPath adapts path expectations for tests running on windows.