|
1 | 1 | package catalog_test |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "context" |
4 | 5 | "fmt" |
| 6 | + "regexp" |
| 7 | + "strings" |
5 | 8 | "testing" |
6 | 9 |
|
7 | 10 | "github.com/databricks/terraform-provider-databricks/internal/acceptance" |
| 11 | + "github.com/databricks/terraform-provider-databricks/qa" |
| 12 | + tfjson "github.com/hashicorp/terraform-json" |
| 13 | + "github.com/hashicorp/terraform-plugin-testing/helper/resource" |
| 14 | + "github.com/hashicorp/terraform-plugin-testing/plancheck" |
8 | 15 | ) |
9 | 16 |
|
10 | 17 | func TestUcAccCatalog(t *testing.T) { |
@@ -55,6 +62,35 @@ func TestUcAccCatalogIsolated(t *testing.T) { |
55 | 62 | }) |
56 | 63 | } |
57 | 64 |
|
| 65 | +type checkResourceRecreate struct { |
| 66 | + address string |
| 67 | +} |
| 68 | + |
| 69 | +func (c checkResourceRecreate) CheckPlan(ctx context.Context, req plancheck.CheckPlanRequest, resp *plancheck.CheckPlanResponse) { |
| 70 | + var change *tfjson.ResourceChange |
| 71 | + for _, resourceChange := range req.Plan.ResourceChanges { |
| 72 | + if resourceChange.Address == c.address { |
| 73 | + change = resourceChange |
| 74 | + break |
| 75 | + } |
| 76 | + } |
| 77 | + if change == nil { |
| 78 | + addressesWithPlannedChanges := make([]string, 0, len(req.Plan.ResourceChanges)) |
| 79 | + for _, change := range req.Plan.ResourceChanges { |
| 80 | + addressesWithPlannedChanges = append(addressesWithPlannedChanges, change.Address) |
| 81 | + } |
| 82 | + resp.Error = fmt.Errorf("address %s not found in resource changes; only planned changes for addresses %s", c.address, strings.Join(addressesWithPlannedChanges, ", ")) |
| 83 | + return |
| 84 | + } |
| 85 | + if change.Change.Actions[0] != tfjson.ActionDelete { |
| 86 | + plannedActions := make([]string, 0, len(change.Change.Actions)) |
| 87 | + for _, action := range change.Change.Actions { |
| 88 | + plannedActions = append(plannedActions, string(action)) |
| 89 | + } |
| 90 | + resp.Error = fmt.Errorf("no delete is planned for %s; planned actions are: %s", c.address, strings.Join(plannedActions, ", ")) |
| 91 | + } |
| 92 | +} |
| 93 | + |
58 | 94 | func TestUcAccCatalogUpdate(t *testing.T) { |
59 | 95 | acceptance.LoadUcwsEnv(t) |
60 | 96 | acceptance.UnityWorkspaceLevel(t, acceptance.Step{ |
@@ -100,5 +136,124 @@ func TestUcAccCatalogUpdate(t *testing.T) { |
100 | 136 | %s |
101 | 137 | owner = "{env.TEST_METASTORE_ADMIN_GROUP_NAME}" |
102 | 138 | }`, getPredictiveOptimizationSetting(t, false)), |
| 139 | + }, acceptance.Step{ |
| 140 | + // Adding options should cause the catalog to be recreated. |
| 141 | + Template: fmt.Sprintf(` |
| 142 | + resource "databricks_catalog" "sandbox" { |
| 143 | + name = "sandbox{var.STICKY_RANDOM}" |
| 144 | + comment = "this catalog is managed by terraform - updated comment" |
| 145 | + properties = { |
| 146 | + purpose = "testing" |
| 147 | + } |
| 148 | + options = { |
| 149 | + user = "miles" |
| 150 | + } |
| 151 | + %s |
| 152 | + owner = "{env.TEST_METASTORE_ADMIN_GROUP_NAME}" |
| 153 | + }`, getPredictiveOptimizationSetting(t, false)), |
| 154 | + ConfigPlanChecks: resource.ConfigPlanChecks{ |
| 155 | + PreApply: []plancheck.PlanCheck{ |
| 156 | + checkResourceRecreate{address: "databricks_catalog.sandbox"}, |
| 157 | + }, |
| 158 | + }, |
| 159 | + }) |
| 160 | +} |
| 161 | + |
| 162 | +// Create a connection to an HMS catalog and update authorized_paths. |
| 163 | +func TestUcAccCatalogHmsConnectionUpdate(t *testing.T) { |
| 164 | + authorizedPath := fmt.Sprintf("s3://%s/path/to/authorized", qa.RandomName("hms-bucket-")) |
| 165 | + otherAuthorizedPath := fmt.Sprintf("s3://%s/path/to/authorized", qa.RandomName("hms-other-bucket-")) |
| 166 | + otherInfra := fmt.Sprintf(` |
| 167 | + resource "databricks_connection" "sandbox" { |
| 168 | + name = "hms_connection{var.STICKY_RANDOM}" |
| 169 | + connection_type = "HIVE_METASTORE" |
| 170 | + comment = "created in TestUcAccCatalogHmsConnectionUpdate" |
| 171 | + options = { |
| 172 | + host = "test.mysql.database.azure.com" |
| 173 | + port = "3306" |
| 174 | + user = "user" |
| 175 | + password = "password" |
| 176 | + database = "metastore" |
| 177 | + db_type = "MYSQL" |
| 178 | + version = "2.3" |
| 179 | + } |
| 180 | + properties = { |
| 181 | + purpose = "testing" |
| 182 | + } |
| 183 | + } |
| 184 | + resource "databricks_storage_credential" "external" { |
| 185 | + name = "cred-{var.STICKY_RANDOM}" |
| 186 | + aws_iam_role { |
| 187 | + role_arn = "{env.TEST_METASTORE_DATA_ACCESS_ARN}" |
| 188 | + } |
| 189 | + comment = "created in TestUcAccCatalogHmsConnectionUpdate" |
| 190 | + } |
| 191 | + resource "databricks_external_location" "sandbox" { |
| 192 | + name = "sandbox{var.STICKY_RANDOM}" |
| 193 | + comment = "created in TestUcAccCatalogHmsConnectionUpdate" |
| 194 | + url = "%s" |
| 195 | + credential_name = "${databricks_storage_credential.external.name}" |
| 196 | + skip_validation = true |
| 197 | + } |
| 198 | + resource "databricks_external_location" "sandbox-other" { |
| 199 | + name = "sandbox-other{var.STICKY_RANDOM}" |
| 200 | + comment = "created in TestUcAccCatalogHmsConnectionUpdate" |
| 201 | + url = "%s" |
| 202 | + credential_name = "${databricks_storage_credential.external.name}" |
| 203 | + skip_validation = true |
| 204 | + } |
| 205 | + `, authorizedPath, otherAuthorizedPath) |
| 206 | + acceptance.UnityWorkspaceLevel(t, acceptance.Step{ |
| 207 | + Template: otherInfra + fmt.Sprintf(` |
| 208 | + resource "databricks_catalog" "sandbox" { |
| 209 | + name = "sandbox{var.STICKY_RANDOM}" |
| 210 | + comment = "created in TestUcAccCatalogHmsConnectionUpdate" |
| 211 | + connection_name = "${databricks_connection.sandbox.name}" |
| 212 | + options = { |
| 213 | + authorized_paths = "%s" |
| 214 | + } |
| 215 | + lifecycle { |
| 216 | + prevent_destroy = true |
| 217 | + } |
| 218 | + depends_on = [databricks_external_location.sandbox, databricks_external_location.sandbox-other] |
| 219 | + }`, authorizedPath), |
| 220 | + }, acceptance.Step{ |
| 221 | + Template: otherInfra + fmt.Sprintf(` |
| 222 | + resource "databricks_catalog" "sandbox" { |
| 223 | + name = "sandbox{var.STICKY_RANDOM}" |
| 224 | + comment = "created in TestUcAccCatalogHmsConnectionUpdate" |
| 225 | + connection_name = "${databricks_connection.sandbox.name}" |
| 226 | + options = { |
| 227 | + authorized_paths = "%s,%s" |
| 228 | + } |
| 229 | + lifecycle { |
| 230 | + prevent_destroy = true |
| 231 | + } |
| 232 | + }`, authorizedPath, otherAuthorizedPath), |
| 233 | + }, acceptance.Step{ |
| 234 | + Template: otherInfra + fmt.Sprintf(` |
| 235 | + resource "databricks_catalog" "sandbox" { |
| 236 | + name = "sandbox{var.STICKY_RANDOM}" |
| 237 | + comment = "created in TestUcAccCatalogHmsConnectionUpdate" |
| 238 | + connection_name = "${databricks_connection.sandbox.name}" |
| 239 | + options = { |
| 240 | + authorized_paths = "%s,%s" |
| 241 | + other_option = "value" |
| 242 | + } |
| 243 | + lifecycle { |
| 244 | + prevent_destroy = true |
| 245 | + } |
| 246 | + }`, authorizedPath, otherAuthorizedPath), |
| 247 | + ExpectError: regexp.MustCompile("Instance cannot be destroyed"), |
| 248 | + }, acceptance.Step{ |
| 249 | + Template: otherInfra + fmt.Sprintf(` |
| 250 | + resource "databricks_catalog" "sandbox" { |
| 251 | + name = "sandbox{var.STICKY_RANDOM}" |
| 252 | + comment = "created in TestUcAccCatalogHmsConnectionUpdate" |
| 253 | + connection_name = "${databricks_connection.sandbox.name}" |
| 254 | + options = { |
| 255 | + authorized_paths = "%s,%s" |
| 256 | + } |
| 257 | + }`, authorizedPath, otherAuthorizedPath), |
103 | 258 | }) |
104 | 259 | } |
0 commit comments