github.com/databricks/cli@v0.203.0/bundle/config/mutator/process_environment_mode_test.go (about) 1 package mutator 2 3 import ( 4 "context" 5 "reflect" 6 "strings" 7 "testing" 8 9 "github.com/databricks/cli/bundle" 10 "github.com/databricks/cli/bundle/config" 11 "github.com/databricks/cli/bundle/config/resources" 12 "github.com/databricks/databricks-sdk-go/service/iam" 13 "github.com/databricks/databricks-sdk-go/service/jobs" 14 "github.com/databricks/databricks-sdk-go/service/ml" 15 "github.com/databricks/databricks-sdk-go/service/pipelines" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 func mockBundle(mode config.Mode) *bundle.Bundle { 21 return &bundle.Bundle{ 22 Config: config.Root{ 23 Bundle: config.Bundle{ 24 Mode: mode, 25 Git: config.Git{ 26 OriginURL: "http://origin", 27 Branch: "main", 28 }, 29 }, 30 Workspace: config.Workspace{ 31 CurrentUser: &config.User{ 32 ShortName: "lennart", 33 User: &iam.User{ 34 UserName: "lennart@company.com", 35 Id: "1", 36 }, 37 }, 38 StatePath: "/Users/lennart@company.com/.bundle/x/y/state", 39 ArtifactsPath: "/Users/lennart@company.com/.bundle/x/y/artifacts", 40 FilesPath: "/Users/lennart@company.com/.bundle/x/y/files", 41 }, 42 Resources: config.Resources{ 43 Jobs: map[string]*resources.Job{ 44 "job1": {JobSettings: &jobs.JobSettings{Name: "job1"}}, 45 }, 46 Pipelines: map[string]*resources.Pipeline{ 47 "pipeline1": {PipelineSpec: &pipelines.PipelineSpec{Name: "pipeline1"}}, 48 }, 49 Experiments: map[string]*resources.MlflowExperiment{ 50 "experiment1": {Experiment: &ml.Experiment{Name: "/Users/lennart.kats@databricks.com/experiment1"}}, 51 "experiment2": {Experiment: &ml.Experiment{Name: "experiment2"}}, 52 }, 53 Models: map[string]*resources.MlflowModel{ 54 "model1": {Model: &ml.Model{Name: "model1"}}, 55 }, 56 }, 57 }, 58 } 59 } 60 61 func TestProcessEnvironmentModeDevelopment(t *testing.T) { 62 bundle := mockBundle(config.Development) 63 64 m := ProcessEnvironmentMode() 65 err := m.Apply(context.Background(), bundle) 66 require.NoError(t, err) 67 assert.Equal(t, "[dev lennart] job1", bundle.Config.Resources.Jobs["job1"].Name) 68 assert.Equal(t, "[dev lennart] pipeline1", bundle.Config.Resources.Pipelines["pipeline1"].Name) 69 assert.Equal(t, "/Users/lennart.kats@databricks.com/[dev lennart] experiment1", bundle.Config.Resources.Experiments["experiment1"].Name) 70 assert.Equal(t, "[dev lennart] experiment2", bundle.Config.Resources.Experiments["experiment2"].Name) 71 assert.Equal(t, "[dev lennart] model1", bundle.Config.Resources.Models["model1"].Name) 72 assert.Equal(t, "dev", bundle.Config.Resources.Experiments["experiment1"].Experiment.Tags[0].Key) 73 assert.True(t, bundle.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Development) 74 } 75 76 func TestProcessEnvironmentModeDefault(t *testing.T) { 77 bundle := mockBundle("") 78 79 m := ProcessEnvironmentMode() 80 err := m.Apply(context.Background(), bundle) 81 require.NoError(t, err) 82 assert.Equal(t, "job1", bundle.Config.Resources.Jobs["job1"].Name) 83 assert.Equal(t, "pipeline1", bundle.Config.Resources.Pipelines["pipeline1"].Name) 84 assert.False(t, bundle.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Development) 85 } 86 87 func TestProcessEnvironmentModeProduction(t *testing.T) { 88 bundle := mockBundle(config.Production) 89 90 err := validateProductionMode(context.Background(), bundle, false) 91 require.ErrorContains(t, err, "state_path") 92 93 bundle.Config.Workspace.StatePath = "/Shared/.bundle/x/y/state" 94 bundle.Config.Workspace.ArtifactsPath = "/Shared/.bundle/x/y/artifacts" 95 bundle.Config.Workspace.FilesPath = "/Shared/.bundle/x/y/files" 96 97 err = validateProductionMode(context.Background(), bundle, false) 98 require.ErrorContains(t, err, "production") 99 100 permissions := []resources.Permission{ 101 { 102 Level: "CAN_MANAGE", 103 UserName: "user@company.com", 104 }, 105 } 106 bundle.Config.Resources.Jobs["job1"].Permissions = permissions 107 bundle.Config.Resources.Jobs["job1"].RunAs = &jobs.JobRunAs{UserName: "user@company.com"} 108 bundle.Config.Resources.Pipelines["pipeline1"].Permissions = permissions 109 bundle.Config.Resources.Experiments["experiment1"].Permissions = permissions 110 bundle.Config.Resources.Experiments["experiment2"].Permissions = permissions 111 bundle.Config.Resources.Models["model1"].Permissions = permissions 112 113 err = validateProductionMode(context.Background(), bundle, false) 114 require.NoError(t, err) 115 116 assert.Equal(t, "job1", bundle.Config.Resources.Jobs["job1"].Name) 117 assert.Equal(t, "pipeline1", bundle.Config.Resources.Pipelines["pipeline1"].Name) 118 assert.False(t, bundle.Config.Resources.Pipelines["pipeline1"].PipelineSpec.Development) 119 } 120 121 func TestProcessEnvironmentModeProductionGit(t *testing.T) { 122 bundle := mockBundle(config.Production) 123 124 // Pretend the user didn't set Git configuration explicitly 125 bundle.Config.Bundle.Git.Inferred = true 126 127 err := validateProductionMode(context.Background(), bundle, false) 128 require.ErrorContains(t, err, "git") 129 bundle.Config.Bundle.Git.Inferred = false 130 } 131 132 func TestProcessEnvironmentModeProductionOkForPrincipal(t *testing.T) { 133 bundle := mockBundle(config.Production) 134 135 // Our environment has all kinds of problems when not using service principals ... 136 err := validateProductionMode(context.Background(), bundle, false) 137 require.Error(t, err) 138 139 // ... but we're much less strict when a principal is used 140 err = validateProductionMode(context.Background(), bundle, true) 141 require.NoError(t, err) 142 } 143 144 // Make sure that we have test coverage for all resource types 145 func TestAllResourcesMocked(t *testing.T) { 146 bundle := mockBundle(config.Development) 147 resources := reflect.ValueOf(bundle.Config.Resources) 148 149 for i := 0; i < resources.NumField(); i++ { 150 field := resources.Field(i) 151 if field.Kind() == reflect.Map { 152 assert.True( 153 t, 154 !field.IsNil() && field.Len() > 0, 155 "process_environment_mode should support '%s' (please add it to process_environment_mode.go and extend the test suite)", 156 resources.Type().Field(i).Name, 157 ) 158 } 159 } 160 } 161 162 // Make sure that we at least rename all resources 163 func TestAllResourcesRenamed(t *testing.T) { 164 bundle := mockBundle(config.Development) 165 resources := reflect.ValueOf(bundle.Config.Resources) 166 167 m := ProcessEnvironmentMode() 168 err := m.Apply(context.Background(), bundle) 169 require.NoError(t, err) 170 171 for i := 0; i < resources.NumField(); i++ { 172 field := resources.Field(i) 173 174 if field.Kind() == reflect.Map { 175 for _, key := range field.MapKeys() { 176 resource := field.MapIndex(key) 177 nameField := resource.Elem().FieldByName("Name") 178 if nameField.IsValid() && nameField.Kind() == reflect.String { 179 assert.True( 180 t, 181 strings.Contains(nameField.String(), "dev"), 182 "process_environment_mode should rename '%s' in '%s'", 183 key, 184 resources.Type().Field(i).Name, 185 ) 186 } 187 } 188 } 189 } 190 }