move config to toml

This commit is contained in:
Shreyas Goenka 2025-01-29 14:51:36 +01:00
parent 3549c22b40
commit 1f1d705de9
No known key found for this signature in database
GPG Key ID: 92A07DF49CCB0622
5 changed files with 37 additions and 64 deletions

View File

@ -2,10 +2,12 @@ package acceptance_test
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
"io" "io"
"net/http"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
@ -30,7 +32,7 @@ var KeepTmp bool
// In order to debug CLI running under acceptance test, set this to full subtest name, e.g. "bundle/variables/empty" // In order to debug CLI running under acceptance test, set this to full subtest name, e.g. "bundle/variables/empty"
// Then install your breakpoints and click "debug test" near TestAccept in VSCODE. // Then install your breakpoints and click "debug test" near TestAccept in VSCODE.
// example: var SingleTest = "bundle/variables/empty" // example: var SingleTest = "bundle/variables/empty"
var SingleTest = "" var SingleTest = "workspace/jobs/create"
// If enabled, instead of compiling and running CLI externally, we'll start in-process server that accepts and runs // If enabled, instead of compiling and running CLI externally, we'll start in-process server that accepts and runs
// CLI commands. The $CLI in test scripts is a helper that just forwards command-line arguments to this server (see bin/callserver.py). // CLI commands. The $CLI in test scripts is a helper that just forwards command-line arguments to this server (see bin/callserver.py).
@ -205,10 +207,17 @@ func runTest(t *testing.T, dir, coverDir string, repls testdiff.ReplacementsCont
cmdEnv := os.Environ() cmdEnv := os.Environ()
// If there is a server.json file in the test directory, start a custom server. // Load custom server stubs configured for the integration test.
// Redirect all API calls to this server. if len(config.Server) > 0 {
if testutil.DetectFile(t, filepath.Join(dir, "server.json")) { server := testserver.New(t)
server := testserver.NewFromConfig(t, filepath.Join(dir, "server.json")) for _, stub := range config.Server {
require.NotEmpty(t, stub.Pattern)
require.NotEmpty(t, stub.Response.Body)
server.Handle(stub.Pattern, func(req *http.Request) (resp any, err error) {
b := json.RawMessage(stub.Response.Body)
return b, nil
})
}
cmdEnv = setEnv(cmdEnv, "DATABRICKS_HOST", server.URL) cmdEnv = setEnv(cmdEnv, "DATABRICKS_HOST", server.URL)
t.Cleanup(func() { t.Cleanup(func() {
server.Close() server.Close()

View File

@ -8,6 +8,7 @@ import (
"github.com/BurntSushi/toml" "github.com/BurntSushi/toml"
"github.com/databricks/cli/libs/testdiff" "github.com/databricks/cli/libs/testdiff"
"github.com/databricks/cli/libs/testserver"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -29,6 +30,9 @@ type TestConfig struct {
// List of additional replacements to apply on this test. // List of additional replacements to apply on this test.
// Old is a regexp, New is a replacement expression. // Old is a regexp, New is a replacement expression.
Repls []testdiff.Replacement Repls []testdiff.Replacement
// List of server stubs to load.
Server []testserver.Stub
} }
// FindConfig finds the closest config file. // FindConfig finds the closest config file.

View File

@ -1,11 +0,0 @@
[
{
"method": "POST",
"path": "/api/2.1/jobs/create",
"response": {
"body": {
"job_id": 1111
}
}
}
]

View File

@ -0,0 +1,7 @@
[[Server]]
Pattern = "POST /api/2.1/jobs/create"
Response.Body = '''
{
"job_id": 1111
}
'''

View File

@ -6,8 +6,6 @@ import (
"net/http/httptest" "net/http/httptest"
"github.com/databricks/cli/internal/testutil" "github.com/databricks/cli/internal/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
type Server struct { type Server struct {
@ -15,17 +13,18 @@ type Server struct {
Mux *http.ServeMux Mux *http.ServeMux
t testutil.TestingT t testutil.TestingT
// API calls that we expect to be made.
calledPatterns map[string]bool
} }
type ApiSpec struct { type Stub struct {
Method string `json:"method"` // The HTTP method and path to match. Examples:
Path string `json:"path"` // 1. /api/2.0/clusters/list (matches all methods)
// 2. GET /api/2.0/clusters/list
Pattern string
// The response body to return.
Response struct { Response struct {
Body json.RawMessage `json:"body"` Body string
} `json:"response"` }
} }
func New(t testutil.TestingT) *Server { func New(t testutil.TestingT) *Server {
@ -33,50 +32,15 @@ func New(t testutil.TestingT) *Server {
server := httptest.NewServer(mux) server := httptest.NewServer(mux)
return &Server{ return &Server{
Server: server, Server: server,
Mux: mux, Mux: mux,
t: t, t: t,
calledPatterns: make(map[string]bool),
} }
} }
func NewFromConfig(t testutil.TestingT, path string) *Server {
content := testutil.ReadFile(t, path)
var apiSpecs []ApiSpec
err := json.Unmarshal([]byte(content), &apiSpecs)
require.NoError(t, err)
server := New(t)
for _, apiSpec := range apiSpecs {
server.MustHandle(apiSpec)
}
return server
}
type HandlerFunc func(req *http.Request) (resp any, err error) type HandlerFunc func(req *http.Request) (resp any, err error)
func (s *Server) MustHandle(apiSpec ApiSpec) {
assert.NotEmpty(s.t, apiSpec.Method)
assert.NotEmpty(s.t, apiSpec.Path)
pattern := apiSpec.Method + " " + apiSpec.Path
s.calledPatterns[pattern] = false
s.Handle(pattern, func(req *http.Request) (any, error) {
// Record the fact that this pattern was called.
s.calledPatterns[pattern] = true
// Return the expected response body.
return apiSpec.Response.Body, nil
})
}
func (s *Server) Close() { func (s *Server) Close() {
for pattern, called := range s.calledPatterns {
assert.Truef(s.t, called, "expected pattern %s to be called", pattern)
}
s.Server.Close() s.Server.Close()
} }