package mutator import ( "context" "testing" "github.com/databricks/cli/bundle" "github.com/databricks/cli/bundle/config" "github.com/databricks/cli/bundle/config/variable" "github.com/databricks/cli/libs/env" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/databricks/databricks-sdk-go/experimental/mocks" "github.com/databricks/databricks-sdk-go/service/compute" "github.com/databricks/databricks-sdk-go/service/iam" ) func TestResolveClusterReference(t *testing.T) { clusterRef1 := "Some Custom Cluster" clusterRef2 := "Some Other Name" justString := "random string" b := &bundle.Bundle{ Config: config.Root{ Variables: map[string]*variable.Variable{ "my-cluster-id-1": { Lookup: &variable.Lookup{ Cluster: clusterRef1, }, }, "my-cluster-id-2": { Lookup: &variable.Lookup{ Cluster: clusterRef2, }, }, "some-variable": { Value: justString, }, }, }, } m := mocks.NewMockWorkspaceClient(t) b.SetWorkpaceClient(m.WorkspaceClient) clusterApi := m.GetMockClustersAPI() clusterApi.EXPECT().ListAll(mock.Anything, compute.ListClustersRequest{ FilterBy: &compute.ListClustersFilterBy{ ClusterSources: []compute.ClusterSource{compute.ClusterSourceApi, compute.ClusterSourceUi}, }, }).Return([]compute.ClusterDetails{ {ClusterId: "1234-5678-abcd", ClusterName: clusterRef1}, {ClusterId: "9876-5432-xywz", ClusterName: clusterRef2}, }, nil) diags := bundle.Apply(context.Background(), b, ResolveResourceReferences()) require.NoError(t, diags.Error()) require.Equal(t, "1234-5678-abcd", b.Config.Variables["my-cluster-id-1"].Value) require.Equal(t, "9876-5432-xywz", b.Config.Variables["my-cluster-id-2"].Value) } func TestResolveNonExistentClusterReference(t *testing.T) { clusterRef := "Random" justString := "random string" b := &bundle.Bundle{ Config: config.Root{ Variables: map[string]*variable.Variable{ "my-cluster-id": { Lookup: &variable.Lookup{ Cluster: clusterRef, }, }, "some-variable": { Value: justString, }, }, }, } m := mocks.NewMockWorkspaceClient(t) b.SetWorkpaceClient(m.WorkspaceClient) clusterApi := m.GetMockClustersAPI() clusterApi.EXPECT().ListAll(mock.Anything, compute.ListClustersRequest{ FilterBy: &compute.ListClustersFilterBy{ ClusterSources: []compute.ClusterSource{compute.ClusterSourceApi, compute.ClusterSourceUi}, }, }).Return([]compute.ClusterDetails{ {ClusterId: "1234-5678-abcd", ClusterName: "some other cluster"}, }, nil) diags := bundle.Apply(context.Background(), b, ResolveResourceReferences()) require.ErrorContains(t, diags.Error(), "failed to resolve cluster: Random, err: cluster named 'Random' does not exist") } func TestNoLookupIfVariableIsSet(t *testing.T) { clusterRef := "donotexist" b := &bundle.Bundle{ Config: config.Root{ Variables: map[string]*variable.Variable{ "my-cluster-id": { Lookup: &variable.Lookup{ Cluster: clusterRef, }, }, }, }, } m := mocks.NewMockWorkspaceClient(t) b.SetWorkpaceClient(m.WorkspaceClient) b.Config.Variables["my-cluster-id"].Set("random value") diags := bundle.Apply(context.Background(), b, ResolveResourceReferences()) require.NoError(t, diags.Error()) require.Equal(t, "random value", b.Config.Variables["my-cluster-id"].Value) } func TestResolveServicePrincipal(t *testing.T) { spName := "Some SP name" b := &bundle.Bundle{ Config: config.Root{ Variables: map[string]*variable.Variable{ "my-sp": { Lookup: &variable.Lookup{ ServicePrincipal: spName, }, }, }, }, } m := mocks.NewMockWorkspaceClient(t) b.SetWorkpaceClient(m.WorkspaceClient) spApi := m.GetMockServicePrincipalsAPI() spApi.EXPECT().GetByDisplayName(mock.Anything, spName).Return(&iam.ServicePrincipal{ Id: "1234", ApplicationId: "app-1234", }, nil) diags := bundle.Apply(context.Background(), b, ResolveResourceReferences()) require.NoError(t, diags.Error()) require.Equal(t, "app-1234", b.Config.Variables["my-sp"].Value) } func TestResolveVariableReferencesInVariableLookups(t *testing.T) { s := "bar" b := &bundle.Bundle{ Config: config.Root{ Bundle: config.Bundle{ Target: "dev", }, Variables: map[string]*variable.Variable{ "foo": { Value: s, }, "lookup": { Lookup: &variable.Lookup{ Cluster: "cluster-${var.foo}-${bundle.target}", }, }, }, }, } m := mocks.NewMockWorkspaceClient(t) b.SetWorkpaceClient(m.WorkspaceClient) clusterApi := m.GetMockClustersAPI() clusterApi.EXPECT().ListAll(mock.Anything, compute.ListClustersRequest{ FilterBy: &compute.ListClustersFilterBy{ ClusterSources: []compute.ClusterSource{compute.ClusterSourceApi, compute.ClusterSourceUi}, }, }).Return([]compute.ClusterDetails{ {ClusterId: "1234-5678-abcd", ClusterName: "cluster-bar-dev"}, {ClusterId: "9876-5432-xywz", ClusterName: "some other cluster"}, }, nil) diags := bundle.Apply(context.Background(), b, bundle.Seq(ResolveVariableReferencesInLookup(), ResolveResourceReferences())) require.NoError(t, diags.Error()) require.Equal(t, "cluster-bar-dev", b.Config.Variables["lookup"].Lookup.Cluster) require.Equal(t, "1234-5678-abcd", b.Config.Variables["lookup"].Value) } func TestResolveLookupVariableReferencesInVariableLookups(t *testing.T) { b := &bundle.Bundle{ Config: config.Root{ Variables: map[string]*variable.Variable{ "another_lookup": { Lookup: &variable.Lookup{ Cluster: "cluster", }, }, "lookup": { Lookup: &variable.Lookup{ Cluster: "cluster-${var.another_lookup}", }, }, }, }, } m := mocks.NewMockWorkspaceClient(t) b.SetWorkpaceClient(m.WorkspaceClient) diags := bundle.Apply(context.Background(), b, bundle.Seq(ResolveVariableReferencesInLookup(), ResolveResourceReferences())) require.ErrorContains(t, diags.Error(), "lookup variables cannot contain references to another lookup variables") } func TestNoResolveLookupIfVariableSetWithEnvVariable(t *testing.T) { b := &bundle.Bundle{ Config: config.Root{ Bundle: config.Bundle{ Target: "dev", }, Variables: map[string]*variable.Variable{ "lookup": { Lookup: &variable.Lookup{ Cluster: "cluster-${bundle.target}", }, }, }, }, } m := mocks.NewMockWorkspaceClient(t) b.SetWorkpaceClient(m.WorkspaceClient) ctx := context.Background() ctx = env.Set(ctx, "BUNDLE_VAR_lookup", "1234-5678-abcd") diags := bundle.Apply(ctx, b, bundle.Seq(SetVariables(), ResolveVariableReferencesInLookup(), ResolveResourceReferences())) require.NoError(t, diags.Error()) require.Equal(t, "1234-5678-abcd", b.Config.Variables["lookup"].Value) }