From f71583fbc09504dbbf0742e53bdcebca53d424a3 Mon Sep 17 00:00:00 2001 From: shreyas-goenka <88374338+shreyas-goenka@users.noreply.github.com> Date: Fri, 7 Feb 2025 21:56:48 +0530 Subject: [PATCH] Error when unknown API endpoint is used in testserver (#2292) ## Changes This PR fails the acceptance test when an unknown endpoint (i.e. not stubbed) is used. We want to ensure that all API endpoints used in an acceptance test are stubbed and do not otherwise silently fail with a 404. The logs on failure output include a configuration that developers can simply copy-paste to `test.toml` to stub the missing API endpoint. It'll look something like: ``` [[Server]] Pattern = " " Response.Body = ''' ''' Response.StatusCode = ``` ## Tests Manually: output.txt when an endpoint is not found: ``` >>> [CLI] jobs create --json {"name":"abc"} Error: No stub found for pattern: POST /api/2.1/jobs/create ``` How this renders in the test logs: ``` --- FAIL: TestAccept/workspace/jobs/create (0.03s) server.go:46: ---------------------------------------- No stub found for pattern: POST /api/2.1/jobs/create To stub a response for this request, you can add the following to test.toml: [[Server]] Pattern = "POST /api/2.1/jobs/create" Response.Body = ''' ''' Response.StatusCode = ---------------------------------------- ``` Manually checked that the debug mode still works. --- acceptance/cmd_server_test.go | 5 ++++- libs/testserver/server.go | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/acceptance/cmd_server_test.go b/acceptance/cmd_server_test.go index 0166dfe32..c8a52f4cd 100644 --- a/acceptance/cmd_server_test.go +++ b/acceptance/cmd_server_test.go @@ -15,7 +15,10 @@ import ( func StartCmdServer(t *testing.T) *testserver.Server { server := testserver.New(t) - server.Handle("/", func(w *testserver.FakeWorkspace, r *http.Request) (any, int) { + // {$} is a wildcard that only matches the end of the URL. We explicitly use + // /{$} to disambiguate it from the generic handler for '/' which is used to + // identify unhandled API endpoints in the test server. + server.Handle("/{$}", func(w *testserver.FakeWorkspace, r *http.Request) (any, int) { q := r.URL.Query() args := strings.Split(q.Get("args"), " ") diff --git a/libs/testserver/server.go b/libs/testserver/server.go index ffb83a49c..9ccf34be0 100644 --- a/libs/testserver/server.go +++ b/libs/testserver/server.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/databricks/cli/internal/testutil" + "github.com/databricks/databricks-sdk-go/apierr" ) type Server struct { @@ -41,13 +42,44 @@ func New(t testutil.TestingT) *Server { server := httptest.NewServer(mux) t.Cleanup(server.Close) - return &Server{ + s := &Server{ Server: server, Mux: mux, t: t, mu: &sync.Mutex{}, fakeWorkspaces: map[string]*FakeWorkspace{}, } + + // The server resolves conflicting handlers by using the one with higher + // specificity. This handler is the least specific, so it will be used as a + // fallback when no other handlers match. + s.Handle("/", func(fakeWorkspace *FakeWorkspace, r *http.Request) (any, int) { + pattern := r.Method + " " + r.URL.Path + + t.Errorf(` + +---------------------------------------- +No stub found for pattern: %s + +To stub a response for this request, you can add +the following to test.toml: +[[Server]] +Pattern = %q +Response.Body = ''' + +''' +Response.StatusCode = +---------------------------------------- + + +`, pattern, pattern) + + return apierr.APIError{ + Message: "No stub found for pattern: " + pattern, + }, http.StatusNotFound + }) + + return s } type HandlerFunc func(fakeWorkspace *FakeWorkspace, req *http.Request) (resp any, statusCode int)