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
2 changes: 1 addition & 1 deletion acceptance/acceptance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func TestAccept(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, user)
testdiff.PrepareReplacementsUser(t, &repls, *user)
testdiff.PrepareReplacements(t, &repls, workspaceClient)
testdiff.PrepareReplacementsWorkspaceClient(t, &repls, workspaceClient)

testDirs := getTests(t)
require.NotEmpty(t, testDirs)
Expand Down
5 changes: 4 additions & 1 deletion integration/bundle/init_default_python_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ func testDefaultPython(t *testing.T, pythonVersion string) {
require.NoError(t, err)
require.NotNil(t, user)
testdiff.PrepareReplacementsUser(t, replacements, *user)
testdiff.PrepareReplacements(t, replacements, wt.W)
testdiff.PrepareReplacementsWorkspaceClient(t, replacements, wt.W)
testdiff.PrepareReplacementsUUID(t, replacements)
testdiff.PrepareReplacementsNumber(t, replacements)
testdiff.PrepareReplacementsTemporaryDirectory(t, replacements)

tmpDir := t.TempDir()
testutil.Chdir(t, tmpDir)
Expand Down
34 changes: 34 additions & 0 deletions libs/testdiff/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package testdiff

import (
"context"
)

type key int

const (
replacementsMapKey = key(1)
)

func WithReplacementsMap(ctx context.Context) (context.Context, *ReplacementsContext) {
value := ctx.Value(replacementsMapKey)
if value != nil {
if existingMap, ok := value.(*ReplacementsContext); ok {
return ctx, existingMap
}
}

newMap := &ReplacementsContext{}
ctx = context.WithValue(ctx, replacementsMapKey, newMap)
return ctx, newMap
}

func GetReplacementsMap(ctx context.Context) *ReplacementsContext {
value := ctx.Value(replacementsMapKey)
if value != nil {
if existingMap, ok := value.(*ReplacementsContext); ok {
return existingMap
}
}
return nil
}
30 changes: 30 additions & 0 deletions libs/testdiff/context_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package testdiff

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetReplacementsMap_Nil(t *testing.T) {
ctx := context.Background()
repls := GetReplacementsMap(ctx)
assert.Nil(t, repls)
}

func TestGetReplacementsMap_NotNil(t *testing.T) {
ctx := context.Background()
ctx, _ = WithReplacementsMap(ctx)
repls := GetReplacementsMap(ctx)
assert.NotNil(t, repls)
}

func TestWithReplacementsMap_UseExisting(t *testing.T) {
ctx := context.Background()
ctx, r1 := WithReplacementsMap(ctx)
ctx, r2 := WithReplacementsMap(ctx)
repls := GetReplacementsMap(ctx)
assert.Equal(t, r1, repls)
assert.Equal(t, r2, repls)
}
150 changes: 1 addition & 149 deletions libs/testdiff/golden.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,15 @@ package testdiff

import (
"context"
"encoding/json"
"flag"
"fmt"
"os"
"regexp"
"strings"
"testing"

"github.com/databricks/cli/internal/testutil"
"github.com/databricks/cli/libs/iamutil"
"github.com/databricks/databricks-sdk-go"
"github.com/databricks/databricks-sdk-go/service/iam"
"github.com/stretchr/testify/assert"
)

const (
testerName = "$USERNAME"
)

var OverwriteMode = false

func init() {
Expand Down Expand Up @@ -75,152 +65,14 @@ func AssertOutputJQ(t testutil.TestingT, ctx context.Context, out, outTitle, exp
}
}

var (
uuidRegex = regexp.MustCompile(`[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}`)
numIdRegex = regexp.MustCompile(`[0-9]{3,}`)
privatePathRegex = regexp.MustCompile(`(/tmp|/private)(/.*)/([a-zA-Z0-9]+)`)
)

func ReplaceOutput(t testutil.TestingT, ctx context.Context, out string) string {
t.Helper()
out = NormalizeNewlines(out)
replacements := GetReplacementsMap(ctx)
if replacements == nil {
t.Fatal("WithReplacementsMap was not called")
}
out = replacements.Replace(out)
out = uuidRegex.ReplaceAllString(out, "<UUID>")
out = numIdRegex.ReplaceAllString(out, "<NUMID>")
out = privatePathRegex.ReplaceAllString(out, "/tmp/.../$3")

return out
}

type key int

const (
replacementsMapKey = key(1)
)

type Replacement struct {
Old string
New string
}

type ReplacementsContext struct {
Repls []Replacement
}

func (r *ReplacementsContext) Replace(s string) string {
// QQQ Should probably only replace whole words
for _, repl := range r.Repls {
s = strings.ReplaceAll(s, repl.Old, repl.New)
}
return s
}

func (r *ReplacementsContext) Set(old, new string) {
if old == "" || new == "" {
return
}

// Always include both verbatim and json version of replacement.
// This helps when the string in question contains \ or other chars that need to be quoted.
// In that case we cannot rely that json(old) == '"{old}"' and need to add it explicitly.

encodedNew, err := json.Marshal(new)
if err == nil {
encodedOld, err := json.Marshal(old)
if err == nil {
r.Repls = append(r.Repls, Replacement{Old: string(encodedOld), New: string(encodedNew)})
}
}

r.Repls = append(r.Repls, Replacement{Old: old, New: new})
}

func WithReplacementsMap(ctx context.Context) (context.Context, *ReplacementsContext) {
value := ctx.Value(replacementsMapKey)
if value != nil {
if existingMap, ok := value.(*ReplacementsContext); ok {
return ctx, existingMap
}
}

newMap := &ReplacementsContext{}
ctx = context.WithValue(ctx, replacementsMapKey, newMap)
return ctx, newMap
}

func GetReplacementsMap(ctx context.Context) *ReplacementsContext {
value := ctx.Value(replacementsMapKey)
if value != nil {
if existingMap, ok := value.(*ReplacementsContext); ok {
return existingMap
}
}
return nil
}

func PrepareReplacements(t testutil.TestingT, r *ReplacementsContext, w *databricks.WorkspaceClient) {
t.Helper()
// in some clouds (gcp) w.Config.Host includes "https://" prefix in others it's really just a host (azure)
host := strings.TrimPrefix(strings.TrimPrefix(w.Config.Host, "http://"), "https://")
r.Set(host, "$DATABRICKS_HOST")
r.Set(w.Config.ClusterID, "$DATABRICKS_CLUSTER_ID")
r.Set(w.Config.WarehouseID, "$DATABRICKS_WAREHOUSE_ID")
r.Set(w.Config.ServerlessComputeID, "$DATABRICKS_SERVERLESS_COMPUTE_ID")
r.Set(w.Config.MetadataServiceURL, "$DATABRICKS_METADATA_SERVICE_URL")
r.Set(w.Config.AccountID, "$DATABRICKS_ACCOUNT_ID")
r.Set(w.Config.Token, "$DATABRICKS_TOKEN")
r.Set(w.Config.Username, "$DATABRICKS_USERNAME")
r.Set(w.Config.Password, "$DATABRICKS_PASSWORD")
r.Set(w.Config.Profile, "$DATABRICKS_CONFIG_PROFILE")
r.Set(w.Config.ConfigFile, "$DATABRICKS_CONFIG_FILE")
r.Set(w.Config.GoogleServiceAccount, "$DATABRICKS_GOOGLE_SERVICE_ACCOUNT")
r.Set(w.Config.GoogleCredentials, "$GOOGLE_CREDENTIALS")
r.Set(w.Config.AzureResourceID, "$DATABRICKS_AZURE_RESOURCE_ID")
r.Set(w.Config.AzureClientSecret, "$ARM_CLIENT_SECRET")
// r.Set(w.Config.AzureClientID, "$ARM_CLIENT_ID")
r.Set(w.Config.AzureClientID, testerName)
r.Set(w.Config.AzureTenantID, "$ARM_TENANT_ID")
r.Set(w.Config.ActionsIDTokenRequestURL, "$ACTIONS_ID_TOKEN_REQUEST_URL")
r.Set(w.Config.ActionsIDTokenRequestToken, "$ACTIONS_ID_TOKEN_REQUEST_TOKEN")
r.Set(w.Config.AzureEnvironment, "$ARM_ENVIRONMENT")
r.Set(w.Config.ClientID, "$DATABRICKS_CLIENT_ID")
r.Set(w.Config.ClientSecret, "$DATABRICKS_CLIENT_SECRET")
r.Set(w.Config.DatabricksCliPath, "$DATABRICKS_CLI_PATH")
// This is set to words like "path" that happen too frequently
// r.Set(w.Config.AuthType, "$DATABRICKS_AUTH_TYPE")
}

func PrepareReplacementsUser(t testutil.TestingT, r *ReplacementsContext, u iam.User) {
t.Helper()
// There could be exact matches or overlap between different name fields, so sort them by length
// to ensure we match the largest one first and map them all to the same token

r.Set(u.UserName, testerName)
r.Set(u.DisplayName, testerName)
if u.Name != nil {
r.Set(u.Name.FamilyName, testerName)
r.Set(u.Name.GivenName, testerName)
}

for _, val := range u.Emails {
r.Set(val.Value, testerName)
}

r.Set(iamutil.GetShortUserName(&u), testerName)

for ind, val := range u.Groups {
r.Set(val.Value, fmt.Sprintf("$USER.Groups[%d]", ind))
}

r.Set(u.Id, "$USER.Id")

for ind, val := range u.Roles {
r.Set(val.Value, fmt.Sprintf("$USER.Roles[%d]", ind))
}
return replacements.Replace(out)
}

func NormalizeNewlines(input string) string {
Expand Down
Loading