Skip to content

Commit afcc0b2

Browse files
Fix: SemanticLayerCredentialValidator erroring when optional fields with defaults are omitted (#650) (#651)
* Don't validate adapter_type if not provided * Changie
1 parent 7d3130b commit afcc0b2

3 files changed

Lines changed: 105 additions & 1 deletion

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
kind: Fixes
2+
body: Don't validate adapter_type if not provided
3+
time: 2026-03-31T08:37:57.064215+03:00

pkg/framework/objects/databricks_credential/resource_acceptance_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ func testCheckSchemaIsProvided() string {
142142
catalog = "test"
143143
target_name = "test"
144144
token = "test"
145+
schema = ""
145146
adapter_type = "databricks"
146147
}
147148
`
@@ -343,6 +344,106 @@ func verifyDatabricksBugIsFixed(t *testing.T, tracker *testhelpers.APICallTracke
343344
}
344345
}
345346

347+
// TestDatabricksCredential_AdapterTypeOptional is a regression test for
348+
// https://github.com/dbt-labs/terraform-provider-dbtcloud/issues/650.
349+
// The old implementation had a SemanticLayerCredentialValidator on adapter_type
350+
// that fired against the raw config value (before defaults are applied), causing
351+
// an error when the field was omitted despite being Optional with a default.
352+
func TestDatabricksCredential_AdapterTypeOptional(t *testing.T) {
353+
originalTFAcc := os.Getenv("TF_ACC")
354+
os.Setenv("TF_ACC", "1")
355+
defer func() {
356+
if originalTFAcc == "" {
357+
os.Unsetenv("TF_ACC")
358+
} else {
359+
os.Setenv("TF_ACC", originalTFAcc)
360+
}
361+
}()
362+
363+
accountID, projectID, credentialID := int64(12345), 67890, 333
364+
tracker := &testhelpers.APICallTracker{}
365+
366+
handlers := databricksCredentialMockHandlers(accountID, projectID, credentialID, tracker)
367+
srv := testhelpers.SetupMockServer(t, handlers)
368+
defer srv.Close()
369+
370+
providerConfig := fmt.Sprintf(`
371+
provider "dbtcloud" {
372+
host_url = "%s"
373+
token = "dummy-token"
374+
account_id = %d
375+
}`, srv.URL, accountID)
376+
377+
// adapter_type is intentionally omitted — the old validator would error here
378+
configWithoutAdapterType := providerConfig + fmt.Sprintf(`
379+
resource "dbtcloud_databricks_credential" "test" {
380+
project_id = %d
381+
token = "test_token"
382+
schema = "test_schema"
383+
}`, projectID)
384+
385+
resource.Test(t, resource.TestCase{
386+
IsUnitTest: true,
387+
ProtoV6ProviderFactories: acctest_helper.TestAccProtoV6ProviderFactories,
388+
Steps: []resource.TestStep{
389+
{
390+
Config: configWithoutAdapterType,
391+
Check: resource.ComposeTestCheckFunc(
392+
resource.TestCheckResourceAttr("dbtcloud_databricks_credential.test", "adapter_type", "databricks"),
393+
),
394+
},
395+
},
396+
})
397+
}
398+
399+
func databricksCredentialMockHandlers(accountID int64, projectID, credentialID int, tracker *testhelpers.APICallTracker) map[string]testhelpers.MockEndpointHandler {
400+
handlers := make(map[string]testhelpers.MockEndpointHandler)
401+
402+
response := func() dbt_cloud.DatabricksCredentialResponse {
403+
return dbt_cloud.DatabricksCredentialResponse{
404+
Data: dbt_cloud.DatabricksCredential{
405+
ID: &credentialID,
406+
Account_Id: accountID,
407+
Project_Id: projectID,
408+
Type: "adapter",
409+
State: 1,
410+
Threads: 4,
411+
Target_Name: "default",
412+
AdapterVersion: "databricks_v0",
413+
Credential_Details: dbt_cloud.AdapterCredentialDetails{
414+
Fields: map[string]dbt_cloud.AdapterCredentialField{
415+
"schema": {Value: "test_schema"},
416+
"token": {Value: "test_token"},
417+
},
418+
},
419+
UnencryptedCredentialDetails: dbt_cloud.DatabricksUnencryptedCredentialDetails{
420+
Schema: "test_schema",
421+
TargetName: "default",
422+
Threads: 4,
423+
Token: "test_token",
424+
},
425+
},
426+
Status: dbt_cloud.ResponseStatus{Code: 200, Is_Success: true},
427+
}
428+
}
429+
430+
createPath := fmt.Sprintf("POST /v3/accounts/%d/projects/%d/credentials/", accountID, projectID)
431+
handlers[createPath] = func(r *http.Request) (int, interface{}, error) {
432+
tracker.CreateCount++
433+
resp := response()
434+
resp.Status.Code = 201
435+
return http.StatusCreated, resp, nil
436+
}
437+
438+
readPath := fmt.Sprintf("GET /v3/accounts/%d/projects/%d/credentials/%d/", accountID, projectID, credentialID)
439+
handlers[readPath] = func(r *http.Request) (int, interface{}, error) {
440+
tracker.ReadCount++
441+
return http.StatusOK, response(), nil
442+
}
443+
444+
return handlers
445+
}
446+
346447
func updateDatabricksCredentialHandlers(handlers map[string]testhelpers.MockEndpointHandler, accountID int64, projectID, credentialID int, tracker *testhelpers.APICallTracker) {
347448
currentSchema := "test_schema"
348449

pkg/helper/sl_cred_validator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func (v SemanticLayerCredentialValidator) MarkdownDescription(ctx context.Contex
2222

2323
func (v SemanticLayerCredentialValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) {
2424

25-
if req.ConfigValue.IsUnknown() {
25+
if req.ConfigValue.IsUnknown() || req.ConfigValue.IsNull() {
2626
return
2727
}
2828

0 commit comments

Comments
 (0)