Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions acceptance/acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,16 +155,6 @@ func TestAccept(t *testing.T) {
testAccept(t, InprocessMode, nil, false)
}

// TestDmsAcc runs acceptance tests against local DMS, selected with go test -run.
// The in-process runner skips unrelated tool builds and old CLI downloads.
func TestDmsAcc(t *testing.T) {
if os.Getenv("DMS_LITEBOX_URL") == "" {
t.Skip("DMS_LITEBOX_URL is not set")
}
require.Empty(t, os.Getenv("CLOUD_ENV"), "Litebox must not use a cloud workspace")
testAccept(t, true, nil, true)
}

func TestInprocessMode(t *testing.T) {
if InprocessMode && !Forcerun {
t.Skip("Already tested by TestAccept")
Expand Down
34 changes: 11 additions & 23 deletions acceptance/internal/dms_litebox.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
"testing"
"time"

"github.com/databricks/cli/libs/env"
"github.com/databricks/cli/libs/testserver"
"github.com/stretchr/testify/require"
)
Expand All @@ -27,25 +26,19 @@ var liteboxPermissionTypes = []string{"directories", "files", "notebooks", "work
// to its shared fakes, retaining request recording and mocks for other APIs.
func configureDMSLitebox(t *testing.T, server *testserver.Server) {
t.Helper()
endpoint := env.Get(t.Context(), "DMS_LITEBOX_URL")
if endpoint == "" {
settings := loadDMSLiteboxSettings(t)
if settings == nil {
return
}
dmsURL := liteboxURL(t, "DMS_LITEBOX_URL")
workspaceURL := liteboxURL(t, "DMS_LITEBOX_WORKSPACE_URL")
dmsURL := liteboxURL(t, settings.URL)

certFile, keyFile := env.Get(t.Context(), "DMS_LITEBOX_CERT"), env.Get(t.Context(), "DMS_LITEBOX_KEY")
caFile := env.Get(t.Context(), "DMS_LITEBOX_CA")
require.NotEmpty(t, certFile, "DMS_LITEBOX_CERT is required with DMS_LITEBOX_URL")
require.NotEmpty(t, keyFile, "DMS_LITEBOX_KEY is required with DMS_LITEBOX_URL")
require.NotEmpty(t, caFile, "DMS_LITEBOX_CA is required with DMS_LITEBOX_URL")
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
cert, err := tls.LoadX509KeyPair(settings.Cert, settings.Key)
require.NoError(t, err, "load Litebox client certificate and key")
pem, err := os.ReadFile(caFile)
require.NoError(t, err, "read DMS_LITEBOX_CA")
pem, err := os.ReadFile(settings.CA)
require.NoError(t, err, "read Litebox CA certificate")
roots := x509.NewCertPool()
require.True(t, roots.AppendCertsFromPEM(pem), "invalid Litebox certificate")
// Both upstreams must use LITE's test certificate for *.svc.cluster.local.
// The LITE gateway uses the service's test certificate.
transport := &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
Expand All @@ -64,10 +57,7 @@ func configureDMSLitebox(t *testing.T, server *testserver.Server) {
},
}
handler := func(r testserver.Request) any {
target := *workspaceURL
if isDMSPath(r.URL.Path) {
target = *dmsURL
}
target := *dmsURL
target.Path, target.RawPath, target.RawQuery = r.URL.Path, r.URL.RawPath, r.URL.RawQuery
req, err := http.NewRequestWithContext(r.Context, r.Method, target.String(), bytes.NewReader(r.Body))
if err != nil {
Expand Down Expand Up @@ -95,16 +85,14 @@ func configureDMSLitebox(t *testing.T, server *testserver.Server) {
routeLitebox(server, handler)
}

func liteboxURL(t *testing.T, name string) *url.URL {
func liteboxURL(t *testing.T, endpoint string) *url.URL {
t.Helper()
endpoint := env.Get(t.Context(), name)
require.NotEmpty(t, endpoint, "%s is required with DMS_LITEBOX_URL", name)
u, err := url.Parse(endpoint)
require.NoError(t, err, "invalid %s", name)
require.NoError(t, err, "invalid DMS LITE gateway URL")
ip := net.ParseIP(u.Hostname())
require.True(t, u.Scheme == "https" && (u.Hostname() == "localhost" || (ip != nil && ip.IsLoopback())) &&
u.User == nil && u.RawQuery == "" && u.Fragment == "" && (u.Path == "" || u.Path == "/"),
"%s must be an HTTPS loopback origin", name)
"DMS LITE gateway URL must be an HTTPS loopback origin")
return u
}

Expand Down
65 changes: 65 additions & 0 deletions acceptance/internal/dms_litebox_settings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package internal

import (
"encoding/json"
"errors"
"os"
"path/filepath"
"testing"

"github.com/databricks/cli/libs/env"
"github.com/stretchr/testify/require"
)

type dmsLiteboxSettings struct {
URL string `json:"url"`
Cert string `json:"cert"`
Key string `json:"key"`
CA string `json:"ca"`
}

func loadDMSLiteboxSettings(t *testing.T) *dmsLiteboxSettings {
t.Helper()
acceptanceDir, err := os.Getwd()
require.NoError(t, err)
file := env.Get(t.Context(), "DMS_CLI_ENDPOINTS_FILE")
explicit := file != ""
if !explicit {
file = findDMSLiteboxSettings(t, filepath.Dir(acceptanceDir))
if file == "" {
return nil
}
}
if !filepath.IsAbs(file) {
file = filepath.Join(acceptanceDir, file)
}
data, err := os.ReadFile(file)
if !explicit && errors.Is(err, os.ErrNotExist) {
return nil
}
require.NoError(t, err, "read DMS LITE settings %s", file)
var settings dmsLiteboxSettings
require.NoError(t, json.Unmarshal(data, &settings), "parse DMS LITE settings %s", file)
require.NotEmpty(t, settings.URL, "DMS LITE settings %s: url is required", file)
require.NotEmpty(t, settings.Cert, "DMS LITE settings %s: cert is required", file)
require.NotEmpty(t, settings.Key, "DMS LITE settings %s: key is required", file)
require.NotEmpty(t, settings.CA, "DMS LITE settings %s: ca is required", file)
return &settings
}

func findDMSLiteboxSettings(t *testing.T, dir string) string {
t.Helper()
for {
file := filepath.Join(dir, "bundle", "metadata-service", "test", ".lite", "cli-endpoints.json")
_, err := os.Stat(file)
if err == nil {
return file
}
require.ErrorIs(t, err, os.ErrNotExist, "find DMS LITE settings %s", file)
parent := filepath.Dir(dir)
if parent == dir {
return ""
}
dir = parent
}
}
Loading