Compare commits

..

No commits in common. "ac37ca0d9825297bf28644caab4206a32563cf84" and "8ec1e0746d4dad9bb8ff56f2e0e8ef262bcd8d3b" have entirely different histories.

98 changed files with 367 additions and 491 deletions

View File

@ -55,7 +55,7 @@ jobs:
pip3 install wheel pip3 install wheel
- name: Run tests - name: Run tests
run: make test run: make testonly
golangci: golangci:
name: lint name: lint
@ -75,7 +75,7 @@ jobs:
- name: golangci-lint - name: golangci-lint
uses: golangci/golangci-lint-action@v6 uses: golangci/golangci-lint-action@v6
with: with:
version: v1.63.1 version: v1.62.2
args: --timeout=15m args: --timeout=15m
validate-bundle-schema: validate-bundle-schema:
@ -90,13 +90,6 @@ jobs:
with: with:
go-version: 1.23.4 go-version: 1.23.4
- name: Verify that the schema is up to date
run: |
if ! ( make schema && git diff --exit-code ); then
echo "The schema is not up to date. Please run 'make schema' and commit the changes."
exit 1
fi
# Github repo: https://github.com/ajv-validator/ajv-cli # Github repo: https://github.com/ajv-validator/ajv-cli
- name: Install ajv-cli - name: Install ajv-cli
run: npm install -g ajv-cli@5.0.0 run: npm install -g ajv-cli@5.0.0

View File

@ -11,7 +11,6 @@ linters:
- gofmt - gofmt
- gofumpt - gofumpt
- goimports - goimports
- testifylint
linters-settings: linters-settings:
govet: govet:
enable-all: true enable-all: true
@ -33,12 +32,7 @@ linters-settings:
gofumpt: gofumpt:
module-path: github.com/databricks/cli module-path: github.com/databricks/cli
extra-rules: true extra-rules: true
testifylint: #goimports:
enable-all: true # local-prefixes: github.com/databricks/cli
disable:
# good check, but we have too many assert.(No)?Errorf? so excluding for now
- require-error
issues: issues:
exclude-dirs-use-default: false # recommended by docs https://golangci-lint.run/usage/false-positives/ exclude-dirs-use-default: false # recommended by docs https://golangci-lint.run/usage/false-positives/
max-issues-per-linter: 1000
max-same-issues: 1000

View File

@ -1,33 +1,38 @@
default: build default: build
PACKAGES=./libs/... ./internal/... ./cmd/... ./bundle/... . lint: vendor
@echo "✓ Linting source code with https://golangci-lint.run/ (with --fix)..."
@./lint.sh ./...
lint: lintcheck: vendor
./lint.sh ./... @echo "✓ Linting source code with https://golangci-lint.run/ ..."
@golangci-lint run ./...
lintcheck: test: lint testonly
golangci-lint run ./...
test: testonly:
gotestsum --format pkgname-and-test-fails --no-summary=skipped -- ${PACKAGES} @echo "✓ Running tests ..."
@gotestsum --format pkgname-and-test-fails --no-summary=skipped --raw-command go test -v -json -short -coverprofile=coverage.txt ./...
cover: coverage: test
gotestsum --format pkgname-and-test-fails --no-summary=skipped -- -coverprofile=coverage.txt ${PACKAGES} @echo "✓ Opening coverage for unit tests ..."
@go tool cover -html=coverage.txt
showcover:
go tool cover -html=coverage.txt
build: vendor build: vendor
go build -mod vendor @echo "✓ Building source code with go build ..."
@go build -mod vendor
snapshot: snapshot:
go build -o .databricks/databricks @echo "✓ Building dev snapshot"
@go build -o .databricks/databricks
vendor: vendor:
go mod vendor @echo "✓ Filling vendor folder with library code ..."
@go mod vendor
schema: schema:
go run ./bundle/internal/schema ./bundle/internal/schema ./bundle/schema/jsonschema.json @echo "✓ Generating json-schema ..."
@go run ./bundle/internal/schema ./bundle/internal/schema ./bundle/schema/jsonschema.json
INTEGRATION = gotestsum --format github-actions --rerun-fails --jsonfile output.json --packages "./integration/..." -- -parallel 4 -timeout=2h INTEGRATION = gotestsum --format github-actions --rerun-fails --jsonfile output.json --packages "./integration/..." -- -parallel 4 -timeout=2h
@ -37,4 +42,4 @@ integration:
integration-short: integration-short:
$(INTEGRATION) -short $(INTEGRATION) -short
.PHONY: lint lintcheck test cover showcover build snapshot vendor schema integration integration-short .PHONY: lint lintcheck test testonly coverage build snapshot vendor schema integration integration-short

View File

@ -97,7 +97,7 @@ func (m *expandGlobs) Apply(ctx context.Context, b *bundle.Bundle) diag.Diagnost
return dyn.SetByPath(v, base, dyn.V(output)) return dyn.SetByPath(v, base, dyn.V(output))
}) })
if err != nil { if err != nil {
diags = diags.Extend(diag.FromErr(err)) return diag.FromErr(err)
} }
return diags return diags

View File

@ -2,6 +2,7 @@ package bundle
import ( import (
"context" "context"
"errors"
"io/fs" "io/fs"
"os" "os"
"path/filepath" "path/filepath"
@ -15,7 +16,7 @@ import (
func TestLoadNotExists(t *testing.T) { func TestLoadNotExists(t *testing.T) {
b, err := Load(context.Background(), "/doesntexist") b, err := Load(context.Background(), "/doesntexist")
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
assert.Nil(t, b) assert.Nil(t, b)
} }

View File

@ -109,19 +109,19 @@ func TestConfigureDashboardDefaultsEmbedCredentials(t *testing.T) {
// Set to true; still true. // Set to true; still true.
v, err = dyn.Get(b.Config.Value(), "resources.dashboards.d1.embed_credentials") v, err = dyn.Get(b.Config.Value(), "resources.dashboards.d1.embed_credentials")
if assert.NoError(t, err) { if assert.NoError(t, err) {
assert.True(t, v.MustBool()) assert.Equal(t, true, v.MustBool())
} }
// Set to false; still false. // Set to false; still false.
v, err = dyn.Get(b.Config.Value(), "resources.dashboards.d2.embed_credentials") v, err = dyn.Get(b.Config.Value(), "resources.dashboards.d2.embed_credentials")
if assert.NoError(t, err) { if assert.NoError(t, err) {
assert.False(t, v.MustBool()) assert.Equal(t, false, v.MustBool())
} }
// Not set; now false. // Not set; now false.
v, err = dyn.Get(b.Config.Value(), "resources.dashboards.d3.embed_credentials") v, err = dyn.Get(b.Config.Value(), "resources.dashboards.d3.embed_credentials")
if assert.NoError(t, err) { if assert.NoError(t, err) {
assert.False(t, v.MustBool()) assert.Equal(t, false, v.MustBool())
} }
// No valid dashboard; no change. // No valid dashboard; no change.

View File

@ -28,8 +28,8 @@ func TestDefaultQueueingApplyNoJobs(t *testing.T) {
}, },
} }
d := bundle.Apply(context.Background(), b, DefaultQueueing()) d := bundle.Apply(context.Background(), b, DefaultQueueing())
assert.Empty(t, d) assert.Len(t, d, 0)
assert.Empty(t, b.Config.Resources.Jobs) assert.Len(t, b.Config.Resources.Jobs, 0)
} }
func TestDefaultQueueingApplyJobsAlreadyEnabled(t *testing.T) { func TestDefaultQueueingApplyJobsAlreadyEnabled(t *testing.T) {
@ -47,7 +47,7 @@ func TestDefaultQueueingApplyJobsAlreadyEnabled(t *testing.T) {
}, },
} }
d := bundle.Apply(context.Background(), b, DefaultQueueing()) d := bundle.Apply(context.Background(), b, DefaultQueueing())
assert.Empty(t, d) assert.Len(t, d, 0)
assert.True(t, b.Config.Resources.Jobs["job"].Queue.Enabled) assert.True(t, b.Config.Resources.Jobs["job"].Queue.Enabled)
} }
@ -66,7 +66,7 @@ func TestDefaultQueueingApplyEnableQueueing(t *testing.T) {
}, },
} }
d := bundle.Apply(context.Background(), b, DefaultQueueing()) d := bundle.Apply(context.Background(), b, DefaultQueueing())
assert.Empty(t, d) assert.Len(t, d, 0)
assert.NotNil(t, b.Config.Resources.Jobs["job"].Queue) assert.NotNil(t, b.Config.Resources.Jobs["job"].Queue)
assert.True(t, b.Config.Resources.Jobs["job"].Queue.Enabled) assert.True(t, b.Config.Resources.Jobs["job"].Queue.Enabled)
} }
@ -96,7 +96,7 @@ func TestDefaultQueueingApplyWithMultipleJobs(t *testing.T) {
}, },
} }
d := bundle.Apply(context.Background(), b, DefaultQueueing()) d := bundle.Apply(context.Background(), b, DefaultQueueing())
assert.Empty(t, d) assert.Len(t, d, 0)
assert.False(t, b.Config.Resources.Jobs["job1"].Queue.Enabled) assert.False(t, b.Config.Resources.Jobs["job1"].Queue.Enabled)
assert.True(t, b.Config.Resources.Jobs["job2"].Queue.Enabled) assert.True(t, b.Config.Resources.Jobs["job2"].Queue.Enabled)
assert.True(t, b.Config.Resources.Jobs["job3"].Queue.Enabled) assert.True(t, b.Config.Resources.Jobs["job3"].Queue.Enabled)

View File

@ -44,7 +44,7 @@ func TestEnvironmentsToTargetsWithEnvironmentsDefined(t *testing.T) {
diags := bundle.Apply(context.Background(), b, mutator.EnvironmentsToTargets()) diags := bundle.Apply(context.Background(), b, mutator.EnvironmentsToTargets())
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
assert.Empty(t, b.Config.Environments) assert.Len(t, b.Config.Environments, 0)
assert.Len(t, b.Config.Targets, 1) assert.Len(t, b.Config.Targets, 1)
} }
@ -61,6 +61,6 @@ func TestEnvironmentsToTargetsWithTargetsDefined(t *testing.T) {
diags := bundle.Apply(context.Background(), b, mutator.EnvironmentsToTargets()) diags := bundle.Apply(context.Background(), b, mutator.EnvironmentsToTargets())
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
assert.Empty(t, b.Config.Environments) assert.Len(t, b.Config.Environments, 0)
assert.Len(t, b.Config.Targets, 1) assert.Len(t, b.Config.Targets, 1)
} }

View File

@ -74,8 +74,8 @@ func TestMergeJobTasks(t *testing.T) {
assert.Equal(t, "i3.2xlarge", cluster.NodeTypeId) assert.Equal(t, "i3.2xlarge", cluster.NodeTypeId)
assert.Equal(t, 4, cluster.NumWorkers) assert.Equal(t, 4, cluster.NumWorkers)
assert.Len(t, task0.Libraries, 2) assert.Len(t, task0.Libraries, 2)
assert.Equal(t, "package1", task0.Libraries[0].Whl) assert.Equal(t, task0.Libraries[0].Whl, "package1")
assert.Equal(t, "package2", task0.Libraries[1].Pypi.Package) assert.Equal(t, task0.Libraries[1].Pypi.Package, "package2")
// This task was left untouched. // This task was left untouched.
task1 := j.Tasks[1].NewCluster task1 := j.Tasks[1].NewCluster

View File

@ -163,18 +163,18 @@ func TestProcessTargetModeDevelopment(t *testing.T) {
// Job 1 // Job 1
assert.Equal(t, "[dev lennart] job1", b.Config.Resources.Jobs["job1"].Name) assert.Equal(t, "[dev lennart] job1", b.Config.Resources.Jobs["job1"].Name)
assert.Equal(t, "tag", b.Config.Resources.Jobs["job1"].Tags["existing"]) assert.Equal(t, b.Config.Resources.Jobs["job1"].Tags["existing"], "tag")
assert.Equal(t, "lennart", b.Config.Resources.Jobs["job1"].Tags["dev"]) assert.Equal(t, b.Config.Resources.Jobs["job1"].Tags["dev"], "lennart")
assert.Equal(t, jobs.PauseStatusPaused, b.Config.Resources.Jobs["job1"].Schedule.PauseStatus) assert.Equal(t, b.Config.Resources.Jobs["job1"].Schedule.PauseStatus, jobs.PauseStatusPaused)
// Job 2 // Job 2
assert.Equal(t, "[dev lennart] job2", b.Config.Resources.Jobs["job2"].Name) assert.Equal(t, "[dev lennart] job2", b.Config.Resources.Jobs["job2"].Name)
assert.Equal(t, "lennart", b.Config.Resources.Jobs["job2"].Tags["dev"]) assert.Equal(t, b.Config.Resources.Jobs["job2"].Tags["dev"], "lennart")
assert.Equal(t, jobs.PauseStatusUnpaused, b.Config.Resources.Jobs["job2"].Schedule.PauseStatus) assert.Equal(t, b.Config.Resources.Jobs["job2"].Schedule.PauseStatus, jobs.PauseStatusUnpaused)
// Pipeline 1 // Pipeline 1
assert.Equal(t, "[dev lennart] pipeline1", b.Config.Resources.Pipelines["pipeline1"].Name) assert.Equal(t, "[dev lennart] pipeline1", b.Config.Resources.Pipelines["pipeline1"].Name)
assert.False(t, b.Config.Resources.Pipelines["pipeline1"].Continuous) assert.Equal(t, false, b.Config.Resources.Pipelines["pipeline1"].Continuous)
assert.True(t, b.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Development) assert.True(t, b.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Development)
// Experiment 1 // Experiment 1

View File

@ -40,7 +40,6 @@ func (m *resolveResourceReferences) Apply(ctx context.Context, b *bundle.Bundle)
}) })
} }
// Note, diags are lost from all goroutines except the first one to return diag
return diag.FromErr(errs.Wait()) return diag.FromErr(errs.Wait())
} }

View File

@ -185,11 +185,11 @@ func TestResolveVariableReferencesForPrimitiveNonStringFields(t *testing.T) {
// Apply for the variable prefix. This should resolve the variables to their values. // Apply for the variable prefix. This should resolve the variables to their values.
diags = bundle.Apply(context.Background(), b, ResolveVariableReferences("variables")) diags = bundle.Apply(context.Background(), b, ResolveVariableReferences("variables"))
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
assert.True(t, b.Config.Resources.Jobs["job1"].JobSettings.NotificationSettings.NoAlertForCanceledRuns) assert.Equal(t, true, b.Config.Resources.Jobs["job1"].JobSettings.NotificationSettings.NoAlertForCanceledRuns)
assert.True(t, b.Config.Resources.Jobs["job1"].JobSettings.NotificationSettings.NoAlertForSkippedRuns) assert.Equal(t, true, b.Config.Resources.Jobs["job1"].JobSettings.NotificationSettings.NoAlertForSkippedRuns)
assert.Equal(t, 1, b.Config.Resources.Jobs["job1"].JobSettings.Tasks[0].NewCluster.Autoscale.MinWorkers) assert.Equal(t, 1, b.Config.Resources.Jobs["job1"].JobSettings.Tasks[0].NewCluster.Autoscale.MinWorkers)
assert.Equal(t, 2, b.Config.Resources.Jobs["job1"].JobSettings.Tasks[0].NewCluster.Autoscale.MaxWorkers) assert.Equal(t, 2, b.Config.Resources.Jobs["job1"].JobSettings.Tasks[0].NewCluster.Autoscale.MaxWorkers)
assert.InDelta(t, 0.5, b.Config.Resources.Jobs["job1"].JobSettings.Tasks[0].NewCluster.AzureAttributes.SpotBidMaxPrice, 0.0001) assert.Equal(t, 0.5, b.Config.Resources.Jobs["job1"].JobSettings.Tasks[0].NewCluster.AzureAttributes.SpotBidMaxPrice)
} }
func TestResolveComplexVariable(t *testing.T) { func TestResolveComplexVariable(t *testing.T) {

View File

@ -71,7 +71,7 @@ func TestNoWorkspacePrefixUsed(t *testing.T) {
} }
for _, d := range diags { for _, d := range diags {
require.Equal(t, diag.Warning, d.Severity) require.Equal(t, d.Severity, diag.Warning)
require.Contains(t, expectedErrors, d.Summary) require.Contains(t, expectedErrors, d.Summary)
delete(expectedErrors, d.Summary) delete(expectedErrors, d.Summary)
} }

View File

@ -30,7 +30,7 @@ func TestSetVariableFromProcessEnvVar(t *testing.T) {
err = convert.ToTyped(&variable, v) err = convert.ToTyped(&variable, v)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "process-env", variable.Value) assert.Equal(t, variable.Value, "process-env")
} }
func TestSetVariableUsingDefaultValue(t *testing.T) { func TestSetVariableUsingDefaultValue(t *testing.T) {
@ -48,7 +48,7 @@ func TestSetVariableUsingDefaultValue(t *testing.T) {
err = convert.ToTyped(&variable, v) err = convert.ToTyped(&variable, v)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "default", variable.Value) assert.Equal(t, variable.Value, "default")
} }
func TestSetVariableWhenAlreadyAValueIsAssigned(t *testing.T) { func TestSetVariableWhenAlreadyAValueIsAssigned(t *testing.T) {
@ -70,7 +70,7 @@ func TestSetVariableWhenAlreadyAValueIsAssigned(t *testing.T) {
err = convert.ToTyped(&variable, v) err = convert.ToTyped(&variable, v)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "assigned-value", variable.Value) assert.Equal(t, variable.Value, "assigned-value")
} }
func TestSetVariableEnvVarValueDoesNotOverridePresetValue(t *testing.T) { func TestSetVariableEnvVarValueDoesNotOverridePresetValue(t *testing.T) {
@ -95,7 +95,7 @@ func TestSetVariableEnvVarValueDoesNotOverridePresetValue(t *testing.T) {
err = convert.ToTyped(&variable, v) err = convert.ToTyped(&variable, v)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "assigned-value", variable.Value) assert.Equal(t, variable.Value, "assigned-value")
} }
func TestSetVariablesErrorsIfAValueCouldNotBeResolved(t *testing.T) { func TestSetVariablesErrorsIfAValueCouldNotBeResolved(t *testing.T) {

View File

@ -37,11 +37,11 @@ func TestCustomMarshallerIsImplemented(t *testing.T) {
field := rt.Field(i) field := rt.Field(i)
// Fields in Resources are expected be of the form map[string]*resourceStruct // Fields in Resources are expected be of the form map[string]*resourceStruct
assert.Equal(t, reflect.Map, field.Type.Kind(), "Resource %s is not a map", field.Name) assert.Equal(t, field.Type.Kind(), reflect.Map, "Resource %s is not a map", field.Name)
kt := field.Type.Key() kt := field.Type.Key()
assert.Equal(t, reflect.String, kt.Kind(), "Resource %s is not a map with string keys", field.Name) assert.Equal(t, kt.Kind(), reflect.String, "Resource %s is not a map with string keys", field.Name)
vt := field.Type.Elem() vt := field.Type.Elem()
assert.Equal(t, reflect.Ptr, vt.Kind(), "Resource %s is not a map with pointer values", field.Name) assert.Equal(t, vt.Kind(), reflect.Ptr, "Resource %s is not a map with pointer values", field.Name)
// Marshalling a resourceStruct will panic if resourceStruct does not have a custom marshaller // Marshalling a resourceStruct will panic if resourceStruct does not have a custom marshaller
// This is because resourceStruct embeds a Go SDK struct that implements // This is because resourceStruct embeds a Go SDK struct that implements

View File

@ -102,8 +102,7 @@ func LoadFromBytes(path string, raw []byte) (*Root, diag.Diagnostics) {
// Convert normalized configuration tree to typed configuration. // Convert normalized configuration tree to typed configuration.
err = r.updateWithDynamicValue(v) err = r.updateWithDynamicValue(v)
if err != nil { if err != nil {
diags = diags.Extend(diag.Errorf("failed to load %s: %v", path, err)) return nil, diag.Errorf("failed to load %s: %v", path, err)
return nil, diags
} }
return &r, diags return &r, diags
} }

View File

@ -87,7 +87,7 @@ func TestFilesToSync_EverythingIgnored(t *testing.T) {
ctx := context.Background() ctx := context.Background()
rb := bundle.ReadOnly(b) rb := bundle.ReadOnly(b)
diags := bundle.ApplyReadOnly(ctx, rb, FilesToSync()) diags := bundle.ApplyReadOnly(ctx, rb, FilesToSync())
require.Len(t, diags, 1) require.Equal(t, 1, len(diags))
assert.Equal(t, diag.Warning, diags[0].Severity) assert.Equal(t, diag.Warning, diags[0].Severity)
assert.Equal(t, "There are no files to sync, please check your .gitignore", diags[0].Summary) assert.Equal(t, "There are no files to sync, please check your .gitignore", diags[0].Summary)
} }
@ -101,7 +101,7 @@ func TestFilesToSync_EverythingExcluded(t *testing.T) {
ctx := context.Background() ctx := context.Background()
rb := bundle.ReadOnly(b) rb := bundle.ReadOnly(b)
diags := bundle.ApplyReadOnly(ctx, rb, FilesToSync()) diags := bundle.ApplyReadOnly(ctx, rb, FilesToSync())
require.Len(t, diags, 1) require.Equal(t, 1, len(diags))
assert.Equal(t, diag.Warning, diags[0].Severity) assert.Equal(t, diag.Warning, diags[0].Severity)
assert.Equal(t, "There are no files to sync, please check your .gitignore and sync.exclude configuration", diags[0].Summary) assert.Equal(t, "There are no files to sync, please check your .gitignore and sync.exclude configuration", diags[0].Summary)
} }

View File

@ -36,8 +36,7 @@ func (f *folderPermissions) Apply(ctx context.Context, b bundle.ReadOnlyBundle)
} }
if err := g.Wait(); err != nil { if err := g.Wait(); err != nil {
// Note, only diag from first coroutine is captured, others are lost return diag.FromErr(err)
diags = diags.Extend(diag.FromErr(err))
} }
for _, r := range results { for _, r := range results {

View File

@ -34,7 +34,7 @@ func TestJobClusterKeyDefined(t *testing.T) {
} }
diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), JobClusterKeyDefined()) diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), JobClusterKeyDefined())
require.Empty(t, diags) require.Len(t, diags, 0)
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
} }
@ -59,8 +59,8 @@ func TestJobClusterKeyNotDefined(t *testing.T) {
diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), JobClusterKeyDefined()) diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), JobClusterKeyDefined())
require.Len(t, diags, 1) require.Len(t, diags, 1)
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
require.Equal(t, diag.Warning, diags[0].Severity) require.Equal(t, diags[0].Severity, diag.Warning)
require.Equal(t, "job_cluster_key do-not-exist is not defined", diags[0].Summary) require.Equal(t, diags[0].Summary, "job_cluster_key do-not-exist is not defined")
} }
func TestJobClusterKeyDefinedInDifferentJob(t *testing.T) { func TestJobClusterKeyDefinedInDifferentJob(t *testing.T) {
@ -92,6 +92,6 @@ func TestJobClusterKeyDefinedInDifferentJob(t *testing.T) {
diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), JobClusterKeyDefined()) diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), JobClusterKeyDefined())
require.Len(t, diags, 1) require.Len(t, diags, 1)
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
require.Equal(t, diag.Warning, diags[0].Severity) require.Equal(t, diags[0].Severity, diag.Warning)
require.Equal(t, "job_cluster_key do-not-exist is not defined", diags[0].Summary) require.Equal(t, diags[0].Summary, "job_cluster_key do-not-exist is not defined")
} }

View File

@ -12,7 +12,7 @@ func TestGetPanics(t *testing.T) {
defer func() { defer func() {
r := recover() r := recover()
require.NotNil(t, r, "The function did not panic") require.NotNil(t, r, "The function did not panic")
assert.Equal(t, "context not configured with bundle", r) assert.Equal(t, r, "context not configured with bundle")
}() }()
Get(context.Background()) Get(context.Background())

View File

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"io" "io"
"io/fs" "io/fs"
"os" "os"
@ -278,7 +279,7 @@ func TestStatePullNoState(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
_, err = os.Stat(statePath) _, err = os.Stat(statePath)
require.ErrorIs(t, err, fs.ErrNotExist) require.True(t, errors.Is(err, fs.ErrNotExist))
} }
func TestStatePullOlderState(t *testing.T) { func TestStatePullOlderState(t *testing.T) {

View File

@ -60,7 +60,7 @@ func TestStateUpdate(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, int64(1), state.Seq) require.Equal(t, int64(1), state.Seq)
require.Equal(t, Filelist{ require.Equal(t, state.Files, Filelist{
{ {
LocalPath: "test1.py", LocalPath: "test1.py",
}, },
@ -68,7 +68,7 @@ func TestStateUpdate(t *testing.T) {
LocalPath: "test2.py", LocalPath: "test2.py",
IsNotebook: true, IsNotebook: true,
}, },
}, state.Files) })
require.Equal(t, build.GetInfo().Version, state.CliVersion) require.Equal(t, build.GetInfo().Version, state.CliVersion)
diags = bundle.Apply(ctx, b, s) diags = bundle.Apply(ctx, b, s)
@ -79,7 +79,7 @@ func TestStateUpdate(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, int64(2), state.Seq) require.Equal(t, int64(2), state.Seq)
require.Equal(t, Filelist{ require.Equal(t, state.Files, Filelist{
{ {
LocalPath: "test1.py", LocalPath: "test1.py",
}, },
@ -87,7 +87,7 @@ func TestStateUpdate(t *testing.T) {
LocalPath: "test2.py", LocalPath: "test2.py",
IsNotebook: true, IsNotebook: true,
}, },
}, state.Files) })
require.Equal(t, build.GetInfo().Version, state.CliVersion) require.Equal(t, build.GetInfo().Version, state.CliVersion)
// Valid non-empty UUID is generated. // Valid non-empty UUID is generated.
@ -130,7 +130,7 @@ func TestStateUpdateWithExistingState(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, int64(11), state.Seq) require.Equal(t, int64(11), state.Seq)
require.Equal(t, Filelist{ require.Equal(t, state.Files, Filelist{
{ {
LocalPath: "test1.py", LocalPath: "test1.py",
}, },
@ -138,7 +138,7 @@ func TestStateUpdateWithExistingState(t *testing.T) {
LocalPath: "test2.py", LocalPath: "test2.py",
IsNotebook: true, IsNotebook: true,
}, },
}, state.Files) })
require.Equal(t, build.GetInfo().Version, state.CliVersion) require.Equal(t, build.GetInfo().Version, state.CliVersion)
// Existing UUID is not overwritten. // Existing UUID is not overwritten.

View File

@ -254,10 +254,10 @@ func TestBundleToTerraformPipeline(t *testing.T) {
assert.Equal(t, "my pipeline", resource.Name) assert.Equal(t, "my pipeline", resource.Name)
assert.Len(t, resource.Library, 2) assert.Len(t, resource.Library, 2)
assert.Len(t, resource.Notification, 2) assert.Len(t, resource.Notification, 2)
assert.Equal(t, []string{"on-update-fatal-failure"}, resource.Notification[0].Alerts) assert.Equal(t, resource.Notification[0].Alerts, []string{"on-update-fatal-failure"})
assert.Equal(t, []string{"jane@doe.com"}, resource.Notification[0].EmailRecipients) assert.Equal(t, resource.Notification[0].EmailRecipients, []string{"jane@doe.com"})
assert.Equal(t, []string{"on-update-failure", "on-flow-failure"}, resource.Notification[1].Alerts) assert.Equal(t, resource.Notification[1].Alerts, []string{"on-update-failure", "on-flow-failure"})
assert.Equal(t, []string{"jane@doe.com", "john@doe.com"}, resource.Notification[1].EmailRecipients) assert.Equal(t, resource.Notification[1].EmailRecipients, []string{"jane@doe.com", "john@doe.com"})
assert.Nil(t, out.Data) assert.Nil(t, out.Data)
} }
@ -454,7 +454,7 @@ func TestBundleToTerraformModelServing(t *testing.T) {
assert.Equal(t, "name", resource.Name) assert.Equal(t, "name", resource.Name)
assert.Equal(t, "model_name", resource.Config.ServedModels[0].ModelName) assert.Equal(t, "model_name", resource.Config.ServedModels[0].ModelName)
assert.Equal(t, "1", resource.Config.ServedModels[0].ModelVersion) assert.Equal(t, "1", resource.Config.ServedModels[0].ModelVersion)
assert.True(t, resource.Config.ServedModels[0].ScaleToZeroEnabled) assert.Equal(t, true, resource.Config.ServedModels[0].ScaleToZeroEnabled)
assert.Equal(t, "Small", resource.Config.ServedModels[0].WorkloadSize) assert.Equal(t, "Small", resource.Config.ServedModels[0].WorkloadSize)
assert.Equal(t, "model_name-1", resource.Config.TrafficConfig.Routes[0].ServedModelName) assert.Equal(t, "model_name-1", resource.Config.TrafficConfig.Routes[0].ServedModelName)
assert.Equal(t, 100, resource.Config.TrafficConfig.Routes[0].TrafficPercentage) assert.Equal(t, 100, resource.Config.TrafficConfig.Routes[0].TrafficPercentage)

View File

@ -225,7 +225,7 @@ func TestSetProxyEnvVars(t *testing.T) {
env := make(map[string]string, 0) env := make(map[string]string, 0)
err := setProxyEnvVars(context.Background(), env, b) err := setProxyEnvVars(context.Background(), env, b)
require.NoError(t, err) require.NoError(t, err)
assert.Empty(t, env) assert.Len(t, env, 0)
// Lower case set. // Lower case set.
clearEnv() clearEnv()
@ -293,7 +293,7 @@ func TestSetUserProfileFromInheritEnvVars(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
assert.Contains(t, env, "USERPROFILE") assert.Contains(t, env, "USERPROFILE")
assert.Equal(t, "c:\\foo\\c", env["USERPROFILE"]) assert.Equal(t, env["USERPROFILE"], "c:\\foo\\c")
} }
func TestInheritEnvVarsWithAbsentTFConfigFile(t *testing.T) { func TestInheritEnvVarsWithAbsentTFConfigFile(t *testing.T) {

View File

@ -2,6 +2,7 @@ package main
import ( import (
"bytes" "bytes"
"fmt"
"io" "io"
"os" "os"
"path" "path"
@ -79,7 +80,7 @@ func TestRequiredAnnotationsForNewFields(t *testing.T) {
}, },
}) })
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, updatedFieldPaths, "Missing JSON-schema descriptions for new config fields in bundle/internal/schema/annotations.yml:\n%s", strings.Join(updatedFieldPaths, "\n")) assert.Empty(t, updatedFieldPaths, fmt.Sprintf("Missing JSON-schema descriptions for new config fields in bundle/internal/schema/annotations.yml:\n%s", strings.Join(updatedFieldPaths, "\n")))
} }
// Checks whether types in annotation files are still present in Config type // Checks whether types in annotation files are still present in Config type

View File

@ -212,12 +212,12 @@ func TestFilerForVolumeWithInvalidVolumePaths(t *testing.T) {
bundletest.SetLocation(b, "workspace.artifact_path", []dyn.Location{{File: "config.yml", Line: 1, Column: 2}}) bundletest.SetLocation(b, "workspace.artifact_path", []dyn.Location{{File: "config.yml", Line: 1, Column: 2}})
_, _, diags := GetFilerForLibraries(context.Background(), b) _, _, diags := GetFilerForLibraries(context.Background(), b)
require.Equal(t, diag.Diagnostics{{ require.Equal(t, diags, diag.Diagnostics{{
Severity: diag.Error, Severity: diag.Error,
Summary: fmt.Sprintf("expected UC volume path to be in the format /Volumes/<catalog>/<schema>/<volume>/..., got %s", p), Summary: fmt.Sprintf("expected UC volume path to be in the format /Volumes/<catalog>/<schema>/<volume>/..., got %s", p),
Locations: []dyn.Location{{File: "config.yml", Line: 1, Column: 2}}, Locations: []dyn.Location{{File: "config.yml", Line: 1, Column: 2}},
Paths: []dyn.Path{dyn.MustPathFromString("workspace.artifact_path")}, Paths: []dyn.Path{dyn.MustPathFromString("workspace.artifact_path")},
}}, diags) }})
} }
} }

View File

@ -12,25 +12,25 @@ func TestLibraryPath(t *testing.T) {
p, err := libraryPath(&compute.Library{Whl: path}) p, err := libraryPath(&compute.Library{Whl: path})
assert.Equal(t, path, p) assert.Equal(t, path, p)
assert.NoError(t, err) assert.Nil(t, err)
p, err = libraryPath(&compute.Library{Jar: path}) p, err = libraryPath(&compute.Library{Jar: path})
assert.Equal(t, path, p) assert.Equal(t, path, p)
assert.NoError(t, err) assert.Nil(t, err)
p, err = libraryPath(&compute.Library{Egg: path}) p, err = libraryPath(&compute.Library{Egg: path})
assert.Equal(t, path, p) assert.Equal(t, path, p)
assert.NoError(t, err) assert.Nil(t, err)
p, err = libraryPath(&compute.Library{Requirements: path}) p, err = libraryPath(&compute.Library{Requirements: path})
assert.Equal(t, path, p) assert.Equal(t, path, p)
assert.NoError(t, err) assert.Nil(t, err)
p, err = libraryPath(&compute.Library{}) p, err = libraryPath(&compute.Library{})
assert.Equal(t, "", p) assert.Equal(t, "", p)
assert.Error(t, err) assert.NotNil(t, err)
p, err = libraryPath(&compute.Library{Pypi: &compute.PythonPyPiLibrary{Package: "pypipackage"}}) p, err = libraryPath(&compute.Library{Pypi: &compute.PythonPyPiLibrary{Package: "pypipackage"}})
assert.Equal(t, "", p) assert.Equal(t, "", p)
assert.Error(t, err) assert.NotNil(t, err)
} }

View File

@ -99,32 +99,32 @@ func TestFilterCurrentUser(t *testing.T) {
assert.NoError(t, diags.Error()) assert.NoError(t, diags.Error())
// Assert current user is filtered out. // Assert current user is filtered out.
assert.Len(t, b.Config.Resources.Jobs["job1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Jobs["job1"].Permissions))
assert.Contains(t, b.Config.Resources.Jobs["job1"].Permissions, robot) assert.Contains(t, b.Config.Resources.Jobs["job1"].Permissions, robot)
assert.Contains(t, b.Config.Resources.Jobs["job1"].Permissions, bob) assert.Contains(t, b.Config.Resources.Jobs["job1"].Permissions, bob)
assert.Len(t, b.Config.Resources.Jobs["job2"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Jobs["job2"].Permissions))
assert.Contains(t, b.Config.Resources.Jobs["job2"].Permissions, robot) assert.Contains(t, b.Config.Resources.Jobs["job2"].Permissions, robot)
assert.Contains(t, b.Config.Resources.Jobs["job2"].Permissions, bob) assert.Contains(t, b.Config.Resources.Jobs["job2"].Permissions, bob)
assert.Len(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Pipelines["pipeline1"].Permissions))
assert.Contains(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, robot) assert.Contains(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, robot)
assert.Contains(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, bob) assert.Contains(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, bob)
assert.Len(t, b.Config.Resources.Experiments["experiment1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Experiments["experiment1"].Permissions))
assert.Contains(t, b.Config.Resources.Experiments["experiment1"].Permissions, robot) assert.Contains(t, b.Config.Resources.Experiments["experiment1"].Permissions, robot)
assert.Contains(t, b.Config.Resources.Experiments["experiment1"].Permissions, bob) assert.Contains(t, b.Config.Resources.Experiments["experiment1"].Permissions, bob)
assert.Len(t, b.Config.Resources.Models["model1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Models["model1"].Permissions))
assert.Contains(t, b.Config.Resources.Models["model1"].Permissions, robot) assert.Contains(t, b.Config.Resources.Models["model1"].Permissions, robot)
assert.Contains(t, b.Config.Resources.Models["model1"].Permissions, bob) assert.Contains(t, b.Config.Resources.Models["model1"].Permissions, bob)
assert.Len(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions))
assert.Contains(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, robot) assert.Contains(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, robot)
assert.Contains(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, bob) assert.Contains(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, bob)
// Assert there's no change to the grant. // Assert there's no change to the grant.
assert.Len(t, b.Config.Resources.RegisteredModels["registered_model1"].Grants, 1) assert.Equal(t, 1, len(b.Config.Resources.RegisteredModels["registered_model1"].Grants))
} }
func TestFilterCurrentServicePrincipal(t *testing.T) { func TestFilterCurrentServicePrincipal(t *testing.T) {
@ -134,32 +134,32 @@ func TestFilterCurrentServicePrincipal(t *testing.T) {
assert.NoError(t, diags.Error()) assert.NoError(t, diags.Error())
// Assert current user is filtered out. // Assert current user is filtered out.
assert.Len(t, b.Config.Resources.Jobs["job1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Jobs["job1"].Permissions))
assert.Contains(t, b.Config.Resources.Jobs["job1"].Permissions, alice) assert.Contains(t, b.Config.Resources.Jobs["job1"].Permissions, alice)
assert.Contains(t, b.Config.Resources.Jobs["job1"].Permissions, bob) assert.Contains(t, b.Config.Resources.Jobs["job1"].Permissions, bob)
assert.Len(t, b.Config.Resources.Jobs["job2"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Jobs["job2"].Permissions))
assert.Contains(t, b.Config.Resources.Jobs["job2"].Permissions, alice) assert.Contains(t, b.Config.Resources.Jobs["job2"].Permissions, alice)
assert.Contains(t, b.Config.Resources.Jobs["job2"].Permissions, bob) assert.Contains(t, b.Config.Resources.Jobs["job2"].Permissions, bob)
assert.Len(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Pipelines["pipeline1"].Permissions))
assert.Contains(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, alice) assert.Contains(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, alice)
assert.Contains(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, bob) assert.Contains(t, b.Config.Resources.Pipelines["pipeline1"].Permissions, bob)
assert.Len(t, b.Config.Resources.Experiments["experiment1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Experiments["experiment1"].Permissions))
assert.Contains(t, b.Config.Resources.Experiments["experiment1"].Permissions, alice) assert.Contains(t, b.Config.Resources.Experiments["experiment1"].Permissions, alice)
assert.Contains(t, b.Config.Resources.Experiments["experiment1"].Permissions, bob) assert.Contains(t, b.Config.Resources.Experiments["experiment1"].Permissions, bob)
assert.Len(t, b.Config.Resources.Models["model1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.Models["model1"].Permissions))
assert.Contains(t, b.Config.Resources.Models["model1"].Permissions, alice) assert.Contains(t, b.Config.Resources.Models["model1"].Permissions, alice)
assert.Contains(t, b.Config.Resources.Models["model1"].Permissions, bob) assert.Contains(t, b.Config.Resources.Models["model1"].Permissions, bob)
assert.Len(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, 2) assert.Equal(t, 2, len(b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions))
assert.Contains(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, alice) assert.Contains(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, alice)
assert.Contains(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, bob) assert.Contains(t, b.Config.Resources.ModelServingEndpoints["endpoint1"].Permissions, bob)
// Assert there's no change to the grant. // Assert there's no change to the grant.
assert.Len(t, b.Config.Resources.RegisteredModels["registered_model1"].Grants, 1) assert.Equal(t, 1, len(b.Config.Resources.RegisteredModels["registered_model1"].Grants))
} }
func TestFilterCurrentUserDoesNotErrorWhenNoResources(t *testing.T) { func TestFilterCurrentUserDoesNotErrorWhenNoResources(t *testing.T) {

View File

@ -164,7 +164,7 @@ func TestAllResourcesExplicitlyDefinedForPermissionsSupport(t *testing.T) {
for _, resource := range unsupportedResources { for _, resource := range unsupportedResources {
_, ok := levelsMap[resource] _, ok := levelsMap[resource]
assert.False(t, ok, "Resource %s is defined in both levelsMap and unsupportedResources", resource) assert.False(t, ok, fmt.Sprintf("Resource %s is defined in both levelsMap and unsupportedResources", resource))
} }
for _, resource := range r.AllResources() { for _, resource := range r.AllResources() {

View File

@ -28,7 +28,7 @@ func TestPermissionDiagnosticsApplyFail(t *testing.T) {
}) })
diags := permissions.PermissionDiagnostics().Apply(context.Background(), b) diags := permissions.PermissionDiagnostics().Apply(context.Background(), b)
require.Equal(t, diag.Warning, diags[0].Severity) require.Equal(t, diags[0].Severity, diag.Warning)
require.Contains(t, diags[0].Summary, "permissions section should include testuser@databricks.com or one of their groups with CAN_MANAGE permissions") require.Contains(t, diags[0].Summary, "permissions section should include testuser@databricks.com or one of their groups with CAN_MANAGE permissions")
} }

View File

@ -54,7 +54,7 @@ func TestConvertPythonParams(t *testing.T) {
err = runner.convertPythonParams(opts) err = runner.convertPythonParams(opts)
require.NoError(t, err) require.NoError(t, err)
require.Contains(t, opts.Job.notebookParams, "__python_params") require.Contains(t, opts.Job.notebookParams, "__python_params")
require.Equal(t, `["param1","param2","param3"]`, opts.Job.notebookParams["__python_params"]) require.Equal(t, opts.Job.notebookParams["__python_params"], `["param1","param2","param3"]`)
} }
func TestJobRunnerCancel(t *testing.T) { func TestJobRunnerCancel(t *testing.T) {

View File

@ -90,6 +90,11 @@ func (r *pipelineRunner) Run(ctx context.Context, opts *Options) (output.RunOutp
// Include resource key in logger. // Include resource key in logger.
ctx = log.NewContext(ctx, log.GetLogger(ctx).With("resource", r.Key())) ctx = log.NewContext(ctx, log.GetLogger(ctx).With("resource", r.Key()))
w := r.bundle.WorkspaceClient() w := r.bundle.WorkspaceClient()
_, err := w.Pipelines.GetByPipelineId(ctx, pipelineID)
if err != nil {
log.Warnf(ctx, "Cannot get pipeline: %s", err)
return nil, err
}
req, err := opts.Pipeline.toPayload(r.pipeline, pipelineID) req, err := opts.Pipeline.toPayload(r.pipeline, pipelineID)
if err != nil { if err != nil {

View File

@ -90,6 +90,8 @@ func TestPipelineRunnerRestart(t *testing.T) {
PipelineId: "123", PipelineId: "123",
}).Return(mockWait, nil) }).Return(mockWait, nil)
pipelineApi.EXPECT().GetByPipelineId(mock.Anything, "123").Return(&pipelines.GetPipelineResponse{}, nil)
// Mock runner starting a new update // Mock runner starting a new update
pipelineApi.EXPECT().StartUpdate(mock.Anything, pipelines.StartUpdate{ pipelineApi.EXPECT().StartUpdate(mock.Anything, pipelines.StartUpdate{
PipelineId: "123", PipelineId: "123",

View File

@ -30,7 +30,7 @@ func TestComplexVariables(t *testing.T) {
require.Equal(t, "true", b.Config.Resources.Jobs["my_job"].JobClusters[0].NewCluster.SparkConf["spark.speculation"]) require.Equal(t, "true", b.Config.Resources.Jobs["my_job"].JobClusters[0].NewCluster.SparkConf["spark.speculation"])
require.Equal(t, "true", b.Config.Resources.Jobs["my_job"].JobClusters[0].NewCluster.SparkConf["spark.random"]) require.Equal(t, "true", b.Config.Resources.Jobs["my_job"].JobClusters[0].NewCluster.SparkConf["spark.random"])
require.Len(t, b.Config.Resources.Jobs["my_job"].Tasks[0].Libraries, 3) require.Equal(t, 3, len(b.Config.Resources.Jobs["my_job"].Tasks[0].Libraries))
require.Contains(t, b.Config.Resources.Jobs["my_job"].Tasks[0].Libraries, compute.Library{ require.Contains(t, b.Config.Resources.Jobs["my_job"].Tasks[0].Libraries, compute.Library{
Jar: "/path/to/jar", Jar: "/path/to/jar",
}) })

View File

@ -2,6 +2,7 @@ package config_tests
import ( import (
"context" "context"
"fmt"
"strings" "strings"
"testing" "testing"
@ -15,7 +16,7 @@ func TestGitAutoLoadWithEnvironment(t *testing.T) {
bundle.Apply(context.Background(), b, mutator.LoadGitDetails()) bundle.Apply(context.Background(), b, mutator.LoadGitDetails())
assert.True(t, b.Config.Bundle.Git.Inferred) assert.True(t, b.Config.Bundle.Git.Inferred)
validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks")
assert.True(t, validUrl, "Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL) assert.True(t, validUrl, fmt.Sprintf("Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL))
} }
func TestGitManuallySetBranchWithEnvironment(t *testing.T) { func TestGitManuallySetBranchWithEnvironment(t *testing.T) {
@ -24,5 +25,5 @@ func TestGitManuallySetBranchWithEnvironment(t *testing.T) {
assert.False(t, b.Config.Bundle.Git.Inferred) assert.False(t, b.Config.Bundle.Git.Inferred)
assert.Equal(t, "main", b.Config.Bundle.Git.Branch) assert.Equal(t, "main", b.Config.Bundle.Git.Branch)
validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks")
assert.True(t, validUrl, "Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL) assert.True(t, validUrl, fmt.Sprintf("Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL))
} }

View File

@ -21,8 +21,8 @@ func TestEnvironmentOverridesResourcesDev(t *testing.T) {
assert.Equal(t, "base job", b.Config.Resources.Jobs["job1"].Name) assert.Equal(t, "base job", b.Config.Resources.Jobs["job1"].Name)
// Base values are preserved in the development environment. // Base values are preserved in the development environment.
assert.True(t, b.Config.Resources.Pipelines["boolean1"].Photon) assert.Equal(t, true, b.Config.Resources.Pipelines["boolean1"].Photon)
assert.False(t, b.Config.Resources.Pipelines["boolean2"].Photon) assert.Equal(t, false, b.Config.Resources.Pipelines["boolean2"].Photon)
} }
func TestEnvironmentOverridesResourcesStaging(t *testing.T) { func TestEnvironmentOverridesResourcesStaging(t *testing.T) {
@ -30,6 +30,6 @@ func TestEnvironmentOverridesResourcesStaging(t *testing.T) {
assert.Equal(t, "staging job", b.Config.Resources.Jobs["job1"].Name) assert.Equal(t, "staging job", b.Config.Resources.Jobs["job1"].Name)
// Override values are applied in the staging environment. // Override values are applied in the staging environment.
assert.False(t, b.Config.Resources.Pipelines["boolean1"].Photon) assert.Equal(t, false, b.Config.Resources.Pipelines["boolean1"].Photon)
assert.True(t, b.Config.Resources.Pipelines["boolean2"].Photon) assert.Equal(t, true, b.Config.Resources.Pipelines["boolean2"].Photon)
} }

View File

@ -10,11 +10,11 @@ import (
func TestJobAndPipelineDevelopmentWithEnvironment(t *testing.T) { func TestJobAndPipelineDevelopmentWithEnvironment(t *testing.T) {
b := loadTarget(t, "./environments_job_and_pipeline", "development") b := loadTarget(t, "./environments_job_and_pipeline", "development")
assert.Empty(t, b.Config.Resources.Jobs) assert.Len(t, b.Config.Resources.Jobs, 0)
assert.Len(t, b.Config.Resources.Pipelines, 1) assert.Len(t, b.Config.Resources.Pipelines, 1)
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"] p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
assert.Equal(t, config.Development, b.Config.Bundle.Mode) assert.Equal(t, b.Config.Bundle.Mode, config.Development)
assert.True(t, p.Development) assert.True(t, p.Development)
require.Len(t, p.Libraries, 1) require.Len(t, p.Libraries, 1)
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path) assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
@ -23,7 +23,7 @@ func TestJobAndPipelineDevelopmentWithEnvironment(t *testing.T) {
func TestJobAndPipelineStagingWithEnvironment(t *testing.T) { func TestJobAndPipelineStagingWithEnvironment(t *testing.T) {
b := loadTarget(t, "./environments_job_and_pipeline", "staging") b := loadTarget(t, "./environments_job_and_pipeline", "staging")
assert.Empty(t, b.Config.Resources.Jobs) assert.Len(t, b.Config.Resources.Jobs, 0)
assert.Len(t, b.Config.Resources.Pipelines, 1) assert.Len(t, b.Config.Resources.Pipelines, 1)
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"] p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]

View File

@ -2,6 +2,7 @@ package config_tests
import ( import (
"context" "context"
"fmt"
"strings" "strings"
"testing" "testing"
@ -16,7 +17,7 @@ func TestGitAutoLoad(t *testing.T) {
bundle.Apply(context.Background(), b, mutator.LoadGitDetails()) bundle.Apply(context.Background(), b, mutator.LoadGitDetails())
assert.True(t, b.Config.Bundle.Git.Inferred) assert.True(t, b.Config.Bundle.Git.Inferred)
validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks")
assert.True(t, validUrl, "Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL) assert.True(t, validUrl, fmt.Sprintf("Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL))
} }
func TestGitManuallySetBranch(t *testing.T) { func TestGitManuallySetBranch(t *testing.T) {
@ -25,7 +26,7 @@ func TestGitManuallySetBranch(t *testing.T) {
assert.False(t, b.Config.Bundle.Git.Inferred) assert.False(t, b.Config.Bundle.Git.Inferred)
assert.Equal(t, "main", b.Config.Bundle.Git.Branch) assert.Equal(t, "main", b.Config.Bundle.Git.Branch)
validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks") validUrl := strings.Contains(b.Config.Bundle.Git.OriginURL, "/cli") || strings.Contains(b.Config.Bundle.Git.OriginURL, "/bricks")
assert.True(t, validUrl, "Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL) assert.True(t, validUrl, fmt.Sprintf("Expected URL to contain '/cli' or '/bricks', got %s", b.Config.Bundle.Git.OriginURL))
} }
func TestGitBundleBranchValidation(t *testing.T) { func TestGitBundleBranchValidation(t *testing.T) {

View File

@ -35,7 +35,7 @@ func TestIssue1828(t *testing.T) {
} }
if assert.Contains(t, b.Config.Variables, "float") { if assert.Contains(t, b.Config.Variables, "float") {
assert.InDelta(t, 3.14, b.Config.Variables["float"].Default, 0.0001) assert.Equal(t, 3.14, b.Config.Variables["float"].Default)
} }
if assert.Contains(t, b.Config.Variables, "time") { if assert.Contains(t, b.Config.Variables, "time") {
@ -43,6 +43,6 @@ func TestIssue1828(t *testing.T) {
} }
if assert.Contains(t, b.Config.Variables, "nil") { if assert.Contains(t, b.Config.Variables, "nil") {
assert.Nil(t, b.Config.Variables["nil"].Default) assert.Equal(t, nil, b.Config.Variables["nil"].Default)
} }
} }

View File

@ -10,11 +10,11 @@ import (
func TestJobAndPipelineDevelopment(t *testing.T) { func TestJobAndPipelineDevelopment(t *testing.T) {
b := loadTarget(t, "./job_and_pipeline", "development") b := loadTarget(t, "./job_and_pipeline", "development")
assert.Empty(t, b.Config.Resources.Jobs) assert.Len(t, b.Config.Resources.Jobs, 0)
assert.Len(t, b.Config.Resources.Pipelines, 1) assert.Len(t, b.Config.Resources.Pipelines, 1)
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"] p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]
assert.Equal(t, config.Development, b.Config.Bundle.Mode) assert.Equal(t, b.Config.Bundle.Mode, config.Development)
assert.True(t, p.Development) assert.True(t, p.Development)
require.Len(t, p.Libraries, 1) require.Len(t, p.Libraries, 1)
assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path) assert.Equal(t, "./dlt/nyc_taxi_loader", p.Libraries[0].Notebook.Path)
@ -23,7 +23,7 @@ func TestJobAndPipelineDevelopment(t *testing.T) {
func TestJobAndPipelineStaging(t *testing.T) { func TestJobAndPipelineStaging(t *testing.T) {
b := loadTarget(t, "./job_and_pipeline", "staging") b := loadTarget(t, "./job_and_pipeline", "staging")
assert.Empty(t, b.Config.Resources.Jobs) assert.Len(t, b.Config.Resources.Jobs, 0)
assert.Len(t, b.Config.Resources.Pipelines, 1) assert.Len(t, b.Config.Resources.Pipelines, 1)
p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"] p := b.Config.Resources.Pipelines["nyc_taxi_pipeline"]

View File

@ -16,13 +16,13 @@ func TestJobClusterKeyNotDefinedTest(t *testing.T) {
diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), validate.JobClusterKeyDefined()) diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), validate.JobClusterKeyDefined())
require.Len(t, diags, 1) require.Len(t, diags, 1)
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
require.Equal(t, diag.Warning, diags[0].Severity) require.Equal(t, diags[0].Severity, diag.Warning)
require.Equal(t, "job_cluster_key key is not defined", diags[0].Summary) require.Equal(t, diags[0].Summary, "job_cluster_key key is not defined")
} }
func TestJobClusterKeyDefinedTest(t *testing.T) { func TestJobClusterKeyDefinedTest(t *testing.T) {
b := loadTarget(t, "./job_cluster_key", "development") b := loadTarget(t, "./job_cluster_key", "development")
diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), validate.JobClusterKeyDefined()) diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), validate.JobClusterKeyDefined())
require.Empty(t, diags) require.Len(t, diags, 0)
} }

View File

@ -20,7 +20,7 @@ func assertExpected(t *testing.T, p *resources.ModelServingEndpoint) {
func TestModelServingEndpointDevelopment(t *testing.T) { func TestModelServingEndpointDevelopment(t *testing.T) {
b := loadTarget(t, "./model_serving_endpoint", "development") b := loadTarget(t, "./model_serving_endpoint", "development")
assert.Len(t, b.Config.Resources.ModelServingEndpoints, 1) assert.Len(t, b.Config.Resources.ModelServingEndpoints, 1)
assert.Equal(t, config.Development, b.Config.Bundle.Mode) assert.Equal(t, b.Config.Bundle.Mode, config.Development)
p := b.Config.Resources.ModelServingEndpoints["my_model_serving_endpoint"] p := b.Config.Resources.ModelServingEndpoints["my_model_serving_endpoint"]
assert.Equal(t, "my-dev-endpoint", p.Name) assert.Equal(t, "my-dev-endpoint", p.Name)

View File

@ -12,14 +12,14 @@ func TestOverrideTasksDev(t *testing.T) {
assert.Len(t, b.Config.Resources.Jobs["foo"].Tasks, 2) assert.Len(t, b.Config.Resources.Jobs["foo"].Tasks, 2)
tasks := b.Config.Resources.Jobs["foo"].Tasks tasks := b.Config.Resources.Jobs["foo"].Tasks
assert.Equal(t, "key1", tasks[0].TaskKey) assert.Equal(t, tasks[0].TaskKey, "key1")
assert.Equal(t, "i3.xlarge", tasks[0].NewCluster.NodeTypeId) assert.Equal(t, tasks[0].NewCluster.NodeTypeId, "i3.xlarge")
assert.Equal(t, 1, tasks[0].NewCluster.NumWorkers) assert.Equal(t, tasks[0].NewCluster.NumWorkers, 1)
assert.Equal(t, "./test1.py", tasks[0].SparkPythonTask.PythonFile) assert.Equal(t, tasks[0].SparkPythonTask.PythonFile, "./test1.py")
assert.Equal(t, "key2", tasks[1].TaskKey) assert.Equal(t, tasks[1].TaskKey, "key2")
assert.Equal(t, "13.3.x-scala2.12", tasks[1].NewCluster.SparkVersion) assert.Equal(t, tasks[1].NewCluster.SparkVersion, "13.3.x-scala2.12")
assert.Equal(t, "./test2.py", tasks[1].SparkPythonTask.PythonFile) assert.Equal(t, tasks[1].SparkPythonTask.PythonFile, "./test2.py")
} }
func TestOverrideTasksStaging(t *testing.T) { func TestOverrideTasksStaging(t *testing.T) {
@ -28,12 +28,12 @@ func TestOverrideTasksStaging(t *testing.T) {
assert.Len(t, b.Config.Resources.Jobs["foo"].Tasks, 2) assert.Len(t, b.Config.Resources.Jobs["foo"].Tasks, 2)
tasks := b.Config.Resources.Jobs["foo"].Tasks tasks := b.Config.Resources.Jobs["foo"].Tasks
assert.Equal(t, "key1", tasks[0].TaskKey) assert.Equal(t, tasks[0].TaskKey, "key1")
assert.Equal(t, "13.3.x-scala2.12", tasks[0].NewCluster.SparkVersion) assert.Equal(t, tasks[0].NewCluster.SparkVersion, "13.3.x-scala2.12")
assert.Equal(t, "./test1.py", tasks[0].SparkPythonTask.PythonFile) assert.Equal(t, tasks[0].SparkPythonTask.PythonFile, "./test1.py")
assert.Equal(t, "key2", tasks[1].TaskKey) assert.Equal(t, tasks[1].TaskKey, "key2")
assert.Equal(t, "i3.2xlarge", tasks[1].NewCluster.NodeTypeId) assert.Equal(t, tasks[1].NewCluster.NodeTypeId, "i3.2xlarge")
assert.Equal(t, 4, tasks[1].NewCluster.NumWorkers) assert.Equal(t, tasks[1].NewCluster.NumWorkers, 4)
assert.Equal(t, "./test3.py", tasks[1].SparkPythonTask.PythonFile) assert.Equal(t, tasks[1].SparkPythonTask.PythonFile, "./test3.py")
} }

View File

@ -13,7 +13,7 @@ func TestPresetsDev(t *testing.T) {
assert.Equal(t, "myprefix", b.Config.Presets.NamePrefix) assert.Equal(t, "myprefix", b.Config.Presets.NamePrefix)
assert.Equal(t, config.Paused, b.Config.Presets.TriggerPauseStatus) assert.Equal(t, config.Paused, b.Config.Presets.TriggerPauseStatus)
assert.Equal(t, 10, b.Config.Presets.JobsMaxConcurrentRuns) assert.Equal(t, 10, b.Config.Presets.JobsMaxConcurrentRuns)
assert.True(t, *b.Config.Presets.PipelinesDevelopment) assert.Equal(t, true, *b.Config.Presets.PipelinesDevelopment)
assert.Equal(t, "true", b.Config.Presets.Tags["dev"]) assert.Equal(t, "true", b.Config.Presets.Tags["dev"])
assert.Equal(t, "finance", b.Config.Presets.Tags["team"]) assert.Equal(t, "finance", b.Config.Presets.Tags["team"])
assert.Equal(t, "false", b.Config.Presets.Tags["prod"]) assert.Equal(t, "false", b.Config.Presets.Tags["prod"])
@ -22,7 +22,7 @@ func TestPresetsDev(t *testing.T) {
func TestPresetsProd(t *testing.T) { func TestPresetsProd(t *testing.T) {
b := loadTarget(t, "./presets", "prod") b := loadTarget(t, "./presets", "prod")
assert.False(t, *b.Config.Presets.PipelinesDevelopment) assert.Equal(t, false, *b.Config.Presets.PipelinesDevelopment)
assert.Equal(t, "finance", b.Config.Presets.Tags["team"]) assert.Equal(t, "finance", b.Config.Presets.Tags["team"])
assert.Equal(t, "true", b.Config.Presets.Tags["prod"]) assert.Equal(t, "true", b.Config.Presets.Tags["prod"])
} }

View File

@ -23,7 +23,7 @@ func TestPythonWheelBuild(t *testing.T) {
matches, err := filepath.Glob("./python_wheel/python_wheel/my_test_code/dist/my_test_code-*.whl") matches, err := filepath.Glob("./python_wheel/python_wheel/my_test_code/dist/my_test_code-*.whl")
require.NoError(t, err) require.NoError(t, err)
require.Len(t, matches, 1) require.Equal(t, 1, len(matches))
match := libraries.ExpandGlobReferences() match := libraries.ExpandGlobReferences()
diags = bundle.Apply(ctx, b, match) diags = bundle.Apply(ctx, b, match)
@ -39,7 +39,7 @@ func TestPythonWheelBuildAutoDetect(t *testing.T) {
matches, err := filepath.Glob("./python_wheel/python_wheel_no_artifact/dist/my_test_code-*.whl") matches, err := filepath.Glob("./python_wheel/python_wheel_no_artifact/dist/my_test_code-*.whl")
require.NoError(t, err) require.NoError(t, err)
require.Len(t, matches, 1) require.Equal(t, 1, len(matches))
match := libraries.ExpandGlobReferences() match := libraries.ExpandGlobReferences()
diags = bundle.Apply(ctx, b, match) diags = bundle.Apply(ctx, b, match)
@ -55,7 +55,7 @@ func TestPythonWheelBuildAutoDetectWithNotebookTask(t *testing.T) {
matches, err := filepath.Glob("./python_wheel/python_wheel_no_artifact_notebook/dist/my_test_code-*.whl") matches, err := filepath.Glob("./python_wheel/python_wheel_no_artifact_notebook/dist/my_test_code-*.whl")
require.NoError(t, err) require.NoError(t, err)
require.Len(t, matches, 1) require.Equal(t, 1, len(matches))
match := libraries.ExpandGlobReferences() match := libraries.ExpandGlobReferences()
diags = bundle.Apply(ctx, b, match) diags = bundle.Apply(ctx, b, match)
@ -108,7 +108,7 @@ func TestPythonWheelBuildWithEnvironmentKey(t *testing.T) {
matches, err := filepath.Glob("./python_wheel/environment_key/my_test_code/dist/my_test_code-*.whl") matches, err := filepath.Glob("./python_wheel/environment_key/my_test_code/dist/my_test_code-*.whl")
require.NoError(t, err) require.NoError(t, err)
require.Len(t, matches, 1) require.Equal(t, 1, len(matches))
match := libraries.ExpandGlobReferences() match := libraries.ExpandGlobReferences()
diags = bundle.Apply(ctx, b, match) diags = bundle.Apply(ctx, b, match)
@ -124,7 +124,7 @@ func TestPythonWheelBuildMultiple(t *testing.T) {
matches, err := filepath.Glob("./python_wheel/python_wheel_multiple/my_test_code/dist/my_test_code*.whl") matches, err := filepath.Glob("./python_wheel/python_wheel_multiple/my_test_code/dist/my_test_code*.whl")
require.NoError(t, err) require.NoError(t, err)
require.Len(t, matches, 2) require.Equal(t, 2, len(matches))
match := libraries.ExpandGlobReferences() match := libraries.ExpandGlobReferences()
diags = bundle.Apply(ctx, b, match) diags = bundle.Apply(ctx, b, match)

View File

@ -19,7 +19,7 @@ func assertExpectedMonitor(t *testing.T, p *resources.QualityMonitor) {
func TestMonitorTableNames(t *testing.T) { func TestMonitorTableNames(t *testing.T) {
b := loadTarget(t, "./quality_monitor", "development") b := loadTarget(t, "./quality_monitor", "development")
assert.Len(t, b.Config.Resources.QualityMonitors, 1) assert.Len(t, b.Config.Resources.QualityMonitors, 1)
assert.Equal(t, config.Development, b.Config.Bundle.Mode) assert.Equal(t, b.Config.Bundle.Mode, config.Development)
p := b.Config.Resources.QualityMonitors["my_monitor"] p := b.Config.Resources.QualityMonitors["my_monitor"]
assert.Equal(t, "main.test.dev", p.TableName) assert.Equal(t, "main.test.dev", p.TableName)

View File

@ -19,7 +19,7 @@ func assertExpectedModel(t *testing.T, p *resources.RegisteredModel) {
func TestRegisteredModelDevelopment(t *testing.T) { func TestRegisteredModelDevelopment(t *testing.T) {
b := loadTarget(t, "./registered_model", "development") b := loadTarget(t, "./registered_model", "development")
assert.Len(t, b.Config.Resources.RegisteredModels, 1) assert.Len(t, b.Config.Resources.RegisteredModels, 1)
assert.Equal(t, config.Development, b.Config.Bundle.Mode) assert.Equal(t, b.Config.Bundle.Mode, config.Development)
p := b.Config.Resources.RegisteredModels["my_registered_model"] p := b.Config.Resources.RegisteredModels["my_registered_model"]
assert.Equal(t, "my-dev-model", p.Name) assert.Equal(t, "my-dev-model", p.Name)

View File

@ -20,26 +20,26 @@ func TestSyncIncludeExcludeNoMatchesTest(t *testing.T) {
require.Len(t, diags, 3) require.Len(t, diags, 3)
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
require.Equal(t, diag.Warning, diags[0].Severity) require.Equal(t, diags[0].Severity, diag.Warning)
require.Equal(t, "Pattern dist does not match any files", diags[0].Summary) require.Equal(t, diags[0].Summary, "Pattern dist does not match any files")
require.Len(t, diags[0].Paths, 1) require.Len(t, diags[0].Paths, 1)
require.Equal(t, "sync.exclude[0]", diags[0].Paths[0].String()) require.Equal(t, diags[0].Paths[0].String(), "sync.exclude[0]")
assert.Len(t, diags[0].Locations, 1) assert.Len(t, diags[0].Locations, 1)
require.Equal(t, diags[0].Locations[0].File, filepath.Join("sync", "override", "databricks.yml")) require.Equal(t, diags[0].Locations[0].File, filepath.Join("sync", "override", "databricks.yml"))
require.Equal(t, 17, diags[0].Locations[0].Line) require.Equal(t, diags[0].Locations[0].Line, 17)
require.Equal(t, 11, diags[0].Locations[0].Column) require.Equal(t, diags[0].Locations[0].Column, 11)
summaries := []string{ summaries := []string{
fmt.Sprintf("Pattern %s does not match any files", filepath.Join("src", "*")), fmt.Sprintf("Pattern %s does not match any files", filepath.Join("src", "*")),
fmt.Sprintf("Pattern %s does not match any files", filepath.Join("tests", "*")), fmt.Sprintf("Pattern %s does not match any files", filepath.Join("tests", "*")),
} }
require.Equal(t, diag.Warning, diags[1].Severity) require.Equal(t, diags[1].Severity, diag.Warning)
require.Contains(t, summaries, diags[1].Summary) require.Contains(t, summaries, diags[1].Summary)
require.Equal(t, diag.Warning, diags[2].Severity) require.Equal(t, diags[2].Severity, diag.Warning)
require.Contains(t, summaries, diags[2].Summary) require.Contains(t, summaries, diags[2].Summary)
} }
@ -47,7 +47,7 @@ func TestSyncIncludeWithNegate(t *testing.T) {
b := loadTarget(t, "./sync/negate", "default") b := loadTarget(t, "./sync/negate", "default")
diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), validate.ValidateSyncPatterns()) diags := bundle.ApplyReadOnly(context.Background(), bundle.ReadOnly(b), validate.ValidateSyncPatterns())
require.Empty(t, diags) require.Len(t, diags, 0)
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
} }
@ -58,6 +58,6 @@ func TestSyncIncludeWithNegateNoMatches(t *testing.T) {
require.Len(t, diags, 1) require.Len(t, diags, 1)
require.NoError(t, diags.Error()) require.NoError(t, diags.Error())
require.Equal(t, diag.Warning, diags[0].Severity) require.Equal(t, diags[0].Severity, diag.Warning)
require.Equal(t, "Pattern !*.txt2 does not match any files", diags[0].Summary) require.Equal(t, diags[0].Summary, "Pattern !*.txt2 does not match any files")
} }

View File

@ -115,12 +115,12 @@ func TestSyncPathsNoRoot(t *testing.T) {
// If set to nil, it won't sync anything. // If set to nil, it won't sync anything.
b = loadTarget(t, "./sync/paths_no_root", "nil") b = loadTarget(t, "./sync/paths_no_root", "nil")
assert.Equal(t, filepath.FromSlash("sync/paths_no_root"), b.SyncRootPath) assert.Equal(t, filepath.FromSlash("sync/paths_no_root"), b.SyncRootPath)
assert.Empty(t, b.Config.Sync.Paths) assert.Len(t, b.Config.Sync.Paths, 0)
// If set to an empty sequence, it won't sync anything. // If set to an empty sequence, it won't sync anything.
b = loadTarget(t, "./sync/paths_no_root", "empty") b = loadTarget(t, "./sync/paths_no_root", "empty")
assert.Equal(t, filepath.FromSlash("sync/paths_no_root"), b.SyncRootPath) assert.Equal(t, filepath.FromSlash("sync/paths_no_root"), b.SyncRootPath)
assert.Empty(t, b.Config.Sync.Paths) assert.Len(t, b.Config.Sync.Paths, 0)
} }
func TestSyncSharedCode(t *testing.T) { func TestSyncSharedCode(t *testing.T) {

View File

@ -44,7 +44,7 @@ func TestDashboard_ErrorOnLegacyDashboard(t *testing.T) {
_, diags := d.resolveID(ctx, b) _, diags := d.resolveID(ctx, b)
require.Len(t, diags, 1) require.Len(t, diags, 1)
assert.Equal(t, "dashboard \"legacy dashboard\" is a legacy dashboard", diags[0].Summary) assert.Equal(t, diags[0].Summary, "dashboard \"legacy dashboard\" is a legacy dashboard")
} }
func TestDashboard_ExistingID_Nominal(t *testing.T) { func TestDashboard_ExistingID_Nominal(t *testing.T) {

View File

@ -3,6 +3,7 @@ package generate
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"io/fs" "io/fs"
@ -301,7 +302,7 @@ func TestGenerateJobCommandOldFileRename(t *testing.T) {
// Make sure file do not exists after the run // Make sure file do not exists after the run
_, err = os.Stat(oldFilename) _, err = os.Stat(oldFilename)
require.ErrorIs(t, err, fs.ErrNotExist) require.True(t, errors.Is(err, fs.ErrNotExist))
data, err := os.ReadFile(filepath.Join(configDir, "test_job.job.yml")) data, err := os.ReadFile(filepath.Join(configDir, "test_job.job.yml"))
require.NoError(t, err) require.NoError(t, err)

View File

@ -148,9 +148,9 @@ func TestEnvVarsConfigureNoInteractive(t *testing.T) {
// We should only save host and token for a profile, other env variables should not be saved // We should only save host and token for a profile, other env variables should not be saved
_, err = defaultSection.GetKey("auth_type") _, err = defaultSection.GetKey("auth_type")
assert.Error(t, err) assert.NotNil(t, err)
_, err = defaultSection.GetKey("metadata_service_url") _, err = defaultSection.GetKey("metadata_service_url")
assert.Error(t, err) assert.NotNil(t, err)
} }
func TestEnvVarsConfigureNoArgsNoInteractive(t *testing.T) { func TestEnvVarsConfigureNoArgsNoInteractive(t *testing.T) {

View File

@ -7,15 +7,14 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestFileFromRef(t *testing.T) { func TestFileFromRef(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/databrickslabs/ucx/main/README.md" { if r.URL.Path == "/databrickslabs/ucx/main/README.md" {
_, err := w.Write([]byte(`abc`)) _, err := w.Write([]byte(`abc`))
if !assert.NoError(t, err) { require.NoError(t, err)
return
}
return return
} }
t.Logf("Requested: %s", r.URL.Path) t.Logf("Requested: %s", r.URL.Path)
@ -35,9 +34,7 @@ func TestDownloadZipball(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/repos/databrickslabs/ucx/zipball/main" { if r.URL.Path == "/repos/databrickslabs/ucx/zipball/main" {
_, err := w.Write([]byte(`abc`)) _, err := w.Write([]byte(`abc`))
if !assert.NoError(t, err) { require.NoError(t, err)
return
}
return return
} }
t.Logf("Requested: %s", r.URL.Path) t.Logf("Requested: %s", r.URL.Path)

View File

@ -7,15 +7,14 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestLoadsReleasesForCLI(t *testing.T) { func TestLoadsReleasesForCLI(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/repos/databricks/cli/releases" { if r.URL.Path == "/repos/databricks/cli/releases" {
_, err := w.Write([]byte(`[{"tag_name": "v1.2.3"}, {"tag_name": "v1.2.2"}]`)) _, err := w.Write([]byte(`[{"tag_name": "v1.2.3"}, {"tag_name": "v1.2.2"}]`))
if !assert.NoError(t, err) { require.NoError(t, err)
return
}
return return
} }
t.Logf("Requested: %s", r.URL.Path) t.Logf("Requested: %s", r.URL.Path)

View File

@ -7,13 +7,14 @@ import (
"testing" "testing"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestRepositories(t *testing.T) { func TestRepositories(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/users/databrickslabs/repos" { if r.URL.Path == "/users/databrickslabs/repos" {
_, err := w.Write([]byte(`[{"name": "x"}]`)) _, err := w.Write([]byte(`[{"name": "x"}]`))
assert.NoError(t, err) require.NoError(t, err)
return return
} }
t.Logf("Requested: %s", r.URL.Path) t.Logf("Requested: %s", r.URL.Path)
@ -27,5 +28,5 @@ func TestRepositories(t *testing.T) {
r := NewRepositoryCache("databrickslabs", t.TempDir()) r := NewRepositoryCache("databrickslabs", t.TempDir())
all, err := r.Load(ctx) all, err := r.Load(ctx)
assert.NoError(t, err) assert.NoError(t, err)
assert.NotEmpty(t, all) assert.True(t, len(all) > 0)
} }

View File

@ -22,7 +22,7 @@ func TestCreatesDirectoryIfNeeded(t *testing.T) {
} }
first, err := c.Load(ctx, tick) first, err := c.Load(ctx, tick)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, int64(1), first) assert.Equal(t, first, int64(1))
} }
func TestImpossibleToCreateDir(t *testing.T) { func TestImpossibleToCreateDir(t *testing.T) {

View File

@ -26,7 +26,6 @@ import (
"github.com/databricks/databricks-sdk-go/service/compute" "github.com/databricks/databricks-sdk-go/service/compute"
"github.com/databricks/databricks-sdk-go/service/iam" "github.com/databricks/databricks-sdk-go/service/iam"
"github.com/databricks/databricks-sdk-go/service/sql" "github.com/databricks/databricks-sdk-go/service/sql"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -170,17 +169,17 @@ func TestInstallerWorksForReleases(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/databrickslabs/blueprint/v0.3.15/labs.yml" { if r.URL.Path == "/databrickslabs/blueprint/v0.3.15/labs.yml" {
raw, err := os.ReadFile("testdata/installed-in-home/.databricks/labs/blueprint/lib/labs.yml") raw, err := os.ReadFile("testdata/installed-in-home/.databricks/labs/blueprint/lib/labs.yml")
assert.NoError(t, err) require.NoError(t, err)
_, err = w.Write(raw) _, err = w.Write(raw)
assert.NoError(t, err) require.NoError(t, err)
return return
} }
if r.URL.Path == "/repos/databrickslabs/blueprint/zipball/v0.3.15" { if r.URL.Path == "/repos/databrickslabs/blueprint/zipball/v0.3.15" {
raw, err := zipballFromFolder("testdata/installed-in-home/.databricks/labs/blueprint/lib") raw, err := zipballFromFolder("testdata/installed-in-home/.databricks/labs/blueprint/lib")
assert.NoError(t, err) require.NoError(t, err)
w.Header().Add("Content-Type", "application/octet-stream") w.Header().Add("Content-Type", "application/octet-stream")
_, err = w.Write(raw) _, err = w.Write(raw)
assert.NoError(t, err) require.NoError(t, err)
return return
} }
if r.URL.Path == "/api/2.1/clusters/get" { if r.URL.Path == "/api/2.1/clusters/get" {
@ -377,17 +376,17 @@ func TestUpgraderWorksForReleases(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/databrickslabs/blueprint/v0.4.0/labs.yml" { if r.URL.Path == "/databrickslabs/blueprint/v0.4.0/labs.yml" {
raw, err := os.ReadFile("testdata/installed-in-home/.databricks/labs/blueprint/lib/labs.yml") raw, err := os.ReadFile("testdata/installed-in-home/.databricks/labs/blueprint/lib/labs.yml")
assert.NoError(t, err) require.NoError(t, err)
_, err = w.Write(raw) _, err = w.Write(raw)
assert.NoError(t, err) require.NoError(t, err)
return return
} }
if r.URL.Path == "/repos/databrickslabs/blueprint/zipball/v0.4.0" { if r.URL.Path == "/repos/databrickslabs/blueprint/zipball/v0.4.0" {
raw, err := zipballFromFolder("testdata/installed-in-home/.databricks/labs/blueprint/lib") raw, err := zipballFromFolder("testdata/installed-in-home/.databricks/labs/blueprint/lib")
assert.NoError(t, err) require.NoError(t, err)
w.Header().Add("Content-Type", "application/octet-stream") w.Header().Add("Content-Type", "application/octet-stream")
_, err = w.Write(raw) _, err = w.Write(raw)
assert.NoError(t, err) require.NoError(t, err)
return return
} }
if r.URL.Path == "/api/2.1/clusters/get" { if r.URL.Path == "/api/2.1/clusters/get" {

View File

@ -85,13 +85,13 @@ func TestUploadArtifactFileToCorrectRemotePath(t *testing.T) {
// The remote path attribute on the artifact file should have been set. // The remote path attribute on the artifact file should have been set.
require.Regexp(t, require.Regexp(t,
path.Join(regexp.QuoteMeta(wsDir), `.internal/test\.whl`), regexp.MustCompile(path.Join(regexp.QuoteMeta(wsDir), `.internal/test\.whl`)),
b.Config.Artifacts["test"].Files[0].RemotePath, b.Config.Artifacts["test"].Files[0].RemotePath,
) )
// The task library path should have been updated to the remote path. // The task library path should have been updated to the remote path.
require.Regexp(t, require.Regexp(t,
path.Join("/Workspace", regexp.QuoteMeta(wsDir), `.internal/test\.whl`), regexp.MustCompile(path.Join("/Workspace", regexp.QuoteMeta(wsDir), `.internal/test\.whl`)),
b.Config.Resources.Jobs["test"].JobSettings.Tasks[0].Libraries[0].Whl, b.Config.Resources.Jobs["test"].JobSettings.Tasks[0].Libraries[0].Whl,
) )
} }
@ -149,13 +149,13 @@ func TestUploadArtifactFileToCorrectRemotePathWithEnvironments(t *testing.T) {
// The remote path attribute on the artifact file should have been set. // The remote path attribute on the artifact file should have been set.
require.Regexp(t, require.Regexp(t,
path.Join(regexp.QuoteMeta(wsDir), `.internal/test\.whl`), regexp.MustCompile(path.Join(regexp.QuoteMeta(wsDir), `.internal/test\.whl`)),
b.Config.Artifacts["test"].Files[0].RemotePath, b.Config.Artifacts["test"].Files[0].RemotePath,
) )
// The job environment deps path should have been updated to the remote path. // The job environment deps path should have been updated to the remote path.
require.Regexp(t, require.Regexp(t,
path.Join("/Workspace", regexp.QuoteMeta(wsDir), `.internal/test\.whl`), regexp.MustCompile(path.Join("/Workspace", regexp.QuoteMeta(wsDir), `.internal/test\.whl`)),
b.Config.Resources.Jobs["test"].JobSettings.Environments[0].Spec.Dependencies[0], b.Config.Resources.Jobs["test"].JobSettings.Environments[0].Spec.Dependencies[0],
) )
} }
@ -218,13 +218,13 @@ func TestUploadArtifactFileToCorrectRemotePathForVolumes(t *testing.T) {
// The remote path attribute on the artifact file should have been set. // The remote path attribute on the artifact file should have been set.
require.Regexp(t, require.Regexp(t,
path.Join(regexp.QuoteMeta(volumePath), `.internal/test\.whl`), regexp.MustCompile(path.Join(regexp.QuoteMeta(volumePath), `.internal/test\.whl`)),
b.Config.Artifacts["test"].Files[0].RemotePath, b.Config.Artifacts["test"].Files[0].RemotePath,
) )
// The task library path should have been updated to the remote path. // The task library path should have been updated to the remote path.
require.Regexp(t, require.Regexp(t,
path.Join(regexp.QuoteMeta(volumePath), `.internal/test\.whl`), regexp.MustCompile(path.Join(regexp.QuoteMeta(volumePath), `.internal/test\.whl`)),
b.Config.Resources.Jobs["test"].JobSettings.Tasks[0].Libraries[0].Whl, b.Config.Resources.Jobs["test"].JobSettings.Tasks[0].Libraries[0].Whl,
) )
} }

View File

@ -2,6 +2,7 @@ package bundle_test
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -98,7 +99,7 @@ func TestBundleDeployUcSchema(t *testing.T) {
// Assert the schema is deleted // Assert the schema is deleted
_, err = w.Schemas.GetByFullName(ctx, strings.Join([]string{catalogName, schemaName}, ".")) _, err = w.Schemas.GetByFullName(ctx, strings.Join([]string{catalogName, schemaName}, "."))
apiErr := &apierr.APIError{} apiErr := &apierr.APIError{}
assert.ErrorAs(t, err, &apiErr) assert.True(t, errors.As(err, &apiErr))
assert.Equal(t, "SCHEMA_DOES_NOT_EXIST", apiErr.ErrorCode) assert.Equal(t, "SCHEMA_DOES_NOT_EXIST", apiErr.ErrorCode)
} }

View File

@ -1,6 +1,7 @@
package bundle_test package bundle_test
import ( import (
"errors"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -70,11 +71,11 @@ func TestBundleDestroy(t *testing.T) {
// Assert snapshot file is deleted // Assert snapshot file is deleted
entries, err = os.ReadDir(snapshotsDir) entries, err = os.ReadDir(snapshotsDir)
require.NoError(t, err) require.NoError(t, err)
assert.Empty(t, entries) assert.Len(t, entries, 0)
// Assert bundle deployment path is deleted // Assert bundle deployment path is deleted
_, err = w.Workspace.GetStatusByPath(ctx, remoteRoot) _, err = w.Workspace.GetStatusByPath(ctx, remoteRoot)
apiErr := &apierr.APIError{} apiErr := &apierr.APIError{}
assert.ErrorAs(t, err, &apiErr) assert.True(t, errors.As(err, &apiErr))
assert.Equal(t, "RESOURCE_DOES_NOT_EXIST", apiErr.ErrorCode) assert.Equal(t, "RESOURCE_DOES_NOT_EXIST", apiErr.ErrorCode)
} }

View File

@ -39,8 +39,6 @@ func TestBundleInitErrorOnUnknownFields(t *testing.T) {
// make changes that can break the MLOps Stacks DAB. In which case we should // make changes that can break the MLOps Stacks DAB. In which case we should
// skip this test until the MLOps Stacks DAB is updated to work again. // skip this test until the MLOps Stacks DAB is updated to work again.
func TestBundleInitOnMlopsStacks(t *testing.T) { func TestBundleInitOnMlopsStacks(t *testing.T) {
testutil.SkipUntil(t, "2025-01-09")
ctx, wt := acc.WorkspaceTest(t) ctx, wt := acc.WorkspaceTest(t)
w := wt.W w := wt.W

View File

@ -5,6 +5,7 @@ import (
"encoding/json" "encoding/json"
"io/fs" "io/fs"
"path" "path"
"regexp"
"strings" "strings"
"testing" "testing"
@ -64,11 +65,11 @@ func TestFsLs(t *testing.T) {
assert.Equal(t, "a", parsedStdout[0]["name"]) assert.Equal(t, "a", parsedStdout[0]["name"])
assert.Equal(t, true, parsedStdout[0]["is_directory"]) assert.Equal(t, true, parsedStdout[0]["is_directory"])
assert.InDelta(t, float64(0), parsedStdout[0]["size"], 0.0001) assert.Equal(t, float64(0), parsedStdout[0]["size"])
assert.Equal(t, "bye.txt", parsedStdout[1]["name"]) assert.Equal(t, "bye.txt", parsedStdout[1]["name"])
assert.Equal(t, false, parsedStdout[1]["is_directory"]) assert.Equal(t, false, parsedStdout[1]["is_directory"])
assert.InDelta(t, float64(3), parsedStdout[1]["size"], 0.0001) assert.Equal(t, float64(3), parsedStdout[1]["size"])
}) })
} }
} }
@ -98,11 +99,11 @@ func TestFsLsWithAbsolutePaths(t *testing.T) {
assert.Equal(t, path.Join(tmpDir, "a"), parsedStdout[0]["name"]) assert.Equal(t, path.Join(tmpDir, "a"), parsedStdout[0]["name"])
assert.Equal(t, true, parsedStdout[0]["is_directory"]) assert.Equal(t, true, parsedStdout[0]["is_directory"])
assert.InDelta(t, float64(0), parsedStdout[0]["size"], 0.0001) assert.Equal(t, float64(0), parsedStdout[0]["size"])
assert.Equal(t, path.Join(tmpDir, "bye.txt"), parsedStdout[1]["name"]) assert.Equal(t, path.Join(tmpDir, "bye.txt"), parsedStdout[1]["name"])
assert.Equal(t, false, parsedStdout[1]["is_directory"]) assert.Equal(t, false, parsedStdout[1]["is_directory"])
assert.InDelta(t, float64(3), parsedStdout[1]["size"].(float64), 0.0001) assert.Equal(t, float64(3), parsedStdout[1]["size"])
}) })
} }
} }
@ -121,7 +122,7 @@ func TestFsLsOnFile(t *testing.T) {
setupLsFiles(t, f) setupLsFiles(t, f)
_, _, err := testcli.RequireErrorRun(t, ctx, "fs", "ls", path.Join(tmpDir, "a", "hello.txt"), "--output=json") _, _, err := testcli.RequireErrorRun(t, ctx, "fs", "ls", path.Join(tmpDir, "a", "hello.txt"), "--output=json")
assert.Regexp(t, "not a directory: .*/a/hello.txt", err.Error()) assert.Regexp(t, regexp.MustCompile("not a directory: .*/a/hello.txt"), err.Error())
assert.ErrorAs(t, err, &filer.NotADirectory{}) assert.ErrorAs(t, err, &filer.NotADirectory{})
}) })
} }
@ -146,7 +147,7 @@ func TestFsLsOnEmptyDir(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// assert on ls output // assert on ls output
assert.Empty(t, parsedStdout) assert.Equal(t, 0, len(parsedStdout))
}) })
} }
} }
@ -165,7 +166,7 @@ func TestFsLsForNonexistingDir(t *testing.T) {
_, _, err := testcli.RequireErrorRun(t, ctx, "fs", "ls", path.Join(tmpDir, "nonexistent"), "--output=json") _, _, err := testcli.RequireErrorRun(t, ctx, "fs", "ls", path.Join(tmpDir, "nonexistent"), "--output=json")
assert.ErrorIs(t, err, fs.ErrNotExist) assert.ErrorIs(t, err, fs.ErrNotExist)
assert.Regexp(t, "no such directory: .*/nonexistent", err.Error()) assert.Regexp(t, regexp.MustCompile("no such directory: .*/nonexistent"), err.Error())
}) })
} }
} }

View File

@ -34,7 +34,7 @@ func TestFsMkdir(t *testing.T) {
info, err := f.Stat(context.Background(), "a") info, err := f.Stat(context.Background(), "a")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "a", info.Name()) assert.Equal(t, "a", info.Name())
assert.True(t, info.IsDir()) assert.Equal(t, true, info.IsDir())
}) })
} }
} }
@ -60,19 +60,19 @@ func TestFsMkdirCreatesIntermediateDirectories(t *testing.T) {
infoA, err := f.Stat(context.Background(), "a") infoA, err := f.Stat(context.Background(), "a")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "a", infoA.Name()) assert.Equal(t, "a", infoA.Name())
assert.True(t, infoA.IsDir()) assert.Equal(t, true, infoA.IsDir())
// assert directory "b" is created // assert directory "b" is created
infoB, err := f.Stat(context.Background(), "a/b") infoB, err := f.Stat(context.Background(), "a/b")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "b", infoB.Name()) assert.Equal(t, "b", infoB.Name())
assert.True(t, infoB.IsDir()) assert.Equal(t, true, infoB.IsDir())
// assert directory "c" is created // assert directory "c" is created
infoC, err := f.Stat(context.Background(), "a/b/c") infoC, err := f.Stat(context.Background(), "a/b/c")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "c", infoC.Name()) assert.Equal(t, "c", infoC.Name())
assert.True(t, infoC.IsDir()) assert.Equal(t, true, infoC.IsDir())
}) })
} }
} }

View File

@ -225,7 +225,7 @@ func (a *syncTest) snapshotContains(files []string) {
assert.Equal(a.t, s.RemotePath, a.remoteRoot) assert.Equal(a.t, s.RemotePath, a.remoteRoot)
for _, filePath := range files { for _, filePath := range files {
_, ok := s.LastModifiedTimes[filePath] _, ok := s.LastModifiedTimes[filePath]
assert.True(a.t, ok, "%s not in snapshot file: %v", filePath, s.LastModifiedTimes) assert.True(a.t, ok, fmt.Sprintf("%s not in snapshot file: %v", filePath, s.LastModifiedTimes))
} }
assert.Equal(a.t, len(files), len(s.LastModifiedTimes)) assert.Equal(a.t, len(files), len(s.LastModifiedTimes))
} }

View File

@ -11,14 +11,14 @@ import (
) )
// Detects if test is run from "debug test" feature in VS Code. // Detects if test is run from "debug test" feature in VS Code.
func IsInDebug() bool { func isInDebug() bool {
ex, _ := os.Executable() ex, _ := os.Executable()
return strings.HasPrefix(path.Base(ex), "__debug_bin") return strings.HasPrefix(path.Base(ex), "__debug_bin")
} }
// Loads debug environment from ~/.databricks/debug-env.json. // Loads debug environment from ~/.databricks/debug-env.json.
func loadDebugEnvIfRunFromIDE(t testutil.TestingT, key string) { func loadDebugEnvIfRunFromIDE(t testutil.TestingT, key string) {
if !IsInDebug() { if !isInDebug() {
return return
} }
home, err := os.UserHomeDir() home, err := os.UserHomeDir()

View File

@ -21,10 +21,9 @@ type WorkspaceT struct {
} }
func WorkspaceTest(t testutil.TestingT) (context.Context, *WorkspaceT) { func WorkspaceTest(t testutil.TestingT) (context.Context, *WorkspaceT) {
t.Helper()
loadDebugEnvIfRunFromIDE(t, "workspace") loadDebugEnvIfRunFromIDE(t, "workspace")
t.Logf("CLOUD_ENV=%s", testutil.GetEnvOrSkipTest(t, "CLOUD_ENV")) t.Log(testutil.GetEnvOrSkipTest(t, "CLOUD_ENV"))
w, err := databricks.NewWorkspaceClient() w, err := databricks.NewWorkspaceClient()
require.NoError(t, err) require.NoError(t, err)
@ -42,10 +41,9 @@ func WorkspaceTest(t testutil.TestingT) (context.Context, *WorkspaceT) {
// Run the workspace test only on UC workspaces. // Run the workspace test only on UC workspaces.
func UcWorkspaceTest(t testutil.TestingT) (context.Context, *WorkspaceT) { func UcWorkspaceTest(t testutil.TestingT) (context.Context, *WorkspaceT) {
t.Helper()
loadDebugEnvIfRunFromIDE(t, "workspace") loadDebugEnvIfRunFromIDE(t, "workspace")
t.Logf("CLOUD_ENV=%s", testutil.GetEnvOrSkipTest(t, "CLOUD_ENV")) t.Log(testutil.GetEnvOrSkipTest(t, "CLOUD_ENV"))
if os.Getenv("TEST_METASTORE_ID") == "" { if os.Getenv("TEST_METASTORE_ID") == "" {
t.Skipf("Skipping on non-UC workspaces") t.Skipf("Skipping on non-UC workspaces")
@ -69,21 +67,19 @@ func UcWorkspaceTest(t testutil.TestingT) (context.Context, *WorkspaceT) {
} }
func (t *WorkspaceT) TestClusterID() string { func (t *WorkspaceT) TestClusterID() string {
t.Helper()
clusterID := testutil.GetEnvOrSkipTest(t, "TEST_BRICKS_CLUSTER_ID") clusterID := testutil.GetEnvOrSkipTest(t, "TEST_BRICKS_CLUSTER_ID")
err := t.W.Clusters.EnsureClusterIsRunning(t.ctx, clusterID) err := t.W.Clusters.EnsureClusterIsRunning(t.ctx, clusterID)
require.NoError(t, err, "Unexpected error from EnsureClusterIsRunning for clusterID=%s", clusterID) require.NoError(t, err)
return clusterID return clusterID
} }
func (t *WorkspaceT) RunPython(code string) (string, error) { func (t *WorkspaceT) RunPython(code string) (string, error) {
t.Helper()
var err error var err error
// Create command executor only once per test. // Create command executor only once per test.
if t.exec == nil { if t.exec == nil {
t.exec, err = t.W.CommandExecution.Start(t.ctx, t.TestClusterID(), compute.LanguagePython) t.exec, err = t.W.CommandExecution.Start(t.ctx, t.TestClusterID(), compute.LanguagePython)
require.NoError(t, err, "Unexpected error from CommandExecution.Start(clusterID=%v)", t.TestClusterID()) require.NoError(t, err)
t.Cleanup(func() { t.Cleanup(func() {
err := t.exec.Destroy(t.ctx) err := t.exec.Destroy(t.ctx)
@ -92,7 +88,7 @@ func (t *WorkspaceT) RunPython(code string) (string, error) {
} }
results, err := t.exec.Execute(t.ctx, code) results, err := t.exec.Execute(t.ctx, code)
require.NoError(t, err, "Unexpected error from Execute(%v)", code) require.NoError(t, err)
require.NotEqual(t, compute.ResultTypeError, results.ResultType, results.Cause) require.NotEqual(t, compute.ResultTypeError, results.ResultType, results.Cause)
output, ok := results.Data.(string) output, ok := results.Data.(string)
require.True(t, ok, "unexpected type %T", results.Data) require.True(t, ok, "unexpected type %T", results.Data)

View File

@ -4,8 +4,6 @@ import (
"fmt" "fmt"
"os" "os"
"testing" "testing"
"github.com/databricks/cli/integration/internal/acc"
) )
// Main is the entry point for integration tests. // Main is the entry point for integration tests.
@ -13,7 +11,7 @@ import (
// they are not inadvertently executed when calling `go test ./...`. // they are not inadvertently executed when calling `go test ./...`.
func Main(m *testing.M) { func Main(m *testing.M) {
value := os.Getenv("CLOUD_ENV") value := os.Getenv("CLOUD_ENV")
if value == "" && !acc.IsInDebug() { if value == "" {
fmt.Println("CLOUD_ENV is not set, skipping integration tests") fmt.Println("CLOUD_ENV is not set, skipping integration tests")
return return
} }

View File

@ -4,11 +4,13 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors"
"io" "io"
"io/fs" "io/fs"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"regexp"
"strings" "strings"
"testing" "testing"
@ -106,7 +108,7 @@ func commonFilerRecursiveDeleteTest(t *testing.T, ctx context.Context, f filer.F
for _, e := range entriesBeforeDelete { for _, e := range entriesBeforeDelete {
names = append(names, e.Name()) names = append(names, e.Name())
} }
assert.Equal(t, []string{"file1", "file2", "subdir1", "subdir2"}, names) assert.Equal(t, names, []string{"file1", "file2", "subdir1", "subdir2"})
err = f.Delete(ctx, "dir") err = f.Delete(ctx, "dir")
assert.ErrorAs(t, err, &filer.DirectoryNotEmptyError{}) assert.ErrorAs(t, err, &filer.DirectoryNotEmptyError{})
@ -149,13 +151,13 @@ func commonFilerReadWriteTests(t *testing.T, ctx context.Context, f filer.Filer)
// Write should fail because the intermediate directory doesn't exist. // Write should fail because the intermediate directory doesn't exist.
err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello world`)) err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello world`))
assert.ErrorAs(t, err, &filer.NoSuchDirectoryError{}) assert.True(t, errors.As(err, &filer.NoSuchDirectoryError{}))
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
// Read should fail because the intermediate directory doesn't yet exist. // Read should fail because the intermediate directory doesn't yet exist.
_, err = f.Read(ctx, "/foo/bar") _, err = f.Read(ctx, "/foo/bar")
assert.ErrorAs(t, err, &filer.FileDoesNotExistError{}) assert.True(t, errors.As(err, &filer.FileDoesNotExistError{}))
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
// Read should fail because the path points to a directory // Read should fail because the path points to a directory
err = f.Mkdir(ctx, "/dir") err = f.Mkdir(ctx, "/dir")
@ -170,8 +172,8 @@ func commonFilerReadWriteTests(t *testing.T, ctx context.Context, f filer.Filer)
// Write should fail because there is an existing file at the specified path. // Write should fail because there is an existing file at the specified path.
err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello universe`)) err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello universe`))
assert.ErrorAs(t, err, &filer.FileAlreadyExistsError{}) assert.True(t, errors.As(err, &filer.FileAlreadyExistsError{}))
assert.ErrorIs(t, err, fs.ErrExist) assert.True(t, errors.Is(err, fs.ErrExist))
// Write with OverwriteIfExists should succeed. // Write with OverwriteIfExists should succeed.
err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello universe`), filer.OverwriteIfExists) err = f.Write(ctx, "/foo/bar", strings.NewReader(`hello universe`), filer.OverwriteIfExists)
@ -188,7 +190,7 @@ func commonFilerReadWriteTests(t *testing.T, ctx context.Context, f filer.Filer)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "foo", info.Name()) assert.Equal(t, "foo", info.Name())
assert.True(t, info.Mode().IsDir()) assert.True(t, info.Mode().IsDir())
assert.True(t, info.IsDir()) assert.Equal(t, true, info.IsDir())
// Stat on a file should succeed. // Stat on a file should succeed.
// Note: size and modification time behave differently between backends. // Note: size and modification time behave differently between backends.
@ -196,17 +198,17 @@ func commonFilerReadWriteTests(t *testing.T, ctx context.Context, f filer.Filer)
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "bar", info.Name()) assert.Equal(t, "bar", info.Name())
assert.True(t, info.Mode().IsRegular()) assert.True(t, info.Mode().IsRegular())
assert.False(t, info.IsDir()) assert.Equal(t, false, info.IsDir())
// Delete should fail if the file doesn't exist. // Delete should fail if the file doesn't exist.
err = f.Delete(ctx, "/doesnt_exist") err = f.Delete(ctx, "/doesnt_exist")
assert.ErrorAs(t, err, &filer.FileDoesNotExistError{}) assert.ErrorAs(t, err, &filer.FileDoesNotExistError{})
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
// Stat should fail if the file doesn't exist. // Stat should fail if the file doesn't exist.
_, err = f.Stat(ctx, "/doesnt_exist") _, err = f.Stat(ctx, "/doesnt_exist")
assert.ErrorAs(t, err, &filer.FileDoesNotExistError{}) assert.ErrorAs(t, err, &filer.FileDoesNotExistError{})
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
// Delete should succeed for file that does exist. // Delete should succeed for file that does exist.
err = f.Delete(ctx, "/foo/bar") err = f.Delete(ctx, "/foo/bar")
@ -215,7 +217,7 @@ func commonFilerReadWriteTests(t *testing.T, ctx context.Context, f filer.Filer)
// Delete should fail for a non-empty directory. // Delete should fail for a non-empty directory.
err = f.Delete(ctx, "/foo") err = f.Delete(ctx, "/foo")
assert.ErrorAs(t, err, &filer.DirectoryNotEmptyError{}) assert.ErrorAs(t, err, &filer.DirectoryNotEmptyError{})
assert.ErrorIs(t, err, fs.ErrInvalid) assert.True(t, errors.Is(err, fs.ErrInvalid))
// Delete should succeed for a non-empty directory if the DeleteRecursively flag is set. // Delete should succeed for a non-empty directory if the DeleteRecursively flag is set.
err = f.Delete(ctx, "/foo", filer.DeleteRecursively) err = f.Delete(ctx, "/foo", filer.DeleteRecursively)
@ -224,8 +226,8 @@ func commonFilerReadWriteTests(t *testing.T, ctx context.Context, f filer.Filer)
// Delete of the filer root should ALWAYS fail, otherwise subsequent writes would fail. // Delete of the filer root should ALWAYS fail, otherwise subsequent writes would fail.
// It is not in the filer's purview to delete its root directory. // It is not in the filer's purview to delete its root directory.
err = f.Delete(ctx, "/") err = f.Delete(ctx, "/")
assert.ErrorAs(t, err, &filer.CannotDeleteRootError{}) assert.True(t, errors.As(err, &filer.CannotDeleteRootError{}))
assert.ErrorIs(t, err, fs.ErrInvalid) assert.True(t, errors.Is(err, fs.ErrInvalid))
} }
func TestFilerReadWrite(t *testing.T) { func TestFilerReadWrite(t *testing.T) {
@ -262,7 +264,7 @@ func commonFilerReadDirTest(t *testing.T, ctx context.Context, f filer.Filer) {
// We start with an empty directory. // We start with an empty directory.
entries, err := f.ReadDir(ctx, ".") entries, err := f.ReadDir(ctx, ".")
require.NoError(t, err) require.NoError(t, err)
assert.Empty(t, entries) assert.Len(t, entries, 0)
// Write a file. // Write a file.
err = f.Write(ctx, "/hello.txt", strings.NewReader(`hello world`)) err = f.Write(ctx, "/hello.txt", strings.NewReader(`hello world`))
@ -282,8 +284,8 @@ func commonFilerReadDirTest(t *testing.T, ctx context.Context, f filer.Filer) {
// Expect an error if the path doesn't exist. // Expect an error if the path doesn't exist.
_, err = f.ReadDir(ctx, "/dir/a/b/c/d/e") _, err = f.ReadDir(ctx, "/dir/a/b/c/d/e")
assert.ErrorAs(t, err, &filer.NoSuchDirectoryError{}, err) assert.True(t, errors.As(err, &filer.NoSuchDirectoryError{}), err)
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
// Expect two entries in the root. // Expect two entries in the root.
entries, err = f.ReadDir(ctx, ".") entries, err = f.ReadDir(ctx, ".")
@ -295,7 +297,7 @@ func commonFilerReadDirTest(t *testing.T, ctx context.Context, f filer.Filer) {
assert.False(t, entries[1].IsDir()) assert.False(t, entries[1].IsDir())
info, err = entries[1].Info() info, err = entries[1].Info()
require.NoError(t, err) require.NoError(t, err)
assert.Positive(t, info.ModTime().Unix()) assert.Greater(t, info.ModTime().Unix(), int64(0))
// Expect two entries in the directory. // Expect two entries in the directory.
entries, err = f.ReadDir(ctx, "/dir") entries, err = f.ReadDir(ctx, "/dir")
@ -307,7 +309,7 @@ func commonFilerReadDirTest(t *testing.T, ctx context.Context, f filer.Filer) {
assert.False(t, entries[1].IsDir()) assert.False(t, entries[1].IsDir())
info, err = entries[1].Info() info, err = entries[1].Info()
require.NoError(t, err) require.NoError(t, err)
assert.Positive(t, info.ModTime().Unix()) assert.Greater(t, info.ModTime().Unix(), int64(0))
// Expect a single entry in the nested path. // Expect a single entry in the nested path.
entries, err = f.ReadDir(ctx, "/dir/a/b") entries, err = f.ReadDir(ctx, "/dir/a/b")
@ -325,7 +327,7 @@ func commonFilerReadDirTest(t *testing.T, ctx context.Context, f filer.Filer) {
require.NoError(t, err) require.NoError(t, err)
entries, err = f.ReadDir(ctx, "empty-dir") entries, err = f.ReadDir(ctx, "empty-dir")
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, entries) assert.Len(t, entries, 0)
// Expect one entry for a directory with a file in it // Expect one entry for a directory with a file in it
err = f.Write(ctx, "dir-with-one-file/my-file.txt", strings.NewReader("abc"), filer.CreateParentDirectories) err = f.Write(ctx, "dir-with-one-file/my-file.txt", strings.NewReader("abc"), filer.CreateParentDirectories)
@ -333,7 +335,7 @@ func commonFilerReadDirTest(t *testing.T, ctx context.Context, f filer.Filer) {
entries, err = f.ReadDir(ctx, "dir-with-one-file") entries, err = f.ReadDir(ctx, "dir-with-one-file")
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, entries, 1) assert.Len(t, entries, 1)
assert.Equal(t, "my-file.txt", entries[0].Name()) assert.Equal(t, entries[0].Name(), "my-file.txt")
assert.False(t, entries[0].IsDir()) assert.False(t, entries[0].IsDir())
} }
@ -459,7 +461,7 @@ func TestFilerWorkspaceNotebook(t *testing.T) {
// Assert uploading a second time fails due to overwrite mode missing // Assert uploading a second time fails due to overwrite mode missing
err = f.Write(ctx, tc.name, strings.NewReader(tc.content2)) err = f.Write(ctx, tc.name, strings.NewReader(tc.content2))
require.ErrorIs(t, err, fs.ErrExist) require.ErrorIs(t, err, fs.ErrExist)
assert.Regexp(t, `file already exists: .*/`+tc.nameWithoutExt+`$`, err.Error()) assert.Regexp(t, regexp.MustCompile(`file already exists: .*/`+tc.nameWithoutExt+`$`), err.Error())
// Try uploading the notebook again with overwrite flag. This time it should succeed. // Try uploading the notebook again with overwrite flag. This time it should succeed.
err = f.Write(ctx, tc.name, strings.NewReader(tc.content2), filer.OverwriteIfExists) err = f.Write(ctx, tc.name, strings.NewReader(tc.content2), filer.OverwriteIfExists)

View File

@ -3,6 +3,7 @@ package testcli
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"github.com/databricks/cli/internal/testutil" "github.com/databricks/cli/internal/testutil"
"github.com/databricks/cli/libs/testdiff" "github.com/databricks/cli/libs/testdiff"
@ -10,7 +11,7 @@ import (
) )
func captureOutput(t testutil.TestingT, ctx context.Context, args []string) string { func captureOutput(t testutil.TestingT, ctx context.Context, args []string) string {
t.Helper() t.Logf("run args: [%s]", strings.Join(args, ", "))
r := NewRunner(t, ctx, args...) r := NewRunner(t, ctx, args...)
stdout, stderr, err := r.Run() stdout, stderr, err := r.Run()
assert.NoError(t, err) assert.NoError(t, err)
@ -18,13 +19,11 @@ func captureOutput(t testutil.TestingT, ctx context.Context, args []string) stri
} }
func AssertOutput(t testutil.TestingT, ctx context.Context, args []string, expectedPath string) { func AssertOutput(t testutil.TestingT, ctx context.Context, args []string, expectedPath string) {
t.Helper()
out := captureOutput(t, ctx, args) out := captureOutput(t, ctx, args)
testdiff.AssertOutput(t, ctx, out, fmt.Sprintf("Output from %v", args), expectedPath) testdiff.AssertOutput(t, ctx, out, fmt.Sprintf("Output from %v", args), expectedPath)
} }
func AssertOutputJQ(t testutil.TestingT, ctx context.Context, args []string, expectedPath string, ignorePaths []string) { func AssertOutputJQ(t testutil.TestingT, ctx context.Context, args []string, expectedPath string, ignorePaths []string) {
t.Helper()
out := captureOutput(t, ctx, args) out := captureOutput(t, ctx, args)
testdiff.AssertOutputJQ(t, ctx, out, fmt.Sprintf("Output from %v", args), expectedPath, ignorePaths) testdiff.AssertOutputJQ(t, ctx, out, fmt.Sprintf("Output from %v", args), expectedPath, ignorePaths)
} }

View File

@ -69,7 +69,6 @@ func consumeLines(ctx context.Context, wg *sync.WaitGroup, r io.Reader) <-chan s
} }
func (r *Runner) registerFlagCleanup(c *cobra.Command) { func (r *Runner) registerFlagCleanup(c *cobra.Command) {
r.Helper()
// Find target command that will be run. Example: if the command run is `databricks fs cp`, // Find target command that will be run. Example: if the command run is `databricks fs cp`,
// target command corresponds to `cp` // target command corresponds to `cp`
targetCmd, _, err := c.Find(r.args) targetCmd, _, err := c.Find(r.args)
@ -231,48 +230,13 @@ func (r *Runner) RunBackground() {
} }
func (r *Runner) Run() (bytes.Buffer, bytes.Buffer, error) { func (r *Runner) Run() (bytes.Buffer, bytes.Buffer, error) {
r.Helper() r.RunBackground()
var stdout, stderr bytes.Buffer err := <-r.errch
ctx := cmdio.NewContext(r.ctx, &cmdio.Logger{ return r.stdout, r.stderr, err
Mode: flags.ModeAppend,
Reader: bufio.Reader{},
Writer: &stderr,
})
cli := cmd.New(ctx)
cli.SetOut(&stdout)
cli.SetErr(&stderr)
cli.SetArgs(r.args)
r.Logf(" args: %s", strings.Join(r.args, ", "))
err := root.Execute(ctx, cli)
if err != nil {
r.Logf(" error: %s", err)
}
if stdout.Len() > 0 {
// Make a copy of the buffer such that it remains "unread".
scanner := bufio.NewScanner(bytes.NewBuffer(stdout.Bytes()))
for scanner.Scan() {
r.Logf("stdout: %s", scanner.Text())
}
}
if stderr.Len() > 0 {
// Make a copy of the buffer such that it remains "unread".
scanner := bufio.NewScanner(bytes.NewBuffer(stderr.Bytes()))
for scanner.Scan() {
r.Logf("stderr: %s", scanner.Text())
}
}
return stdout, stderr, err
} }
// Like [require.Eventually] but errors if the underlying command has failed. // Like [require.Eventually] but errors if the underlying command has failed.
func (r *Runner) Eventually(condition func() bool, waitFor, tick time.Duration, msgAndArgs ...any) { func (r *Runner) Eventually(condition func() bool, waitFor, tick time.Duration, msgAndArgs ...any) {
r.Helper()
ch := make(chan bool, 1) ch := make(chan bool, 1)
timer := time.NewTimer(waitFor) timer := time.NewTimer(waitFor)
@ -305,14 +269,12 @@ func (r *Runner) Eventually(condition func() bool, waitFor, tick time.Duration,
} }
func (r *Runner) RunAndExpectOutput(heredoc string) { func (r *Runner) RunAndExpectOutput(heredoc string) {
r.Helper()
stdout, _, err := r.Run() stdout, _, err := r.Run()
require.NoError(r, err) require.NoError(r, err)
require.Equal(r, cmdio.Heredoc(heredoc), strings.TrimSpace(stdout.String())) require.Equal(r, cmdio.Heredoc(heredoc), strings.TrimSpace(stdout.String()))
} }
func (r *Runner) RunAndParseJSON(v any) { func (r *Runner) RunAndParseJSON(v any) {
r.Helper()
stdout, _, err := r.Run() stdout, _, err := r.Run()
require.NoError(r, err) require.NoError(r, err)
err = json.Unmarshal(stdout.Bytes(), &v) err = json.Unmarshal(stdout.Bytes(), &v)
@ -329,7 +291,7 @@ func NewRunner(t testutil.TestingT, ctx context.Context, args ...string) *Runner
} }
func RequireSuccessfulRun(t testutil.TestingT, ctx context.Context, args ...string) (bytes.Buffer, bytes.Buffer) { func RequireSuccessfulRun(t testutil.TestingT, ctx context.Context, args ...string) (bytes.Buffer, bytes.Buffer) {
t.Helper() t.Logf("run args: [%s]", strings.Join(args, ", "))
r := NewRunner(t, ctx, args...) r := NewRunner(t, ctx, args...)
stdout, stderr, err := r.Run() stdout, stderr, err := r.Run()
require.NoError(t, err) require.NoError(t, err)
@ -337,7 +299,6 @@ func RequireSuccessfulRun(t testutil.TestingT, ctx context.Context, args ...stri
} }
func RequireErrorRun(t testutil.TestingT, ctx context.Context, args ...string) (bytes.Buffer, bytes.Buffer, error) { func RequireErrorRun(t testutil.TestingT, ctx context.Context, args ...string) (bytes.Buffer, bytes.Buffer, error) {
t.Helper()
r := NewRunner(t, ctx, args...) r := NewRunner(t, ctx, args...)
stdout, stderr, err := r.Run() stdout, stderr, err := r.Run()
require.Error(t, err) require.Error(t, err)

View File

@ -5,9 +5,6 @@ import (
"math/rand" "math/rand"
"os" "os"
"strings" "strings"
"time"
"github.com/stretchr/testify/require"
) )
// GetEnvOrSkipTest proceeds with test only with that env variable. // GetEnvOrSkipTest proceeds with test only with that env variable.
@ -33,12 +30,3 @@ func RandomName(prefix ...string) string {
} }
return string(b) return string(b)
} }
func SkipUntil(t TestingT, date string) {
deadline, err := time.Parse(time.DateOnly, date)
require.NoError(t, err)
if time.Now().Before(deadline) {
t.Skipf("Skipping test until %s. Time right now: %s", deadline.Format(time.DateOnly), time.Now())
}
}

View File

@ -24,6 +24,4 @@ type TestingT interface {
Setenv(key, value string) Setenv(key, value string)
TempDir() string TempDir() string
Helper()
} }

View File

@ -42,7 +42,7 @@ func TestStoreAndLookup(t *testing.T) {
tok, err := l.Lookup("x") tok, err := l.Lookup("x")
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "abc", tok.AccessToken) assert.Equal(t, "abc", tok.AccessToken)
assert.Len(t, l.Tokens, 2) assert.Equal(t, 2, len(l.Tokens))
_, err = l.Lookup("z") _, err = l.Lookup("z")
assert.Equal(t, ErrNotConfigured, err) assert.Equal(t, ErrNotConfigured, err)

View File

@ -216,7 +216,7 @@ func TestSaveToProfile_ClearingPreviousProfile(t *testing.T) {
dlft, err := file.GetSection("DEFAULT") dlft, err := file.GetSection("DEFAULT")
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, dlft.KeysHash()) assert.Len(t, dlft.KeysHash(), 0)
abc, err := file.GetSection("abc") abc, err := file.GetSection("abc")
assert.NoError(t, err) assert.NoError(t, err)

View File

@ -11,10 +11,10 @@ import (
) )
func TestProfileCloud(t *testing.T) { func TestProfileCloud(t *testing.T) {
assert.Equal(t, "AWS", Profile{Host: "https://dbc-XXXXXXXX-YYYY.cloud.databricks.com"}.Cloud()) assert.Equal(t, Profile{Host: "https://dbc-XXXXXXXX-YYYY.cloud.databricks.com"}.Cloud(), "AWS")
assert.Equal(t, "Azure", Profile{Host: "https://adb-xxx.y.azuredatabricks.net/"}.Cloud()) assert.Equal(t, Profile{Host: "https://adb-xxx.y.azuredatabricks.net/"}.Cloud(), "Azure")
assert.Equal(t, "GCP", Profile{Host: "https://workspace.gcp.databricks.com/"}.Cloud()) assert.Equal(t, Profile{Host: "https://workspace.gcp.databricks.com/"}.Cloud(), "GCP")
assert.Equal(t, "AWS", Profile{Host: "https://some.invalid.host.com/"}.Cloud()) assert.Equal(t, Profile{Host: "https://some.invalid.host.com/"}.Cloud(), "AWS")
} }
func TestProfilesSearchCaseInsensitive(t *testing.T) { func TestProfilesSearchCaseInsensitive(t *testing.T) {

View File

@ -1,6 +1,7 @@
package errs package errs
import ( import (
"errors"
"fmt" "fmt"
"testing" "testing"
@ -13,13 +14,13 @@ func TestFromManyErrors(t *testing.T) {
e3 := fmt.Errorf("Error 3") e3 := fmt.Errorf("Error 3")
err := FromMany(e1, e2, e3) err := FromMany(e1, e2, e3)
assert.ErrorIs(t, err, e1) assert.True(t, errors.Is(err, e1))
assert.ErrorIs(t, err, e2) assert.True(t, errors.Is(err, e2))
assert.ErrorIs(t, err, e3) assert.True(t, errors.Is(err, e3))
assert.Equal(t, `Error 1 assert.Equal(t, err.Error(), `Error 1
Error 2 Error 2
Error 3`, err.Error()) Error 3`)
} }
func TestFromManyErrorsWihtNil(t *testing.T) { func TestFromManyErrorsWihtNil(t *testing.T) {
@ -28,9 +29,9 @@ func TestFromManyErrorsWihtNil(t *testing.T) {
e3 := fmt.Errorf("Error 3") e3 := fmt.Errorf("Error 3")
err := FromMany(e1, e2, e3) err := FromMany(e1, e2, e3)
assert.ErrorIs(t, err, e1) assert.True(t, errors.Is(err, e1))
assert.ErrorIs(t, err, e3) assert.True(t, errors.Is(err, e3))
assert.Equal(t, `Error 1 assert.Equal(t, err.Error(), `Error 1
Error 3`, err.Error()) Error 3`)
} }

View File

@ -37,7 +37,7 @@ func TestFilerCompleterSetsPrefix(t *testing.T) {
assert.Equal(t, []string{"dbfs:/dir/dirA/", "dbfs:/dir/dirB/"}, completions) assert.Equal(t, []string{"dbfs:/dir/dirA/", "dbfs:/dir/dirB/"}, completions)
assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive) assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive)
assert.NoError(t, err) assert.Nil(t, err)
} }
func TestFilerCompleterReturnsNestedDirs(t *testing.T) { func TestFilerCompleterReturnsNestedDirs(t *testing.T) {
@ -46,7 +46,7 @@ func TestFilerCompleterReturnsNestedDirs(t *testing.T) {
assert.Equal(t, []string{"dir/dirA/", "dir/dirB/"}, completions) assert.Equal(t, []string{"dir/dirA/", "dir/dirB/"}, completions)
assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive) assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive)
assert.NoError(t, err) assert.Nil(t, err)
} }
func TestFilerCompleterReturnsAdjacentDirs(t *testing.T) { func TestFilerCompleterReturnsAdjacentDirs(t *testing.T) {
@ -55,7 +55,7 @@ func TestFilerCompleterReturnsAdjacentDirs(t *testing.T) {
assert.Equal(t, []string{"dir/dirA/", "dir/dirB/"}, completions) assert.Equal(t, []string{"dir/dirA/", "dir/dirB/"}, completions)
assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive) assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive)
assert.NoError(t, err) assert.Nil(t, err)
} }
func TestFilerCompleterReturnsNestedDirsAndFiles(t *testing.T) { func TestFilerCompleterReturnsNestedDirsAndFiles(t *testing.T) {
@ -64,7 +64,7 @@ func TestFilerCompleterReturnsNestedDirsAndFiles(t *testing.T) {
assert.Equal(t, []string{"dir/dirA/", "dir/dirB/", "dir/fileA"}, completions) assert.Equal(t, []string{"dir/dirA/", "dir/dirB/", "dir/fileA"}, completions)
assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive) assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive)
assert.NoError(t, err) assert.Nil(t, err)
} }
func TestFilerCompleterAddsDbfsPath(t *testing.T) { func TestFilerCompleterAddsDbfsPath(t *testing.T) {
@ -78,7 +78,7 @@ func TestFilerCompleterAddsDbfsPath(t *testing.T) {
assert.Equal(t, []string{"dir/dirA/", "dir/dirB/", "dbfs:/"}, completions) assert.Equal(t, []string{"dir/dirA/", "dir/dirB/", "dbfs:/"}, completions)
assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive) assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive)
assert.NoError(t, err) assert.Nil(t, err)
} }
func TestFilerCompleterWindowsSeparator(t *testing.T) { func TestFilerCompleterWindowsSeparator(t *testing.T) {
@ -92,7 +92,7 @@ func TestFilerCompleterWindowsSeparator(t *testing.T) {
assert.Equal(t, []string{"dir\\dirA\\", "dir\\dirB\\", "dbfs:/"}, completions) assert.Equal(t, []string{"dir\\dirA\\", "dir\\dirB\\", "dbfs:/"}, completions)
assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive) assert.Equal(t, cobra.ShellCompDirectiveNoSpace, directive)
assert.NoError(t, err) assert.Nil(t, err)
} }
func TestFilerCompleterNoCompletions(t *testing.T) { func TestFilerCompleterNoCompletions(t *testing.T) {

View File

@ -100,94 +100,42 @@ func NewDbfsClient(w *databricks.WorkspaceClient, root string) (Filer, error) {
}, nil }, nil
} }
// The PUT API for DBFS requires setting the content length header beforehand in the HTTP
// request.
func putContentLength(path, overwriteField string, file *os.File) (int64, error) {
buf := &bytes.Buffer{}
writer := multipart.NewWriter(buf)
err := writer.WriteField("path", path)
if err != nil {
return 0, fmt.Errorf("failed to write field path field in multipart form: %w", err)
}
err = writer.WriteField("overwrite", overwriteField)
if err != nil {
return 0, fmt.Errorf("failed to write field overwrite field in multipart form: %w", err)
}
_, err = writer.CreateFormFile("contents", "")
if err != nil {
return 0, fmt.Errorf("failed to write contents field in multipart form: %w", err)
}
err = writer.Close()
if err != nil {
return 0, fmt.Errorf("failed to close multipart form writer: %w", err)
}
stat, err := file.Stat()
if err != nil {
return 0, fmt.Errorf("failed to stat file %s: %w", path, err)
}
return int64(buf.Len()) + stat.Size(), nil
}
func contentLengthVisitor(path, overwriteField string, file *os.File) func(*http.Request) error {
return func(r *http.Request) error {
cl, err := putContentLength(path, overwriteField, file)
if err != nil {
return fmt.Errorf("failed to calculate content length: %w", err)
}
r.ContentLength = cl
return nil
}
}
func (w *DbfsClient) putFile(ctx context.Context, path string, overwrite bool, file *os.File) error { func (w *DbfsClient) putFile(ctx context.Context, path string, overwrite bool, file *os.File) error {
overwriteField := "False" overwriteField := "False"
if overwrite { if overwrite {
overwriteField = "True" overwriteField = "True"
} }
pr, pw := io.Pipe() buf := &bytes.Buffer{}
writer := multipart.NewWriter(pw) writer := multipart.NewWriter(buf)
go func() {
defer pw.Close()
err := writer.WriteField("path", path) err := writer.WriteField("path", path)
if err != nil { if err != nil {
pw.CloseWithError(fmt.Errorf("failed to write field path field in multipart form: %w", err)) return err
return
} }
err = writer.WriteField("overwrite", overwriteField) err = writer.WriteField("overwrite", overwriteField)
if err != nil { if err != nil {
pw.CloseWithError(fmt.Errorf("failed to write field overwrite field in multipart form: %w", err)) return err
return
} }
contents, err := writer.CreateFormFile("contents", "") contents, err := writer.CreateFormFile("contents", "")
if err != nil { if err != nil {
pw.CloseWithError(fmt.Errorf("failed to write contents field in multipart form: %w", err)) return err
return
} }
_, err = io.Copy(contents, file) _, err = io.Copy(contents, file)
if err != nil { if err != nil {
pw.CloseWithError(fmt.Errorf("error while streaming file to dbfs: %w", err)) return err
return
} }
err = writer.Close() err = writer.Close()
if err != nil { if err != nil {
pw.CloseWithError(fmt.Errorf("failed to close multipart form writer: %w", err)) return err
return
} }
}()
// Request bodies of Content-Type multipart/form-data are not supported by // Request bodies of Content-Type multipart/form-data are not supported by
// the Go SDK directly for DBFS. So we use the Do method directly. // the Go SDK directly for DBFS. So we use the Do method directly.
err := w.apiClient.Do(ctx, err = w.apiClient.Do(ctx, http.MethodPost, "/api/2.0/dbfs/put", map[string]string{
http.MethodPost, "Content-Type": writer.FormDataContentType(),
"/api/2.0/dbfs/put", }, buf.Bytes(), nil)
map[string]string{"Content-Type": writer.FormDataContentType()},
pr,
nil,
contentLengthVisitor(path, overwriteField, file))
var aerr *apierr.APIError var aerr *apierr.APIError
if errors.As(err, &aerr) && aerr.ErrorCode == "RESOURCE_ALREADY_EXISTS" { if errors.As(err, &aerr) && aerr.ErrorCode == "RESOURCE_ALREADY_EXISTS" {
return FileAlreadyExistsError{path} return FileAlreadyExistsError{path}

View File

@ -31,9 +31,7 @@ func (m *mockDbfsApiClient) Do(ctx context.Context, method, path string,
require.Equal(m.t, "POST", method) require.Equal(m.t, "POST", method)
require.Equal(m.t, "/api/2.0/dbfs/put", path) require.Equal(m.t, "/api/2.0/dbfs/put", path)
require.Contains(m.t, headers["Content-Type"], "multipart/form-data; boundary=") require.Contains(m.t, headers["Content-Type"], "multipart/form-data; boundary=")
contents, err := io.ReadAll(request.(io.Reader)) require.Contains(m.t, string(request.([]byte)), "hello world")
require.NoError(m.t, err)
require.Contains(m.t, string(contents), "hello world")
return nil return nil
} }

View File

@ -63,7 +63,7 @@ func TestFsOpenFile(t *testing.T) {
assert.Equal(t, "fileA", info.Name()) assert.Equal(t, "fileA", info.Name())
assert.Equal(t, int64(3), info.Size()) assert.Equal(t, int64(3), info.Size())
assert.Equal(t, fs.FileMode(0), info.Mode()) assert.Equal(t, fs.FileMode(0), info.Mode())
assert.False(t, info.IsDir()) assert.Equal(t, false, info.IsDir())
// Read until closed. // Read until closed.
b := make([]byte, 3) b := make([]byte, 3)
@ -91,7 +91,7 @@ func TestFsOpenDir(t *testing.T) {
info, err := fakeFile.Stat() info, err := fakeFile.Stat()
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "root", info.Name()) assert.Equal(t, "root", info.Name())
assert.True(t, info.IsDir()) assert.Equal(t, true, info.IsDir())
de, ok := fakeFile.(fs.ReadDirFile) de, ok := fakeFile.(fs.ReadDirFile)
require.True(t, ok) require.True(t, ok)

View File

@ -52,7 +52,7 @@ func TestGlobFileset(t *testing.T) {
files, err = g.Files() files, err = g.Files()
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, files) require.Equal(t, len(files), 0)
} }
func TestGlobFilesetWithRelativeRoot(t *testing.T) { func TestGlobFilesetWithRelativeRoot(t *testing.T) {

View File

@ -123,12 +123,12 @@ func TestJsonUnmarshalForRequest(t *testing.T) {
assert.Equal(t, "new job", r.NewSettings.Name) assert.Equal(t, "new job", r.NewSettings.Name)
assert.Equal(t, 0, r.NewSettings.TimeoutSeconds) assert.Equal(t, 0, r.NewSettings.TimeoutSeconds)
assert.Equal(t, 1, r.NewSettings.MaxConcurrentRuns) assert.Equal(t, 1, r.NewSettings.MaxConcurrentRuns)
assert.Len(t, r.NewSettings.Tasks, 1) assert.Equal(t, 1, len(r.NewSettings.Tasks))
assert.Equal(t, "new task", r.NewSettings.Tasks[0].TaskKey) assert.Equal(t, "new task", r.NewSettings.Tasks[0].TaskKey)
assert.Equal(t, 0, r.NewSettings.Tasks[0].TimeoutSeconds) assert.Equal(t, 0, r.NewSettings.Tasks[0].TimeoutSeconds)
assert.Equal(t, 0, r.NewSettings.Tasks[0].MaxRetries) assert.Equal(t, 0, r.NewSettings.Tasks[0].MaxRetries)
assert.Equal(t, 0, r.NewSettings.Tasks[0].MinRetryIntervalMillis) assert.Equal(t, 0, r.NewSettings.Tasks[0].MinRetryIntervalMillis)
assert.True(t, r.NewSettings.Tasks[0].RetryOnTimeout) assert.Equal(t, true, r.NewSettings.Tasks[0].RetryOnTimeout)
} }
const incorrectJsonData = `{ const incorrectJsonData = `{
@ -280,8 +280,8 @@ func TestJsonUnmarshalForRequestWithForceSendFields(t *testing.T) {
assert.NoError(t, diags.Error()) assert.NoError(t, diags.Error())
assert.Empty(t, diags) assert.Empty(t, diags)
assert.False(t, r.NewSettings.NotificationSettings.NoAlertForSkippedRuns) assert.Equal(t, false, r.NewSettings.NotificationSettings.NoAlertForSkippedRuns)
assert.False(t, r.NewSettings.NotificationSettings.NoAlertForCanceledRuns) assert.Equal(t, false, r.NewSettings.NotificationSettings.NoAlertForCanceledRuns)
assert.NotContains(t, r.NewSettings.NotificationSettings.ForceSendFields, "NoAlertForSkippedRuns") assert.NotContains(t, r.NewSettings.NotificationSettings.ForceSendFields, "NoAlertForSkippedRuns")
assert.Contains(t, r.NewSettings.NotificationSettings.ForceSendFields, "NoAlertForCanceledRuns") assert.Contains(t, r.NewSettings.NotificationSettings.ForceSendFields, "NoAlertForCanceledRuns")
} }

View File

@ -33,6 +33,6 @@ func TestFindDirWithLeaf(t *testing.T) {
{ {
out, err := FindDirWithLeaf(root, "this-leaf-doesnt-exist-anywhere") out, err := FindDirWithLeaf(root, "this-leaf-doesnt-exist-anywhere")
assert.ErrorIs(t, err, os.ErrNotExist) assert.ErrorIs(t, err, os.ErrNotExist)
assert.Equal(t, "", out) assert.Equal(t, out, "")
} }
} }

View File

@ -96,7 +96,7 @@ func TestTemplateFromString(t *testing.T) {
v, err = fromString("1.1", NumberType) v, err = fromString("1.1", NumberType)
assert.NoError(t, err) assert.NoError(t, err)
// Floating point conversions are not perfect // Floating point conversions are not perfect
assert.Less(t, (v.(float64) - 1.1), 0.000001) assert.True(t, (v.(float64)-1.1) < 0.000001)
v, err = fromString("12345", IntegerType) v, err = fromString("12345", IntegerType)
assert.NoError(t, err) assert.NoError(t, err)
@ -104,7 +104,7 @@ func TestTemplateFromString(t *testing.T) {
v, err = fromString("123", NumberType) v, err = fromString("123", NumberType)
assert.NoError(t, err) assert.NoError(t, err)
assert.InDelta(t, float64(123), v.(float64), 0.0001) assert.Equal(t, float64(123), v)
_, err = fromString("qrt", ArrayType) _, err = fromString("qrt", ArrayType)
assert.EqualError(t, err, "cannot parse string as object of type array. Value of string: \"qrt\"") assert.EqualError(t, err, "cannot parse string as object of type array. Value of string: \"qrt\"")

View File

@ -1,6 +1,7 @@
package notebook package notebook
import ( import (
"errors"
"io/fs" "io/fs"
"os" "os"
"path/filepath" "path/filepath"
@ -52,7 +53,7 @@ func TestDetectCallsDetectJupyter(t *testing.T) {
func TestDetectUnknownExtension(t *testing.T) { func TestDetectUnknownExtension(t *testing.T) {
_, _, err := Detect("./testdata/doesntexist.foobar") _, _, err := Detect("./testdata/doesntexist.foobar")
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
nb, _, err := Detect("./testdata/unknown_extension.foobar") nb, _, err := Detect("./testdata/unknown_extension.foobar")
require.NoError(t, err) require.NoError(t, err)
@ -61,7 +62,7 @@ func TestDetectUnknownExtension(t *testing.T) {
func TestDetectNoExtension(t *testing.T) { func TestDetectNoExtension(t *testing.T) {
_, _, err := Detect("./testdata/doesntexist") _, _, err := Detect("./testdata/doesntexist")
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
nb, _, err := Detect("./testdata/no_extension") nb, _, err := Detect("./testdata/no_extension")
require.NoError(t, err) require.NoError(t, err)

View File

@ -95,7 +95,7 @@ func TestBackgroundNoStdin(t *testing.T) {
func TestBackgroundFails(t *testing.T) { func TestBackgroundFails(t *testing.T) {
ctx := context.Background() ctx := context.Background()
_, err := Background(ctx, []string{"ls", "/dev/null/x"}) _, err := Background(ctx, []string{"ls", "/dev/null/x"})
assert.Error(t, err) assert.NotNil(t, err)
} }
func TestBackgroundFailsOnOption(t *testing.T) { func TestBackgroundFailsOnOption(t *testing.T) {

View File

@ -27,7 +27,7 @@ func TestForwardedFails(t *testing.T) {
err := Forwarded(ctx, []string{ err := Forwarded(ctx, []string{
"_non_existent_", "_non_existent_",
}, strings.NewReader("abc\n"), &buf, &buf) }, strings.NewReader("abc\n"), &buf, &buf)
assert.Error(t, err) assert.NotNil(t, err)
} }
func TestForwardedFailsOnStdinPipe(t *testing.T) { func TestForwardedFailsOnStdinPipe(t *testing.T) {
@ -39,5 +39,5 @@ func TestForwardedFailsOnStdinPipe(t *testing.T) {
c.Stdin = strings.NewReader("x") c.Stdin = strings.NewReader("x")
return nil return nil
}) })
assert.Error(t, err) assert.NotNil(t, err)
} }

View File

@ -41,7 +41,7 @@ func TestWorksWithLibsEnv(t *testing.T) {
vars := cmd.Environ() vars := cmd.Environ()
sort.Strings(vars) sort.Strings(vars)
assert.GreaterOrEqual(t, len(vars), 2) assert.True(t, len(vars) >= 2)
assert.Equal(t, "CCC=DDD", vars[0]) assert.Equal(t, "CCC=DDD", vars[0])
assert.Equal(t, "EEE=FFF", vars[1]) assert.Equal(t, "EEE=FFF", vars[1])
} }

View File

@ -18,7 +18,7 @@ func TestAtLeastOnePythonInstalled(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
a := all.Latest() a := all.Latest()
t.Logf("latest is: %s", a) t.Logf("latest is: %s", a)
assert.NotEmpty(t, all) assert.True(t, len(all) > 0)
} }
func TestNoInterpretersFound(t *testing.T) { func TestNoInterpretersFound(t *testing.T) {

View File

@ -51,7 +51,7 @@ func TestDiff(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
change, err := state.diff(ctx, files) change, err := state.diff(ctx, files)
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, change.delete) assert.Len(t, change.delete, 0)
assert.Len(t, change.put, 2) assert.Len(t, change.put, 2)
assert.Contains(t, change.put, "hello.txt") assert.Contains(t, change.put, "hello.txt")
assert.Contains(t, change.put, "world.txt") assert.Contains(t, change.put, "world.txt")
@ -67,7 +67,7 @@ func TestDiff(t *testing.T) {
change, err = state.diff(ctx, files) change, err = state.diff(ctx, files)
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, change.delete) assert.Len(t, change.delete, 0)
assert.Len(t, change.put, 1) assert.Len(t, change.put, 1)
assert.Contains(t, change.put, "world.txt") assert.Contains(t, change.put, "world.txt")
assertKeysOfMap(t, state.LastModifiedTimes, []string{"hello.txt", "world.txt"}) assertKeysOfMap(t, state.LastModifiedTimes, []string{"hello.txt", "world.txt"})
@ -82,7 +82,7 @@ func TestDiff(t *testing.T) {
change, err = state.diff(ctx, files) change, err = state.diff(ctx, files)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, change.delete, 1) assert.Len(t, change.delete, 1)
assert.Empty(t, change.put) assert.Len(t, change.put, 0)
assert.Contains(t, change.delete, "hello.txt") assert.Contains(t, change.delete, "hello.txt")
assertKeysOfMap(t, state.LastModifiedTimes, []string{"world.txt"}) assertKeysOfMap(t, state.LastModifiedTimes, []string{"world.txt"})
assert.Equal(t, map[string]string{"world.txt": "world.txt"}, state.LocalToRemoteNames) assert.Equal(t, map[string]string{"world.txt": "world.txt"}, state.LocalToRemoteNames)
@ -145,8 +145,8 @@ func TestFolderDiff(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
change, err := state.diff(ctx, files) change, err := state.diff(ctx, files)
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, change.delete) assert.Len(t, change.delete, 0)
assert.Empty(t, change.rmdir) assert.Len(t, change.rmdir, 0)
assert.Len(t, change.mkdir, 1) assert.Len(t, change.mkdir, 1)
assert.Len(t, change.put, 1) assert.Len(t, change.put, 1)
assert.Contains(t, change.mkdir, "foo") assert.Contains(t, change.mkdir, "foo")
@ -159,8 +159,8 @@ func TestFolderDiff(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, change.delete, 1) assert.Len(t, change.delete, 1)
assert.Len(t, change.rmdir, 1) assert.Len(t, change.rmdir, 1)
assert.Empty(t, change.mkdir) assert.Len(t, change.mkdir, 0)
assert.Empty(t, change.put) assert.Len(t, change.put, 0)
assert.Contains(t, change.delete, "foo/bar") assert.Contains(t, change.delete, "foo/bar")
assert.Contains(t, change.rmdir, "foo") assert.Contains(t, change.rmdir, "foo")
} }
@ -189,7 +189,7 @@ func TestPythonNotebookDiff(t *testing.T) {
foo.Overwrite(t, "# Databricks notebook source\nprint(\"abc\")") foo.Overwrite(t, "# Databricks notebook source\nprint(\"abc\")")
change, err := state.diff(ctx, files) change, err := state.diff(ctx, files)
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, change.delete) assert.Len(t, change.delete, 0)
assert.Len(t, change.put, 1) assert.Len(t, change.put, 1)
assert.Contains(t, change.put, "foo.py") assert.Contains(t, change.put, "foo.py")
assertKeysOfMap(t, state.LastModifiedTimes, []string{"foo.py"}) assertKeysOfMap(t, state.LastModifiedTimes, []string{"foo.py"})
@ -233,9 +233,9 @@ func TestPythonNotebookDiff(t *testing.T) {
change, err = state.diff(ctx, files) change, err = state.diff(ctx, files)
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, change.delete, 1) assert.Len(t, change.delete, 1)
assert.Empty(t, change.put) assert.Len(t, change.put, 0)
assert.Contains(t, change.delete, "foo") assert.Contains(t, change.delete, "foo")
assert.Empty(t, state.LastModifiedTimes) assert.Len(t, state.LastModifiedTimes, 0)
assert.Equal(t, map[string]string{}, state.LocalToRemoteNames) assert.Equal(t, map[string]string{}, state.LocalToRemoteNames)
assert.Equal(t, map[string]string{}, state.RemoteToLocalNames) assert.Equal(t, map[string]string{}, state.RemoteToLocalNames)
} }
@ -264,7 +264,7 @@ func TestErrorWhenIdenticalRemoteName(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
change, err := state.diff(ctx, files) change, err := state.diff(ctx, files)
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, change.delete) assert.Len(t, change.delete, 0)
assert.Len(t, change.put, 2) assert.Len(t, change.put, 2)
assert.Contains(t, change.put, "foo.py") assert.Contains(t, change.put, "foo.py")
assert.Contains(t, change.put, "foo") assert.Contains(t, change.put, "foo")
@ -300,7 +300,7 @@ func TestNoErrorRenameWithIdenticalRemoteName(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
change, err := state.diff(ctx, files) change, err := state.diff(ctx, files)
assert.NoError(t, err) assert.NoError(t, err)
assert.Empty(t, change.delete) assert.Len(t, change.delete, 0)
assert.Len(t, change.put, 1) assert.Len(t, change.put, 1)
assert.Contains(t, change.put, "foo.py") assert.Contains(t, change.put, "foo.py")

View File

@ -59,7 +59,7 @@ func TestGetFileSet(t *testing.T) {
fileList, err := s.GetFileList(ctx) fileList, err := s.GetFileList(ctx)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, fileList, 10) require.Equal(t, len(fileList), 10)
inc, err = fileset.NewGlobSet(root, []string{}) inc, err = fileset.NewGlobSet(root, []string{})
require.NoError(t, err) require.NoError(t, err)
@ -77,7 +77,7 @@ func TestGetFileSet(t *testing.T) {
fileList, err = s.GetFileList(ctx) fileList, err = s.GetFileList(ctx)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, fileList, 2) require.Equal(t, len(fileList), 2)
inc, err = fileset.NewGlobSet(root, []string{"./.databricks/*.go"}) inc, err = fileset.NewGlobSet(root, []string{"./.databricks/*.go"})
require.NoError(t, err) require.NoError(t, err)
@ -95,7 +95,7 @@ func TestGetFileSet(t *testing.T) {
fileList, err = s.GetFileList(ctx) fileList, err = s.GetFileList(ctx)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, fileList, 11) require.Equal(t, len(fileList), 11)
} }
func TestRecursiveExclude(t *testing.T) { func TestRecursiveExclude(t *testing.T) {
@ -125,7 +125,7 @@ func TestRecursiveExclude(t *testing.T) {
fileList, err := s.GetFileList(ctx) fileList, err := s.GetFileList(ctx)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, fileList, 7) require.Equal(t, len(fileList), 7)
} }
func TestNegateExclude(t *testing.T) { func TestNegateExclude(t *testing.T) {
@ -155,6 +155,6 @@ func TestNegateExclude(t *testing.T) {
fileList, err := s.GetFileList(ctx) fileList, err := s.GetFileList(ctx)
require.NoError(t, err) require.NoError(t, err)
require.Len(t, fileList, 1) require.Equal(t, len(fileList), 1)
require.Equal(t, "test/sub1/sub2/h.txt", fileList[0].Relative) require.Equal(t, fileList[0].Relative, "test/sub1/sub2/h.txt")
} }

View File

@ -24,7 +24,7 @@ func TestTemplateConfigAssignValuesFromFile(t *testing.T) {
err = c.assignValuesFromFile(filepath.Join(testDir, "config.json")) err = c.assignValuesFromFile(filepath.Join(testDir, "config.json"))
if assert.NoError(t, err) { if assert.NoError(t, err) {
assert.Equal(t, int64(1), c.values["int_val"]) assert.Equal(t, int64(1), c.values["int_val"])
assert.InDelta(t, float64(2), c.values["float_val"].(float64), 0.0001) assert.Equal(t, float64(2), c.values["float_val"])
assert.Equal(t, true, c.values["bool_val"]) assert.Equal(t, true, c.values["bool_val"])
assert.Equal(t, "hello", c.values["string_val"]) assert.Equal(t, "hello", c.values["string_val"])
} }
@ -44,7 +44,7 @@ func TestTemplateConfigAssignValuesFromFileDoesNotOverwriteExistingConfigs(t *te
err = c.assignValuesFromFile(filepath.Join(testDir, "config.json")) err = c.assignValuesFromFile(filepath.Join(testDir, "config.json"))
if assert.NoError(t, err) { if assert.NoError(t, err) {
assert.Equal(t, int64(1), c.values["int_val"]) assert.Equal(t, int64(1), c.values["int_val"])
assert.InDelta(t, float64(2), c.values["float_val"].(float64), 0.0001) assert.Equal(t, float64(2), c.values["float_val"])
assert.Equal(t, true, c.values["bool_val"]) assert.Equal(t, true, c.values["bool_val"])
assert.Equal(t, "this-is-not-overwritten", c.values["string_val"]) assert.Equal(t, "this-is-not-overwritten", c.values["string_val"])
} }
@ -89,7 +89,7 @@ func TestTemplateConfigAssignValuesFromDefaultValues(t *testing.T) {
err = c.assignDefaultValues(r) err = c.assignDefaultValues(r)
if assert.NoError(t, err) { if assert.NoError(t, err) {
assert.Equal(t, int64(123), c.values["int_val"]) assert.Equal(t, int64(123), c.values["int_val"])
assert.InDelta(t, float64(123), c.values["float_val"].(float64), 0.0001) assert.Equal(t, float64(123), c.values["float_val"])
assert.Equal(t, true, c.values["bool_val"]) assert.Equal(t, true, c.values["bool_val"])
assert.Equal(t, "hello", c.values["string_val"]) assert.Equal(t, "hello", c.values["string_val"])
} }
@ -110,7 +110,7 @@ func TestTemplateConfigAssignValuesFromTemplatedDefaultValues(t *testing.T) {
err = c.assignDefaultValues(r) err = c.assignDefaultValues(r)
if assert.NoError(t, err) { if assert.NoError(t, err) {
assert.Equal(t, int64(123), c.values["int_val"]) assert.Equal(t, int64(123), c.values["int_val"])
assert.InDelta(t, float64(123), c.values["float_val"].(float64), 0.0001) assert.Equal(t, float64(123), c.values["float_val"])
assert.Equal(t, true, c.values["bool_val"]) assert.Equal(t, true, c.values["bool_val"])
assert.Equal(t, "world", c.values["string_val"]) assert.Equal(t, "world", c.values["string_val"])
} }

View File

@ -86,7 +86,7 @@ func TestTemplateRandIntFunction(t *testing.T) {
assert.Len(t, r.files, 1) assert.Len(t, r.files, 1)
randInt, err := strconv.Atoi(strings.TrimSpace(string(r.files[0].(*inMemoryFile).content))) randInt, err := strconv.Atoi(strings.TrimSpace(string(r.files[0].(*inMemoryFile).content)))
assert.Less(t, randInt, 10) assert.Less(t, randInt, 10)
assert.NoError(t, err) assert.Empty(t, err)
} }
func TestTemplateUuidFunction(t *testing.T) { func TestTemplateUuidFunction(t *testing.T) {

View File

@ -434,7 +434,7 @@ func TestRendererSkipAllFilesInCurrentDirectory(t *testing.T) {
entries, err := os.ReadDir(tmpDir) entries, err := os.ReadDir(tmpDir)
require.NoError(t, err) require.NoError(t, err)
// Assert none of the files are persisted to disk, because of {{skip "*"}} // Assert none of the files are persisted to disk, because of {{skip "*"}}
assert.Empty(t, entries) assert.Len(t, entries, 0)
} }
func TestRendererSkipPatternsAreRelativeToFileDirectory(t *testing.T) { func TestRendererSkipPatternsAreRelativeToFileDirectory(t *testing.T) {
@ -588,8 +588,8 @@ func TestRendererNonTemplatesAreCreatedAsCopyFiles(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, r.files, 1) assert.Len(t, r.files, 1)
assert.Equal(t, "not-a-template", r.files[0].(*copyFile).srcPath) assert.Equal(t, r.files[0].(*copyFile).srcPath, "not-a-template")
assert.Equal(t, "not-a-template", r.files[0].RelPath()) assert.Equal(t, r.files[0].RelPath(), "not-a-template")
} }
func TestRendererFileTreeRendering(t *testing.T) { func TestRendererFileTreeRendering(t *testing.T) {
@ -609,7 +609,7 @@ func TestRendererFileTreeRendering(t *testing.T) {
// Assert in memory representation is created. // Assert in memory representation is created.
assert.Len(t, r.files, 1) assert.Len(t, r.files, 1)
assert.Equal(t, "my_directory/my_file", r.files[0].RelPath()) assert.Equal(t, r.files[0].RelPath(), "my_directory/my_file")
out, err := filer.NewLocalClient(tmpDir) out, err := filer.NewLocalClient(tmpDir)
require.NoError(t, err) require.NoError(t, err)

View File

@ -19,25 +19,22 @@ import (
var OverwriteMode = os.Getenv("TESTS_OUTPUT") == "OVERWRITE" var OverwriteMode = os.Getenv("TESTS_OUTPUT") == "OVERWRITE"
func ReadFile(t testutil.TestingT, ctx context.Context, filename string) string { func ReadFile(t testutil.TestingT, ctx context.Context, filename string) string {
t.Helper()
data, err := os.ReadFile(filename) data, err := os.ReadFile(filename)
if os.IsNotExist(err) { if os.IsNotExist(err) {
return "" return ""
} }
assert.NoError(t, err, "Failed to read %s", filename) assert.NoError(t, err)
// On CI, on Windows \n in the file somehow end up as \r\n // On CI, on Windows \n in the file somehow end up as \r\n
return NormalizeNewlines(string(data)) return NormalizeNewlines(string(data))
} }
func WriteFile(t testutil.TestingT, filename, data string) { func WriteFile(t testutil.TestingT, filename, data string) {
t.Helper()
t.Logf("Overwriting %s", filename) t.Logf("Overwriting %s", filename)
err := os.WriteFile(filename, []byte(data), 0o644) err := os.WriteFile(filename, []byte(data), 0o644)
assert.NoError(t, err, "Failed to write %s", filename) assert.NoError(t, err)
} }
func AssertOutput(t testutil.TestingT, ctx context.Context, out, outTitle, expectedPath string) { func AssertOutput(t testutil.TestingT, ctx context.Context, out, outTitle, expectedPath string) {
t.Helper()
expected := ReadFile(t, ctx, expectedPath) expected := ReadFile(t, ctx, expectedPath)
out = ReplaceOutput(t, ctx, out) out = ReplaceOutput(t, ctx, out)
@ -52,7 +49,6 @@ func AssertOutput(t testutil.TestingT, ctx context.Context, out, outTitle, expec
} }
func AssertOutputJQ(t testutil.TestingT, ctx context.Context, out, outTitle, expectedPath string, ignorePaths []string) { func AssertOutputJQ(t testutil.TestingT, ctx context.Context, out, outTitle, expectedPath string, ignorePaths []string) {
t.Helper()
expected := ReadFile(t, ctx, expectedPath) expected := ReadFile(t, ctx, expectedPath)
out = ReplaceOutput(t, ctx, out) out = ReplaceOutput(t, ctx, out)
@ -73,7 +69,6 @@ var (
) )
func ReplaceOutput(t testutil.TestingT, ctx context.Context, out string) string { func ReplaceOutput(t testutil.TestingT, ctx context.Context, out string) string {
t.Helper()
out = NormalizeNewlines(out) out = NormalizeNewlines(out)
replacements := GetReplacementsMap(ctx) replacements := GetReplacementsMap(ctx)
if replacements == nil { if replacements == nil {
@ -141,7 +136,6 @@ func GetReplacementsMap(ctx context.Context) *ReplacementsContext {
} }
func PrepareReplacements(t testutil.TestingT, r *ReplacementsContext, w *databricks.WorkspaceClient) { 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) // 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://") host := strings.TrimPrefix(strings.TrimPrefix(w.Config.Host, "http://"), "https://")
r.Set(host, "$DATABRICKS_HOST") r.Set(host, "$DATABRICKS_HOST")
@ -173,7 +167,6 @@ func PrepareReplacements(t testutil.TestingT, r *ReplacementsContext, w *databri
} }
func PrepareReplacementsUser(t testutil.TestingT, r *ReplacementsContext, u iam.User) { 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 // 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 // to ensure we match the largest one first and map them all to the same token
names := []string{ names := []string{

View File

@ -18,10 +18,9 @@ func UnifiedDiff(filename1, filename2, s1, s2 string) string {
} }
func AssertEqualTexts(t testutil.TestingT, filename1, filename2, expected, out string) { func AssertEqualTexts(t testutil.TestingT, filename1, filename2, expected, out string) {
t.Helper()
if len(out) < 1000 && len(expected) < 1000 { if len(out) < 1000 && len(expected) < 1000 {
// This shows full strings + diff which could be useful when debugging newlines // This shows full strings + diff which could be useful when debugging newlines
assert.Equal(t, expected, out, "%s vs %s", filename1, filename2) assert.Equal(t, expected, out)
} else { } else {
// only show diff for large texts // only show diff for large texts
diff := UnifiedDiff(filename1, filename2, expected, out) diff := UnifiedDiff(filename1, filename2, expected, out)
@ -30,7 +29,6 @@ func AssertEqualTexts(t testutil.TestingT, filename1, filename2, expected, out s
} }
func AssertEqualJQ(t testutil.TestingT, expectedName, outName, expected, out string, ignorePaths []string) { func AssertEqualJQ(t testutil.TestingT, expectedName, outName, expected, out string, ignorePaths []string) {
t.Helper()
patch, err := jsondiff.CompareJSON([]byte(expected), []byte(out)) patch, err := jsondiff.CompareJSON([]byte(expected), []byte(out))
if err != nil { if err != nil {
t.Logf("CompareJSON error for %s vs %s: %s (fallback to textual comparison)", outName, expectedName, err) t.Logf("CompareJSON error for %s vs %s: %s (fallback to textual comparison)", outName, expectedName, err)

View File

@ -2,6 +2,7 @@ package vfs
import ( import (
"context" "context"
"errors"
"io/fs" "io/fs"
"os" "os"
"path/filepath" "path/filepath"
@ -41,7 +42,7 @@ func TestFilerPath(t *testing.T) {
// Open non-existent file. // Open non-existent file.
_, err = p.Open("doesntexist_test.go") _, err = p.Open("doesntexist_test.go")
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
// Stat self. // Stat self.
s, err = p.Stat("filer_test.go") s, err = p.Stat("filer_test.go")
@ -51,7 +52,7 @@ func TestFilerPath(t *testing.T) {
// Stat non-existent file. // Stat non-existent file.
_, err = p.Stat("doesntexist_test.go") _, err = p.Stat("doesntexist_test.go")
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
// ReadDir self. // ReadDir self.
entries, err := p.ReadDir(".") entries, err := p.ReadDir(".")
@ -60,7 +61,7 @@ func TestFilerPath(t *testing.T) {
// ReadDir non-existent directory. // ReadDir non-existent directory.
_, err = p.ReadDir("doesntexist") _, err = p.ReadDir("doesntexist")
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
// ReadFile self. // ReadFile self.
buf, err = p.ReadFile("filer_test.go") buf, err = p.ReadFile("filer_test.go")
@ -69,7 +70,7 @@ func TestFilerPath(t *testing.T) {
// ReadFile non-existent file. // ReadFile non-existent file.
_, err = p.ReadFile("doesntexist_test.go") _, err = p.ReadFile("doesntexist_test.go")
assert.ErrorIs(t, err, fs.ErrNotExist) assert.True(t, errors.Is(err, fs.ErrNotExist))
// Parent self. // Parent self.
pp := p.Parent() pp := p.Parent()

17
lint.sh
View File

@ -1,14 +1,9 @@
#!/bin/bash #!/bin/bash
set -uo pipefail set -euo pipefail
# With golangci-lint, if there are any compliation issues, then formatters' autofix won't be applied. # With golangci-lint, if there are any compliation issues, then formatters' autofix won't be applied.
# https://github.com/golangci/golangci-lint/issues/5257 # https://github.com/golangci/golangci-lint/issues/5257
# However, running goimports first alone will actually fix some of the compilation issues.
golangci-lint run --fix "$@" # Fixing formatting is also reasonable thing to do.
lint_exit_code=$? # For this reason, this script runs golangci-lint in two stages:
golangci-lint run --enable-only="gofmt,gofumpt,goimports" --fix $@
if [ $lint_exit_code -ne 0 ]; then exec golangci-lint run --fix $@
# These linters work in presence of compilation issues when run alone, so let's get these fixes at least.
golangci-lint run --enable-only="gofmt,gofumpt,goimports" --fix "$@"
fi
exit $lint_exit_code