diff --git a/aws/resource_service_principal_role_test.go b/aws/resource_service_principal_role_test.go index 071b5da036..260ee0e3b3 100644 --- a/aws/resource_service_principal_role_test.go +++ b/aws/resource_service_principal_role_test.go @@ -1,9 +1,10 @@ package aws import ( - "github.com/databrickslabs/terraform-provider-databricks/common" "testing" + "github.com/databrickslabs/terraform-provider-databricks/common" + "github.com/databrickslabs/terraform-provider-databricks/scim" "github.com/databrickslabs/terraform-provider-databricks/qa" diff --git a/catalog/resource_external_location.go b/catalog/resource_external_location.go index a9105d7db0..930f375107 100644 --- a/catalog/resource_external_location.go +++ b/catalog/resource_external_location.go @@ -18,13 +18,13 @@ func NewExternalLocationsAPI(ctx context.Context, m interface{}) ExternalLocatio } type ExternalLocationInfo struct { - Name string `json:"name" tf:"force_new"` - URL string `json:"url"` - CredentialName string `json:"credential_name"` - Comment string `json:"comment,omitempty"` - SkipValidation bool `json:"skip_validation,omitempty"` - Owner string `json:"owner,omitempty" tf:"computed"` - MetastoreID string `json:"metastore_id,omitempty" tf:"computed"` + Name string `json:"name" tf:"force_new"` + URL string `json:"url"` + CredentialName string `json:"credential_name"` + Comment string `json:"comment,omitempty"` + SkipValidation bool `json:"skip_validation,omitempty"` + Owner string `json:"owner,omitempty" tf:"computed"` + MetastoreID string `json:"metastore_id,omitempty" tf:"computed"` } func (a ExternalLocationsAPI) create(el *ExternalLocationInfo) error { diff --git a/commands/commands.go b/commands/commands.go index 7eba88d155..635c81f5eb 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -8,7 +8,6 @@ import ( "github.com/databrickslabs/terraform-provider-databricks/clusters" "github.com/databrickslabs/terraform-provider-databricks/common" - "github.com/databrickslabs/terraform-provider-databricks/internal" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -52,7 +51,7 @@ func (a CommandsAPI) Execute(clusterID, language, commandStr string) common.Comm Summary: fmt.Sprintf("Cluster %s has to be running or resizing, but is %s", clusterID, cluster.State), } } - commandStr = internal.TrimLeadingWhitespace(commandStr) + commandStr = TrimLeadingWhitespace(commandStr) log.Printf("[INFO] Executing %s command on %s:\n%s", language, clusterID, commandStr) context, err := a.createContext(language, clusterID) if err != nil { diff --git a/internal/utils.go b/commands/leading_whitespace.go similarity index 81% rename from internal/utils.go rename to commands/leading_whitespace.go index 5c89ed7099..ae93ef3d7c 100644 --- a/internal/utils.go +++ b/commands/leading_whitespace.go @@ -1,10 +1,11 @@ -package internal +package commands import ( "strings" ) -// TrimLeadingWhitespace removes leading whitespace +// TrimLeadingWhitespace removes leading whitespace, so that Python code blocks +// that are embedded into Go code still could be interpreted properly. func TrimLeadingWhitespace(commandStr string) (newCommand string) { lines := strings.Split(strings.ReplaceAll(commandStr, "\t", " "), "\n") leadingWhitespace := 1<<31 - 1 diff --git a/internal/utils_test.go b/commands/leading_whitespace_test.go similarity index 92% rename from internal/utils_test.go rename to commands/leading_whitespace_test.go index d9b436922b..b627871c78 100644 --- a/internal/utils_test.go +++ b/commands/leading_whitespace_test.go @@ -1,4 +1,4 @@ -package internal +package commands import ( "testing" diff --git a/common/client.go b/common/client.go index ab59843a23..86b4b71ac7 100644 --- a/common/client.go +++ b/common/client.go @@ -320,6 +320,8 @@ func (c *DatabricksClient) niceAuthError(message string) error { } info = ". " + strings.Join(infos, ". ") } + info = strings.TrimSuffix(info, ".") + message = strings.TrimSuffix(message, ".") docUrl := "https://registry.terraform.io/providers/databrickslabs/databricks/latest/docs#authentication" return fmt.Errorf("%s%s. Please check %s for details", message, info, docUrl) } diff --git a/common/http.go b/common/http.go index 74adac0778..e704adca23 100644 --- a/common/http.go +++ b/common/http.go @@ -6,7 +6,7 @@ import ( "encoding/json" "errors" "fmt" - "io/ioutil" + "io" "log" "net/http" "net/url" @@ -179,7 +179,7 @@ func (c *DatabricksClient) commonErrorClarity(resp *http.Response) *APIError { } func (c *DatabricksClient) parseError(resp *http.Response) APIError { - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return APIError{ Message: err.Error(), @@ -345,16 +345,21 @@ func (c *DatabricksClient) completeUrl(r *http.Request) error { return nil } +// scimPathVisitorFactory is a separate method for the sake of unit tests +func (c *DatabricksClient) scimVisitor(r *http.Request) error { + r.Header.Set("Content-Type", "application/scim+json; charset=utf-8") + if c.isAccountsClient() && c.AccountID != "" { + // until `/preview` is there for workspace scim, + // `/api/2.0` is added by completeUrl visitor + r.URL.Path = strings.ReplaceAll(r.URL.Path, "/api/2.0/preview", + fmt.Sprintf("/api/2.0/accounts/%s", c.AccountID)) + } + return nil +} + // Scim sets SCIM headers func (c *DatabricksClient) Scim(ctx context.Context, method, path string, request interface{}, response interface{}) error { - body, err := c.authenticatedQuery(ctx, method, path, request, c.completeUrl, func(r *http.Request) error { - r.Header.Set("Content-Type", "application/scim+json; charset=utf-8") - if c.isAccountsClient() && c.AccountID != "" { - // until `/preview` is there for workspace scim - r.URL.Path = strings.ReplaceAll(path, "/preview", fmt.Sprintf("/api/2.0/accounts/%s", c.AccountID)) - } - return nil - }) + body, err := c.authenticatedQuery(ctx, method, path, request, c.completeUrl, c.scimVisitor) if err != nil { return err } @@ -402,7 +407,9 @@ func (c *DatabricksClient) redactedDump(body []byte) (res string) { if len(body) == 0 { return } - + if body[0] != '{' { + return fmt.Sprintf("[non-JSON document of %d bytes]", len(body)) + } var requestMap map[string]interface{} err := json.Unmarshal(body, &requestMap) if err != nil { @@ -465,21 +472,21 @@ func (c *DatabricksClient) genericQuery(ctx context.Context, method, requestURL return nil, fmt.Errorf("DatabricksClient is not configured") } if err = c.rateLimiter.Wait(ctx); err != nil { - return nil, err + return nil, fmt.Errorf("rate limited: %w", err) } - requestBody, err := makeRequestBody(method, &requestURL, data, true) + requestBody, err := makeRequestBody(method, &requestURL, data) if err != nil { - return nil, err + return nil, fmt.Errorf("request marshal: %w", err) } request, err := http.NewRequestWithContext(ctx, method, requestURL, bytes.NewBuffer(requestBody)) if err != nil { - return nil, err + return nil, fmt.Errorf("new request: %w", err) } request.Header.Set("User-Agent", c.userAgent(ctx)) for _, requestVisitor := range visitors { err = requestVisitor(request) if err != nil { - return nil, err + return nil, fmt.Errorf("failed visitor: %w", err) } } headers := c.createDebugHeaders(request.Header, c.Host) @@ -488,78 +495,93 @@ func (c *DatabricksClient) genericQuery(ctx context.Context, method, requestURL r, err := retryablehttp.FromRequest(request) if err != nil { - return nil, err + return nil, err // no error invariants possible because of `makeRequestBody` } resp, err := c.httpClient.Do(r) // retryablehttp library now returns only wrapped errors var ae APIError if errors.As(err, &ae) { + // don't re-wrap, as upper layers may depend on handling common.APIError return nil, ae } if err != nil { - return nil, err + // i don't even know which errors in the real world would end up here. + // `retryablehttp` package nicely wraps _everything_ to `url.Error`. + return nil, fmt.Errorf("failed request: %w", err) } defer func() { if ferr := resp.Body.Close(); ferr != nil { - err = ferr + err = fmt.Errorf("failed to close: %w", ferr) } }() - body, err = ioutil.ReadAll(resp.Body) + body, err = io.ReadAll(resp.Body) if err != nil { - return nil, err + return nil, fmt.Errorf("response body: %w", err) } headers = c.createDebugHeaders(resp.Header, "") log.Printf("[DEBUG] %s %s %s <- %s %s", resp.Status, headers, c.redactedDump(body), method, strings.ReplaceAll(request.URL.Path, "\n", "")) return body, nil } -func makeRequestBody(method string, requestURL *string, data interface{}, marshalJSON bool) ([]byte, error) { +func makeQueryString(data interface{}) (string, error) { + inputVal := reflect.ValueOf(data) + inputType := reflect.TypeOf(data) + if inputType.Kind() == reflect.Map { + s := []string{} + keys := inputVal.MapKeys() + // sort map keys by their string repr, so that tests can be deterministic + sort.Slice(keys, func(i, j int) bool { + return keys[i].String() < keys[j].String() + }) + for _, k := range keys { + v := inputVal.MapIndex(k) + if v.IsZero() { + continue + } + s = append(s, fmt.Sprintf("%s=%s", + strings.Replace(url.QueryEscape(fmt.Sprintf("%v", k.Interface())), "+", "%20", -1), + strings.Replace(url.QueryEscape(fmt.Sprintf("%v", v.Interface())), "+", "%20", -1))) + } + return "?" + strings.Join(s, "&"), nil + } + if inputType.Kind() == reflect.Struct { + params, err := query.Values(data) + if err != nil { + return "", fmt.Errorf("cannot create query string: %w", err) + } + return "?" + params.Encode(), nil + } + return "", fmt.Errorf("unsupported query string data: %#v", data) +} + +func makeRequestBody(method string, requestURL *string, data interface{}) ([]byte, error) { var requestBody []byte if data == nil && (method == "DELETE" || method == "GET") { return requestBody, nil } if method == "GET" { - inputVal := reflect.ValueOf(data) - inputType := reflect.TypeOf(data) - switch inputType.Kind() { - case reflect.Map: - s := []string{} - keys := inputVal.MapKeys() - // sort map keys by their string repr, so that tests can be deterministic - sort.Slice(keys, func(i, j int) bool { - return keys[i].String() < keys[j].String() - }) - for _, k := range keys { - v := inputVal.MapIndex(k) - if v.IsZero() { - continue - } - s = append(s, fmt.Sprintf("%s=%s", - strings.Replace(url.QueryEscape(fmt.Sprintf("%v", k.Interface())), "+", "%20", -1), - strings.Replace(url.QueryEscape(fmt.Sprintf("%v", v.Interface())), "+", "%20", -1))) - } - *requestURL += "?" + strings.Join(s, "&") - case reflect.Struct: - params, err := query.Values(data) - if err != nil { - return nil, err - } - *requestURL += "?" + params.Encode() - default: - return requestBody, fmt.Errorf("unsupported request data: %#v", data) + qs, err := makeQueryString(data) + if err != nil { + return nil, err } - } else { - if marshalJSON { - bodyBytes, err := json.MarshalIndent(data, "", " ") - if err != nil { - return nil, err - } - requestBody = bodyBytes - } else { - requestBody = []byte(data.(string)) + *requestURL += qs + return requestBody, nil + } + if reader, ok := data.(io.Reader); ok { + raw, err := io.ReadAll(reader) + if err != nil { + return nil, fmt.Errorf("failed to read from reader: %w", err) } + return raw, nil + } + if str, ok := data.(string); ok { + return []byte(str), nil + } + bodyBytes, err := json.MarshalIndent(data, "", " ") + if err != nil { + return nil, fmt.Errorf("request marshal failure: %w", err) } - return requestBody, nil + return bodyBytes, nil } func onlyNBytes(j string, numBytes int) string { diff --git a/common/http_test.go b/common/http_test.go index c0a04e34a8..70e58c65e1 100644 --- a/common/http_test.go +++ b/common/http_test.go @@ -11,6 +11,7 @@ import ( "strings" "testing" + "github.com/hashicorp/go-retryablehttp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -77,8 +78,11 @@ func (errReader) Read(p []byte) (n int, err error) { return 0, fmt.Errorf("test error") } -func (errReader) Close() error { - return fmt.Errorf("test error") +func (i errReader) Close() error { + if int(i) > 100 { + return fmt.Errorf("test error") + } + return nil } func TestParseError_IO(t *testing.T) { @@ -163,6 +167,7 @@ func TestParseError_SCIM(t *testing.T) { "detail": "Detailed SCIM message", "status": "MALFUNCTION", "string_value": "sensitive", + "token_value": "sensitive", "content": "sensitive" }`))), }) @@ -334,19 +339,123 @@ func TestScim(t *testing.T) { require.NoError(t, err) } +func TestScimFailingQuery(t *testing.T) { + err := (&DatabricksClient{ + Host: "https://localhost", + Token: "..", + }).Scim(context.Background(), "GET", "/foo", nil, nil) + assert.EqualError(t, err, "DatabricksClient is not configured") +} + +func TestScimVisitorForAccounts(t *testing.T) { + request := &http.Request{ + Header: http.Header{}, + URL: &url.URL{ + Path: "/api/2.0/preview/scim/v2/Users/abc", + }, + } + err := (&DatabricksClient{ + Host: "https://accounts.everywhere", + AccountID: "uuid", + }).scimVisitor(request) + assert.NoError(t, err) + assert.Equal(t, "application/scim+json; charset=utf-8", request.Header.Get("Content-Type")) + assert.Equal(t, "/api/2.0/accounts/uuid/scim/v2/Users/abc", request.URL.Path) +} + func TestMakeRequestBody(t *testing.T) { type x struct { Scope string `json:"scope" url:"scope"` } requestURL := "/a/b/c" - _, err := makeRequestBody("GET", &requestURL, x{"test"}, true) + _, err := makeRequestBody("GET", &requestURL, x{"test"}) require.NoError(t, err) assert.Equal(t, "/a/b/c?scope=test", requestURL) - body, _ := makeRequestBody("POST", &requestURL, "abc", false) + body, _ := makeRequestBody("POST", &requestURL, "abc") assert.Equal(t, []byte("abc"), body) } +func TestMakeRequestBodyFromReader(t *testing.T) { + requestURL := "/a/b/c" + body, err := makeRequestBody("PUT", &requestURL, strings.NewReader("abc")) + require.NoError(t, err) + assert.Equal(t, []byte("abc"), body) +} + +func TestMakeRequestBodyReaderError(t *testing.T) { + requestURL := "/a/b/c" + _, err := makeRequestBody("POST", &requestURL, errReader(1)) + assert.EqualError(t, err, "failed to read from reader: test error") +} + +func TestMakeRequestBodyJsonError(t *testing.T) { + requestURL := "/a/b/c" + type x struct { + Foo chan string `json:"foo"` + } + _, err := makeRequestBody("POST", &requestURL, x{make(chan string)}) + assert.EqualError(t, err, "request marshal failure: json: unsupported type: chan string") +} + +type failingUrlEncode string + +func (fue failingUrlEncode) EncodeValues(key string, v *url.Values) error { + return fmt.Errorf(string(fue)) +} + +func TestMakeRequestBodyQueryFailingEncode(t *testing.T) { + requestURL := "/a/b/c" + type x struct { + Foo failingUrlEncode `url:"foo"` + } + _, err := makeRequestBody("GET", &requestURL, x{failingUrlEncode("always failing")}) + assert.EqualError(t, err, "cannot create query string: always failing") +} + +func TestMakeRequestBodyQueryUnsupported(t *testing.T) { + requestURL := "/a/b/c" + _, err := makeRequestBody("GET", &requestURL, true) + assert.EqualError(t, err, "unsupported query string data: true") +} + +func TestReaderBodyIsNotDumped(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc( + func(rw http.ResponseWriter, req *http.Request) { + raw, err := ioutil.ReadAll(req.Body) + assert.NoError(t, err) + assert.Equal(t, "abc", string(raw)) + rw.WriteHeader(200) + })) + defer server.Close() + client := &DatabricksClient{ + Host: server.URL + "/", + Token: "..", + InsecureSkipVerify: true, + DebugHeaders: true, + } + err := client.Configure() + assert.NoError(t, err) + ctx := context.Background() + err = client.Post(ctx, "/workspace/import-file", strings.NewReader("abc"), nil) + assert.NoError(t, err) +} + +func TestRedactedDumpMalformedJsonReturnsEmptyString(t *testing.T) { + client := &DatabricksClient{} + res := client.redactedDump([]byte("{..}")) + assert.Equal(t, "", res) +} + +func TestRedactedDumpOverridesMaxBytes(t *testing.T) { + client := &DatabricksClient{ + DebugTruncateBytes: 1300, + } + res := client.redactedDump([]byte(`{"foo":"` + strings.Repeat("x", 1500) + `"}`)) + assert.Len(t, res, 1319) + assert.True(t, strings.HasSuffix(res, "... (35 more bytes)")) +} + func TestMakeRequestBodyForMap(t *testing.T) { requestURL := "/a" _, err := makeRequestBody("GET", &requestURL, map[string]int{ @@ -358,7 +467,7 @@ func TestMakeRequestBodyForMap(t *testing.T) { "c": 5, "b": 6, "d": 7, - }, true) + }) require.NoError(t, err) assert.Equal(t, "/a?a=2&b=6&c=5&d=7&e=1&f=3&g=4", requestURL) } @@ -446,3 +555,90 @@ func TestClient_HandleErrors(t *testing.T) { }) } } + +func TestGenericQueryNotConfigured(t *testing.T) { + _, err := (&DatabricksClient{}).genericQuery(context.Background(), "GET", "/foo", true) + assert.EqualError(t, err, "DatabricksClient is not configured") +} + +func TestGenericQueryStoppedContext(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + client := &DatabricksClient{Host: "https://localhost", Token: ".."} + err := client.Configure() + assert.NoError(t, err) + _, err = client.genericQuery(ctx, "GET", "/foo", true) + assert.EqualError(t, err, "rate limited: context canceled") +} + +func TestGenericQueryMarshalError(t *testing.T) { + ctx := context.Background() + client := &DatabricksClient{Host: "https://localhost", Token: ".."} + err := client.Configure() + assert.NoError(t, err) + _, err = client.genericQuery(ctx, "POST", "/foo", errReader(1)) + assert.EqualError(t, err, "request marshal: failed to read from reader: test error") +} + +func TestGenericQueryInvalidMethod(t *testing.T) { + ctx := context.Background() + client := &DatabricksClient{Host: "https://localhost", Token: ".."} + err := client.Configure() + assert.NoError(t, err) + _, err = client.genericQuery(ctx, "😃", "/foo", strings.NewReader("abc")) + assert.EqualError(t, err, `new request: net/http: invalid method "😃"`) +} + +func TestGenericQueryFailingVisitor(t *testing.T) { + ctx := context.Background() + client := &DatabricksClient{Host: "https://localhost", Token: ".."} + err := client.Configure() + assert.NoError(t, err) + _, err = client.genericQuery(ctx, "POST", "/foo", strings.NewReader("abc"), + func(r *http.Request) error { + return fmt.Errorf("😃") + }) + assert.EqualError(t, err, `failed visitor: 😃`) +} + +func TestGenericQueryFailingRequest(t *testing.T) { + ctx := context.Background() + client := &DatabricksClient{Host: "https://localhost", Token: ".."} + err := client.Configure() + assert.NoError(t, err) + client.httpClient.RetryMax = 0 + client.httpClient.ErrorHandler = func(_ *http.Response, _ error, _ int) (*http.Response, error) { + return nil, fmt.Errorf("😃") + } + _, err = client.genericQuery(ctx, "PUT", "https://127.0.0.1/foo", strings.NewReader("abc")) + assert.EqualError(t, err, `failed request: 😃`) +} + +func TestGenericQueryFailingResponseBodyRead(t *testing.T) { + client, server := singleRequestServer(t, "GET", "/api/2.0/imaginary/endpoint", `{"a": "b"}`) + defer server.Close() + client.httpClient.RetryMax = 0 + client.httpClient.ResponseLogHook = func(_ retryablehttp.Logger, r *http.Response) { + r.Body = errReader(1) + } + ctx := context.Background() + _, err := client.genericQuery(ctx, "GET", fmt.Sprintf("%s/api/2.0/imaginary/endpoint", server.URL), nil) + assert.EqualError(t, err, "response body: test error") +} + +func TestGenericQueryFailingResponseBodyClose(t *testing.T) { + client, server := singleRequestServer(t, "GET", "/api/2.0/imaginary/endpoint", `{"a": "b"}`) + defer server.Close() + client.httpClient.RetryMax = 0 + client.httpClient.ResponseLogHook = func(_ retryablehttp.Logger, r *http.Response) { + r.Body = errReader(1000) + } + ctx := context.Background() + _, err := client.genericQuery(ctx, "GET", fmt.Sprintf("%s/api/2.0/imaginary/endpoint", server.URL), nil) + assert.EqualError(t, err, "failed to close: test error") +} + +func TestParseUnknownErrorStatusMalformed(t *testing.T) { + eb := (&DatabricksClient{}).parseUnknownError("malformed", nil, fmt.Errorf("test")) + assert.Equal(t, "UNKNOWN", eb.ErrorCode) +} diff --git a/exporter/importables_test.go b/exporter/importables_test.go index 83afabd617..7ece26c2e8 100644 --- a/exporter/importables_test.go +++ b/exporter/importables_test.go @@ -9,7 +9,7 @@ import ( "github.com/databrickslabs/terraform-provider-databricks/clusters" "github.com/databrickslabs/terraform-provider-databricks/common" - "github.com/databrickslabs/terraform-provider-databricks/internal" + "github.com/databrickslabs/terraform-provider-databricks/commands" "github.com/databrickslabs/terraform-provider-databricks/jobs" "github.com/databrickslabs/terraform-provider-databricks/permissions" "github.com/databrickslabs/terraform-provider-databricks/policies" @@ -598,7 +598,7 @@ func TestNotebookGeneration(t *testing.T) { assert.NoError(t, err) ic.generateHclForResources(nil) - assert.Equal(t, internal.TrimLeadingWhitespace(` + assert.Equal(t, commands.TrimLeadingWhitespace(` resource "databricks_notebook" "firstsecond" { source = "${path.module}/notebooks/First/Second.py" path = "/First/Second" @@ -625,7 +625,7 @@ func TestGlobalInitScriptGen(t *testing.T) { }) ic.generateHclForResources(nil) - assert.Equal(t, internal.TrimLeadingWhitespace(` + assert.Equal(t, commands.TrimLeadingWhitespace(` resource "databricks_global_init_script" "new_importing_things" { source = "${path.module}/files/new_importing_things.sh" name = "New: Importing ^ Things" @@ -655,7 +655,7 @@ func TestSecretGen(t *testing.T) { }) ic.generateHclForResources(nil) - assert.Equal(t, internal.TrimLeadingWhitespace(` + assert.Equal(t, commands.TrimLeadingWhitespace(` resource "databricks_secret" "a_b" { string_value = var.string_value_a_b scope = "a" @@ -688,7 +688,7 @@ func TestDbfsFileGen(t *testing.T) { }) ic.generateHclForResources(nil) - assert.Equal(t, internal.TrimLeadingWhitespace(` + assert.Equal(t, commands.TrimLeadingWhitespace(` resource "databricks_dbfs_file" "_a_0cc175b9c0f1b6a831c399e269772661" { source = "${path.module}/files/_a_0cc175b9c0f1b6a831c399e269772661" path = "a" diff --git a/internal/acceptance/acceptance.go b/internal/acceptance/acceptance.go index 732c6a5c01..3c6abe5810 100644 --- a/internal/acceptance/acceptance.go +++ b/internal/acceptance/acceptance.go @@ -8,12 +8,9 @@ import ( "strings" "testing" + "github.com/databrickslabs/terraform-provider-databricks/commands" "github.com/databrickslabs/terraform-provider-databricks/common" - "github.com/databrickslabs/terraform-provider-databricks/internal" "github.com/databrickslabs/terraform-provider-databricks/internal/compute" - - "github.com/databrickslabs/terraform-provider-databricks/qa" - "github.com/databrickslabs/terraform-provider-databricks/provider" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" @@ -75,7 +72,7 @@ func Test(t *testing.T, steps []Step, otherVars ...map[string]string) { stepConfig := "" for _, s := range steps { if s.Template != "" { - stepConfig = qa.EnvironmentTemplate(t, s.Template, vars) + stepConfig = EnvironmentTemplate(t, s.Template, vars) } ts = append(ts, resource.TestStep{ Config: stepConfig, @@ -152,7 +149,7 @@ func AccTest(t *testing.T, tc resource.TestCase) { if s.Config != "" { t.Logf("Test %s (%s) step %d config is:\n%s", t.Name(), cloudEnv, i, - internal.TrimLeadingWhitespace(s.Config)) + commands.TrimLeadingWhitespace(s.Config)) } } } diff --git a/internal/acceptance/environment_template.go b/internal/acceptance/environment_template.go new file mode 100644 index 0000000000..ae504b8b8b --- /dev/null +++ b/internal/acceptance/environment_template.go @@ -0,0 +1,62 @@ +package acceptance + +import ( + "errors" + "fmt" + "os" + "regexp" + "strings" + "testing" + + "github.com/databrickslabs/terraform-provider-databricks/commands" + "github.com/databrickslabs/terraform-provider-databricks/qa" +) + +// For writing a unit test to intercept the errors (t.Fatalf literally ends the test in failure) +func environmentTemplate(t *testing.T, template string, otherVars ...map[string]string) (string, error) { + vars := map[string]string{ + "RANDOM": qa.RandomName("t"), + } + if len(otherVars) > 1 { + return "", errors.New("cannot have more than one custom variable map") + } + if len(otherVars) == 1 { + for k, v := range otherVars[0] { + vars[k] = v + } + } + // pullAll otherVars + missing := 0 + var varType, varName, value string + r := regexp.MustCompile(`{(env|var).([^{}]*)}`) + for _, variableMatch := range r.FindAllStringSubmatch(template, -1) { + value = "" + varType = variableMatch[1] + varName = variableMatch[2] + switch varType { + case "env": + value = os.Getenv(varName) + case "var": + value = vars[varName] + } + if value == "" { + t.Logf("Missing %s %s variable.", varType, varName) + missing++ + continue + } + template = strings.ReplaceAll(template, `{`+varType+`.`+varName+`}`, value) + } + if missing > 0 { + return "", fmt.Errorf("please set %d variables and restart", missing) + } + return commands.TrimLeadingWhitespace(template), nil +} + +// EnvironmentTemplate asserts existence and fills in {env.VAR} & {var.RANDOM} placeholders in template +func EnvironmentTemplate(t *testing.T, template string, otherVars ...map[string]string) string { + resp, err := environmentTemplate(t, template, otherVars...) + if err != nil { + t.Skipf(err.Error()) + } + return resp +} \ No newline at end of file diff --git a/internal/acceptance/environment_template_test.go b/internal/acceptance/environment_template_test.go new file mode 100644 index 0000000000..73553032cc --- /dev/null +++ b/internal/acceptance/environment_template_test.go @@ -0,0 +1,44 @@ +package acceptance + +import ( + "fmt" + "os" + "testing" + + "github.com/databrickslabs/terraform-provider-databricks/common" + "github.com/databrickslabs/terraform-provider-databricks/qa" + "github.com/stretchr/testify/assert" +) + + +func TestEnvironmentTemplate(t *testing.T) { + defer common.CleanupEnvironment() + err := os.Setenv("USER", qa.RandomName()) + assert.NoError(t, err) + + res := EnvironmentTemplate(t, ` + resource "user" "me" { + name = "{env.USER}" + email = "{env.USER}+{var.RANDOM}@example.com" + }`) + assert.Equal(t, os.Getenv("USER"), qa.FirstKeyValue(t, res, "name")) +} + +func TestEnvironmentTemplate_other_vars(t *testing.T) { + otherVar := map[string]string{"TEST": "value"} + res := EnvironmentTemplate(t, ` + resource "user" "me" { + name = "{var.TEST}" + }`, otherVar) + assert.Equal(t, otherVar["TEST"], qa.FirstKeyValue(t, res, "name")) +} + +func TestEnvironmentTemplate_unset_env(t *testing.T) { + res, err := environmentTemplate(t, ` + resource "user" "me" { + name = "{env.USER}" + email = "{env.USER}+{var.RANDOM}@example.com" + }`) + assert.Equal(t, "", res) + assert.Errorf(t, err, fmt.Sprintf("please set %d variables and restart.", 2)) +} diff --git a/mws/resource_workspace_test.go b/mws/resource_workspace_test.go index d4cdfa08fd..82708f0952 100644 --- a/mws/resource_workspace_test.go +++ b/mws/resource_workspace_test.go @@ -1151,7 +1151,7 @@ func TestWorkspaceTokenWrongAuthCornerCase(t *testing.T) { wsApi := NewWorkspacesAPI(context.Background(), client) noAuth := "cannot authenticate parent client: authentication is not configured " + - "for provider.. Please check https://registry.terraform.io/providers/" + + "for provider. Please check https://registry.terraform.io/providers/" + "databrickslabs/databricks/latest/docs#authentication for details" assert.EqualError(t, CreateTokenIfNeeded(wsApi, r.Schema, d), noAuth, "create") assert.EqualError(t, EnsureTokenExistsIfNeeded(wsApi, r.Schema, d), noAuth, "ensure") diff --git a/provider/provider_test.go b/provider/provider_test.go index 64876589b7..842618938d 100644 --- a/provider/provider_test.go +++ b/provider/provider_test.go @@ -107,7 +107,7 @@ func TestConfig_TokenEnv(t *testing.T) { env: map[string]string{ "DATABRICKS_TOKEN": "x", }, - assertError: "authentication is not configured for provider.. Environment variables used: DATABRICKS_TOKEN", + assertError: "authentication is not configured for provider. Environment variables used: DATABRICKS_TOKEN", }.apply(t) } @@ -139,7 +139,7 @@ func TestConfig_UserPasswordEnv(t *testing.T) { "DATABRICKS_USERNAME": "x", "DATABRICKS_PASSWORD": "x", }, - assertError: "authentication is not configured for provider.." + + assertError: "authentication is not configured for provider." + " Environment variables used: DATABRICKS_USERNAME, DATABRICKS_PASSWORD", assertHost: "https://x", }.apply(t) diff --git a/qa/testing.go b/qa/testing.go index b86ec7ec19..56134dddf6 100644 --- a/qa/testing.go +++ b/qa/testing.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "encoding/json" - "errors" "fmt" "log" "math/rand" @@ -18,7 +17,6 @@ import ( "github.com/Azure/go-autorest/autorest/azure" "github.com/databrickslabs/terraform-provider-databricks/common" - "github.com/databrickslabs/terraform-provider-databricks/internal" "github.com/hashicorp/go-cty/cty" "github.com/hashicorp/hcl" @@ -512,55 +510,6 @@ func fixHCL(v interface{}) interface{} { } } -// For writing a unit test to intercept the errors (t.Fatalf literally ends the test in failure) -func environmentTemplate(t *testing.T, template string, otherVars ...map[string]string) (string, error) { - vars := map[string]string{ - "RANDOM": RandomName("t"), - } - if len(otherVars) > 1 { - return "", errors.New("cannot have more than one custom variable map") - } - if len(otherVars) == 1 { - for k, v := range otherVars[0] { - vars[k] = v - } - } - // pullAll otherVars - missing := 0 - var varType, varName, value string - r := regexp.MustCompile(`{(env|var).([^{}]*)}`) - for _, variableMatch := range r.FindAllStringSubmatch(template, -1) { - value = "" - varType = variableMatch[1] - varName = variableMatch[2] - switch varType { - case "env": - value = os.Getenv(varName) - case "var": - value = vars[varName] - } - if value == "" { - t.Logf("Missing %s %s variable.", varType, varName) - missing++ - continue - } - template = strings.ReplaceAll(template, `{`+varType+`.`+varName+`}`, value) - } - if missing > 0 { - return "", fmt.Errorf("please set %d variables and restart", missing) - } - return internal.TrimLeadingWhitespace(template), nil -} - -// EnvironmentTemplate asserts existence and fills in {env.VAR} & {var.RANDOM} placeholders in template -func EnvironmentTemplate(t *testing.T, template string, otherVars ...map[string]string) string { - resp, err := environmentTemplate(t, template, otherVars...) - if err != nil { - t.Skipf(err.Error()) - } - return resp -} - // FirstKeyValue gets it from HCL string func FirstKeyValue(t *testing.T, str, key string) string { r := regexp.MustCompile(key + `\s+=\s+"([^"]*)"`) diff --git a/qa/testing_test.go b/qa/testing_test.go index 2ff9ed491f..efc3630de8 100644 --- a/qa/testing_test.go +++ b/qa/testing_test.go @@ -3,7 +3,6 @@ package qa import ( "context" "fmt" - "os" "testing" "github.com/databrickslabs/terraform-provider-databricks/common" @@ -28,38 +27,6 @@ func TestRandomName(t *testing.T) { assert.Equal(t, 14, len(n)) } -func TestEnvironmentTemplate(t *testing.T) { - defer common.CleanupEnvironment() - err := os.Setenv("USER", RandomName()) - assert.NoError(t, err) - - res := EnvironmentTemplate(t, ` - resource "user" "me" { - name = "{env.USER}" - email = "{env.USER}+{var.RANDOM}@example.com" - }`) - assert.Equal(t, os.Getenv("USER"), FirstKeyValue(t, res, "name")) -} - -func TestEnvironmentTemplate_other_vars(t *testing.T) { - otherVar := map[string]string{"TEST": "value"} - res := EnvironmentTemplate(t, ` - resource "user" "me" { - name = "{var.TEST}" - }`, otherVar) - assert.Equal(t, otherVar["TEST"], FirstKeyValue(t, res, "name")) -} - -func TestEnvironmentTemplate_unset_env(t *testing.T) { - res, err := environmentTemplate(t, ` - resource "user" "me" { - name = "{env.USER}" - email = "{env.USER}+{var.RANDOM}@example.com" - }`) - assert.Equal(t, "", res) - assert.Errorf(t, err, fmt.Sprintf("please set %d variables and restart.", 2)) -} - func TestResourceFixture(t *testing.T) { client, server, err := HttpFixtureClient(t, []HTTPFixture{ { diff --git a/scim/acceptance/resource_user_test.go b/scim/acceptance/resource_user_test.go index 87a46df008..55dc78cefa 100644 --- a/scim/acceptance/resource_user_test.go +++ b/scim/acceptance/resource_user_test.go @@ -44,7 +44,7 @@ func TestAccUserResource(t *testing.T) { if _, ok := os.LookupEnv("CLOUD_ENV"); !ok { t.Skip("Acceptance tests skipped unless env 'CLOUD_ENV' is set") } - config := qa.EnvironmentTemplate(t, ` + config := acceptance.EnvironmentTemplate(t, ` resource "databricks_user" "first" { user_name = "eerste+{var.RANDOM}@example.com" display_name = "Eerste {var.RANDOM}" diff --git a/secrets/acceptance/secret_acl_test.go b/secrets/acceptance/secret_acl_test.go index 5e64f5dd59..2003856567 100644 --- a/secrets/acceptance/secret_acl_test.go +++ b/secrets/acceptance/secret_acl_test.go @@ -10,7 +10,6 @@ import ( "github.com/databrickslabs/terraform-provider-databricks/common" "github.com/databrickslabs/terraform-provider-databricks/internal/acceptance" - "github.com/databrickslabs/terraform-provider-databricks/qa" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/stretchr/testify/assert" @@ -24,7 +23,7 @@ func TestAccSecretAclResource(t *testing.T) { acceptance.AccTest(t, resource.TestCase{ Steps: []resource.TestStep{ { - Config: qa.EnvironmentTemplate(t, ` + Config: acceptance.EnvironmentTemplate(t, ` resource "databricks_group" "ds" { display_name = "data-scientists-{var.RANDOM}" } @@ -69,7 +68,7 @@ func TestAccSecretAclResourceDefaultPrincipal(t *testing.T) { acceptance.AccTest(t, resource.TestCase{ Steps: []resource.TestStep{ { - Config: qa.EnvironmentTemplate(t, ` + Config: acceptance.EnvironmentTemplate(t, ` resource "databricks_secret_scope" "app" { name = "app-{var.RANDOM}" initial_manage_principal = "users" diff --git a/secrets/acceptance/secret_test.go b/secrets/acceptance/secret_test.go index 26c2a812c3..c1205d650a 100644 --- a/secrets/acceptance/secret_test.go +++ b/secrets/acceptance/secret_test.go @@ -19,7 +19,7 @@ func TestAccSecretResource(t *testing.T) { if _, ok := os.LookupEnv("CLOUD_ENV"); !ok { t.Skip("Acceptance tests skipped unless env 'CLOUD_ENV' is set") } - config := qa.EnvironmentTemplate(t, ` + config := acceptance.EnvironmentTemplate(t, ` resource "databricks_secret_scope" "this" { name = "tf-scope-{var.RANDOM}" } diff --git a/storage/acceptance/adls_gen1_test.go b/storage/acceptance/adls_gen1_test.go index 55d3fe13a3..66e6831c05 100644 --- a/storage/acceptance/adls_gen1_test.go +++ b/storage/acceptance/adls_gen1_test.go @@ -22,7 +22,7 @@ func TestAzureAccAdlsGen1Mount_correctly_mounts(t *testing.T) { acceptance.AccTest(t, resource.TestCase{ Steps: []resource.TestStep{ { - Config: qa.EnvironmentTemplate(t, ` + Config: acceptance.EnvironmentTemplate(t, ` resource "databricks_secret_scope" "terraform" { name = "terraform-{var.RANDOM}" initial_manage_principal = "users" diff --git a/storage/acceptance/adls_gen2_test.go b/storage/acceptance/adls_gen2_test.go index 356579e49f..5a2c7efb9f 100644 --- a/storage/acceptance/adls_gen2_test.go +++ b/storage/acceptance/adls_gen2_test.go @@ -22,7 +22,7 @@ func TestAzureAccAdlsGen2Mount_correctly_mounts(t *testing.T) { acceptance.AccTest(t, resource.TestCase{ Steps: []resource.TestStep{ { - Config: qa.EnvironmentTemplate(t, ` + Config: acceptance.EnvironmentTemplate(t, ` resource "databricks_secret_scope" "terraform" { name = "terraform-{var.RANDOM}" initial_manage_principal = "users" diff --git a/storage/acceptance/aws_s3_mount_test.go b/storage/acceptance/aws_s3_mount_test.go index 1e334f4db2..660993986b 100644 --- a/storage/acceptance/aws_s3_mount_test.go +++ b/storage/acceptance/aws_s3_mount_test.go @@ -43,7 +43,7 @@ func TestAwsAccS3IamMount_WithCluster(t *testing.T) { if instanceProfilesAPI.IsRegistered(arn) { return false } - config := qa.EnvironmentTemplate(t, ` + config := acceptance.EnvironmentTemplate(t, ` resource "databricks_instance_profile" "this" { instance_profile_arn = "{env.TEST_EC2_INSTANCE_PROFILE}" } @@ -89,7 +89,7 @@ func TestAwsAccS3IamMount_NoClusterGiven(t *testing.T) { ctx := context.WithValue(context.Background(), common.Current, t.Name()) instanceProfilesAPI := aws.NewInstanceProfilesAPI(ctx, client) instanceProfilesAPI.Synchronized(arn, func() bool { - config := qa.EnvironmentTemplate(t, ` + config := acceptance.EnvironmentTemplate(t, ` resource "databricks_instance_profile" "this" { instance_profile_arn = "{env.TEST_EC2_INSTANCE_PROFILE}" } diff --git a/storage/acceptance/azure_blob_mount_test.go b/storage/acceptance/azure_blob_mount_test.go index a76e531d71..b0017ced2c 100644 --- a/storage/acceptance/azure_blob_mount_test.go +++ b/storage/acceptance/azure_blob_mount_test.go @@ -36,7 +36,7 @@ func TestAzureAccBlobMount_correctly_mounts(t *testing.T) { if _, ok := os.LookupEnv("CLOUD_ENV"); !ok { t.Skip("Acceptance tests skipped unless env 'CLOUD_ENV' is set") } - config := qa.EnvironmentTemplate(t, ` + config := acceptance.EnvironmentTemplate(t, ` resource "databricks_secret_scope" "terraform" { name = "terraform-{var.RANDOM}" initial_manage_principal = "users" diff --git a/storage/adls_gen1_mount_test.go b/storage/adls_gen1_mount_test.go index 75a868e1b3..f321f4904b 100644 --- a/storage/adls_gen1_mount_test.go +++ b/storage/adls_gen1_mount_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/databrickslabs/terraform-provider-databricks/clusters" + "github.com/databrickslabs/terraform-provider-databricks/commands" "github.com/databrickslabs/terraform-provider-databricks/common" - "github.com/databrickslabs/terraform-provider-databricks/internal" "github.com/databrickslabs/terraform-provider-databricks/qa" "github.com/stretchr/testify/assert" @@ -27,7 +27,7 @@ func TestResourceAdlsGen1Mount_Create(t *testing.T) { }, Resource: ResourceAzureAdlsGen1Mount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, "adl://test-adls.azuredatalakestore.net") diff --git a/storage/adls_gen2_mount_test.go b/storage/adls_gen2_mount_test.go index 34eb5dce0c..ea1c907f72 100644 --- a/storage/adls_gen2_mount_test.go +++ b/storage/adls_gen2_mount_test.go @@ -5,8 +5,8 @@ import ( "testing" "github.com/databrickslabs/terraform-provider-databricks/clusters" + "github.com/databrickslabs/terraform-provider-databricks/commands" "github.com/databrickslabs/terraform-provider-databricks/common" - "github.com/databrickslabs/terraform-provider-databricks/internal" "github.com/databrickslabs/terraform-provider-databricks/qa" "github.com/stretchr/testify/assert" @@ -27,7 +27,7 @@ func TestResourceAdlsGen2Mount_Create(t *testing.T) { }, Resource: ResourceAzureAdlsGen2Mount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, "abfss://e@test-adls-gen2.dfs.core.windows.net") diff --git a/storage/aws_s3_mount_test.go b/storage/aws_s3_mount_test.go index 7dda4a96cd..e7f29a05cd 100644 --- a/storage/aws_s3_mount_test.go +++ b/storage/aws_s3_mount_test.go @@ -6,7 +6,7 @@ import ( "github.com/databrickslabs/terraform-provider-databricks/clusters" "github.com/databrickslabs/terraform-provider-databricks/common" - "github.com/databrickslabs/terraform-provider-databricks/internal" + "github.com/databrickslabs/terraform-provider-databricks/commands" "github.com/databrickslabs/terraform-provider-databricks/qa" "github.com/stretchr/testify/assert" @@ -36,7 +36,7 @@ func TestResourceAwsS3MountCreate(t *testing.T) { }, Resource: ResourceAWSS3Mount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, testS3BucketPath) // bucketname @@ -102,7 +102,7 @@ func TestResourceAwsS3MountRead(t *testing.T) { }, Resource: ResourceAWSS3Mount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) assert.Contains(t, trunc, "dbutils.fs.mounts()") assert.Contains(t, trunc, `mount.mountPoint == "/mnt/this_mount"`) @@ -141,7 +141,7 @@ func TestResourceAwsS3MountRead_NotFound(t *testing.T) { }, Resource: ResourceAWSS3Mount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) return common.CommandResults{ ResultType: "error", @@ -176,7 +176,7 @@ func TestResourceAwsS3MountRead_Error(t *testing.T) { }, Resource: ResourceAWSS3Mount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) return common.CommandResults{ ResultType: "error", @@ -213,7 +213,7 @@ func TestResourceAwsS3MountDelete(t *testing.T) { }, Resource: ResourceAWSS3Mount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) assert.Contains(t, trunc, "/mnt/this_mount") assert.Contains(t, trunc, "dbutils.fs.unmount(mount_point)") diff --git a/storage/azure_blob_mount_test.go b/storage/azure_blob_mount_test.go index 9a0a102927..7c7400ae0a 100644 --- a/storage/azure_blob_mount_test.go +++ b/storage/azure_blob_mount_test.go @@ -6,7 +6,7 @@ import ( "github.com/databrickslabs/terraform-provider-databricks/clusters" "github.com/databrickslabs/terraform-provider-databricks/common" - "github.com/databrickslabs/terraform-provider-databricks/internal" + "github.com/databrickslabs/terraform-provider-databricks/commands" "github.com/databrickslabs/terraform-provider-databricks/qa" "github.com/stretchr/testify/assert" @@ -27,7 +27,7 @@ func TestResourceAzureBlobMountCreate(t *testing.T) { }, Resource: ResourceAzureBlobMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { @@ -105,7 +105,7 @@ func TestResourceAzureBlobMountRead(t *testing.T) { }, Resource: ResourceAzureBlobMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) assert.Contains(t, trunc, "dbutils.fs.mounts()") assert.Contains(t, trunc, `mount.mountPoint == "/mnt/e"`) @@ -145,7 +145,7 @@ func TestResourceAzureBlobMountRead_NotFound(t *testing.T) { }, Resource: ResourceAzureBlobMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) return common.CommandResults{ ResultType: "error", @@ -181,7 +181,7 @@ func TestResourceAzureBlobMountRead_Error(t *testing.T) { }, Resource: ResourceAzureBlobMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) return common.CommandResults{ ResultType: "error", @@ -219,7 +219,7 @@ func TestResourceAzureBlobMountDelete(t *testing.T) { }, Resource: ResourceAzureBlobMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) assert.Contains(t, trunc, "dbutils.fs.unmount(mount_point)") return common.CommandResults{ diff --git a/storage/mounts_test.go b/storage/mounts_test.go index 0c148da15f..acf3c62cda 100644 --- a/storage/mounts_test.go +++ b/storage/mounts_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/databrickslabs/terraform-provider-databricks/clusters" - "github.com/databrickslabs/terraform-provider-databricks/internal" + "github.com/databrickslabs/terraform-provider-databricks/commands" "github.com/databrickslabs/terraform-provider-databricks/qa" @@ -47,7 +47,7 @@ func testMountFuncHelper(t *testing.T, mountFunc func(mp MountPoint, mount Mount c.WithCommandMock(func(commandStr string) common.CommandResults { called = true - assert.Equal(t, internal.TrimLeadingWhitespace(expectedCommand), internal.TrimLeadingWhitespace(commandStr)) + assert.Equal(t, commands.TrimLeadingWhitespace(expectedCommand), commands.TrimLeadingWhitespace(commandStr)) return common.CommandResults{ ResultType: "text", Data: expectedCommandResp, diff --git a/storage/resource_mount_test.go b/storage/resource_mount_test.go index 2de9dd3948..8bd9c2e29f 100644 --- a/storage/resource_mount_test.go +++ b/storage/resource_mount_test.go @@ -6,7 +6,7 @@ import ( "github.com/databrickslabs/terraform-provider-databricks/clusters" "github.com/databrickslabs/terraform-provider-databricks/common" - "github.com/databrickslabs/terraform-provider-databricks/internal" + "github.com/databrickslabs/terraform-provider-databricks/commands" "github.com/databrickslabs/terraform-provider-databricks/qa" "github.com/Azure/go-autorest/autorest/azure" @@ -84,7 +84,7 @@ func TestResourceAwsS3MountGenericCreate(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, testS3BucketPath) // bucketname @@ -127,7 +127,7 @@ func TestResourceAwsS3MountGenericCreate_NoName(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, testS3BucketPath) // bucketname @@ -235,7 +235,7 @@ func TestResourceAwsS3MountGenericCreate_WithInstanceProfile(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, testS3BucketPath) // bucketname @@ -308,7 +308,7 @@ func TestResourceAwsS3MountGenericRead(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) assert.Contains(t, trunc, "dbutils.fs.mounts()") assert.Contains(t, trunc, `mount.mountPoint == "/mnt/this_mount"`) @@ -349,7 +349,7 @@ func TestResourceAwsS3MountGenericRead_NotFound(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) return common.CommandResults{ ResultType: "error", @@ -386,7 +386,7 @@ func TestResourceAwsS3MountGenericRead_Error(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) return common.CommandResults{ ResultType: "error", @@ -425,7 +425,7 @@ func TestResourceAwsS3MountDeleteGeneric(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) assert.Contains(t, trunc, "/mnt/this_mount") assert.Contains(t, trunc, "dbutils.fs.unmount(mount_point)") @@ -465,7 +465,7 @@ func TestResourceAdlsGen1MountGeneric_Create(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, "adl://test-adls.azuredatalakestore.net") @@ -509,7 +509,7 @@ func TestResourceAdlsGen1MountGeneric_Create_ResourceID(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, "adl://gen1.azuredatalakestore.net") @@ -630,7 +630,7 @@ func TestResourceAdlsGen2MountGeneric_Create(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, "abfss://e@test-adls-gen2.dfs.core.windows.net") @@ -675,7 +675,7 @@ func TestResourceAdlsGen2MountGeneric_Create_ResourceID(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, "abfss://e@test-adls-gen2.dfs.core.windows.net") @@ -718,7 +718,7 @@ func TestResourceAdlsGen2MountGeneric_Create_NoTenantID_SPN(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, "abfss://e@test-adls-gen2.dfs.core.windows.net") @@ -764,7 +764,7 @@ func TestResourceAdlsGen2MountGeneric_Create_NoTenantID_CLI(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, "abfss://e@test-adls-gen2.dfs.core.windows.net") @@ -853,7 +853,7 @@ func TestResourceAzureBlobMountCreateGeneric(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { @@ -899,7 +899,7 @@ func TestResourceAzureBlobMountCreateGeneric_SAS(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { @@ -945,7 +945,7 @@ func TestResourceAzureBlobMountCreateGeneric_Resource_ID(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { @@ -1075,7 +1075,7 @@ func TestResourceAzureBlobMountGeneric_Read(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) assert.Contains(t, trunc, "dbutils.fs.mounts()") assert.Contains(t, trunc, `mount.mountPoint == "/mnt/e"`) @@ -1117,7 +1117,7 @@ func TestResourceAzureBlobMountGenericRead_NotFound(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) return common.CommandResults{ ResultType: "error", @@ -1155,7 +1155,7 @@ func TestResourceAzureBlobMountGenericRead_Error(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) return common.CommandResults{ ResultType: "error", @@ -1195,7 +1195,7 @@ func TestResourceAzureBlobMountGenericDelete(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) assert.Contains(t, trunc, "dbutils.fs.unmount(mount_point)") return common.CommandResults{ @@ -1265,7 +1265,7 @@ func TestResourceGcsMountGenericCreate_WithCluster(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, testGcsBucketPath) // bucketname @@ -1309,7 +1309,7 @@ func TestResourceGcsMountGenericCreate_WithCluster_NoName(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, testGcsBucketPath) // bucketname @@ -1414,7 +1414,7 @@ func TestResourceGcsMountGenericCreate_WithServiceAccount(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, testGcsBucketPath) // bucketname @@ -1472,7 +1472,7 @@ func TestResourceMountGenericCreate_WithUriAndOpts(t *testing.T) { }, Resource: ResourceMount(), CommandMock: func(commandStr string) common.CommandResults { - trunc := internal.TrimLeadingWhitespace(commandStr) + trunc := commands.TrimLeadingWhitespace(commandStr) t.Logf("Received command:\n%s", trunc) if strings.HasPrefix(trunc, "def safe_mount") { assert.Contains(t, trunc, abfssPath) // URI