| // Copyright (c) HashiCorp, Inc. |
| // SPDX-License-Identifier: MPL-2.0 |
| package provider_test |
| |
| import ( |
| "context" |
| "errors" |
| "os" |
| "testing" |
| |
| "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" |
| "github.com/hashicorp/terraform-provider-google-beta/google-beta/provider" |
| "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" |
| transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" |
| ) |
| |
| func TestProvider_ValidateCredentials(t *testing.T) { |
| cases := map[string]struct { |
| ConfigValue func(t *testing.T) interface{} |
| ValueNotProvided bool |
| ExpectedWarnings []string |
| ExpectedErrors []error |
| }{ |
| "configuring credentials as a path to a credentials JSON file is valid": { |
| ConfigValue: func(t *testing.T) interface{} { |
| return transport_tpg.TestFakeCredentialsPath // Path to a test fixture |
| }, |
| }, |
| "configuring credentials as a path to a non-existant file is NOT valid": { |
| ConfigValue: func(t *testing.T) interface{} { |
| return "./this/path/doesnt/exist.json" // Doesn't exist |
| }, |
| ExpectedErrors: []error{ |
| // As the file doesn't exist, so the function attempts to parse it as a JSON |
| errors.New("JSON credentials are not valid: invalid character '.' looking for beginning of value"), |
| }, |
| }, |
| "configuring credentials as a credentials JSON string is valid": { |
| ConfigValue: func(t *testing.T) interface{} { |
| contents, err := os.ReadFile(transport_tpg.TestFakeCredentialsPath) |
| if err != nil { |
| t.Fatalf("Unexpected error: %s", err) |
| } |
| return string(contents) |
| }, |
| }, |
| "configuring credentials as an empty string is not valid": { |
| ConfigValue: func(t *testing.T) interface{} { |
| return "" |
| }, |
| ExpectedErrors: []error{ |
| errors.New("expected a non-empty string"), |
| }, |
| }, |
| "leaving credentials unconfigured is valid": { |
| ValueNotProvided: true, |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| var configValue interface{} |
| if !tc.ValueNotProvided { |
| configValue = tc.ConfigValue(t) |
| } |
| |
| // Act |
| // Note: second argument is currently unused by the function but is necessary to fulfill the SchemaValidateFunc type's function signature |
| ws, es := provider.ValidateCredentials(configValue, "") |
| |
| // Assert |
| if len(ws) != len(tc.ExpectedWarnings) { |
| t.Fatalf("Expected %d warnings, got %d: %v", len(tc.ExpectedWarnings), len(ws), ws) |
| } |
| if len(es) != len(tc.ExpectedErrors) { |
| t.Fatalf("Expected %d errors, got %d: %v", len(tc.ExpectedErrors), len(es), es) |
| } |
| |
| if len(tc.ExpectedErrors) > 0 && len(es) > 0 { |
| if es[0].Error() != tc.ExpectedErrors[0].Error() { |
| t.Fatalf("Expected first error to be \"%s\", got \"%s\"", tc.ExpectedErrors[0], es[0]) |
| } |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ValidateEmptyStrings(t *testing.T) { |
| cases := map[string]struct { |
| ConfigValue interface{} |
| ValueNotProvided bool |
| ExpectedWarnings []string |
| ExpectedErrors []error |
| }{ |
| "non-empty strings are valid": { |
| ConfigValue: "foobar", |
| }, |
| "unconfigured values are valid": { |
| ValueNotProvided: true, |
| }, |
| "empty strings are not valid": { |
| ConfigValue: "", |
| ExpectedErrors: []error{ |
| errors.New("expected a non-empty string"), |
| }, |
| }, |
| } |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| var configValue interface{} |
| if !tc.ValueNotProvided { |
| configValue = tc.ConfigValue |
| } |
| |
| // Act |
| // Note: second argument is currently unused by the function but is necessary to fulfill the SchemaValidateFunc type's function signature |
| ws, es := provider.ValidateEmptyStrings(configValue, "") |
| |
| // Assert |
| if len(ws) != len(tc.ExpectedWarnings) { |
| t.Fatalf("Expected %d warnings, got %d: %v", len(tc.ExpectedWarnings), len(ws), ws) |
| } |
| if len(es) != len(tc.ExpectedErrors) { |
| t.Fatalf("Expected %d errors, got %d: %v", len(tc.ExpectedErrors), len(es), es) |
| } |
| |
| if len(tc.ExpectedErrors) > 0 && len(es) > 0 { |
| if es[0].Error() != tc.ExpectedErrors[0].Error() { |
| t.Fatalf("Expected first error to be \"%s\", got \"%s\"", tc.ExpectedErrors[0], es[0]) |
| } |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_credentials(t *testing.T) { |
| |
| const pathToMissingFile string = "./this/path/doesnt/exist.json" // Doesn't exist |
| |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectError bool |
| ExpectFieldUnset bool |
| ExpectedSchemaValue string |
| ExpectedConfigValue string |
| }{ |
| "credentials can be configured as a path to a credentials JSON file": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{}, |
| ExpectedSchemaValue: transport_tpg.TestFakeCredentialsPath, |
| ExpectedConfigValue: transport_tpg.TestFakeCredentialsPath, |
| }, |
| "configuring credentials as a path to a non-existant file results in an error": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": pathToMissingFile, |
| }, |
| ExpectError: true, |
| ExpectedSchemaValue: pathToMissingFile, |
| ExpectedConfigValue: pathToMissingFile, |
| }, |
| "credentials set in the config are not overridden by environment variables": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": acctest.GenerateFakeCredentialsJson("test"), |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_CREDENTIALS": acctest.GenerateFakeCredentialsJson("GOOGLE_CREDENTIALS"), |
| "GOOGLE_CLOUD_KEYFILE_JSON": acctest.GenerateFakeCredentialsJson("GOOGLE_CLOUD_KEYFILE_JSON"), |
| "GCLOUD_KEYFILE_JSON": acctest.GenerateFakeCredentialsJson("GCLOUD_KEYFILE_JSON"), |
| "GOOGLE_APPLICATION_CREDENTIALS": acctest.GenerateFakeCredentialsJson("GOOGLE_APPLICATION_CREDENTIALS"), |
| }, |
| ExpectedSchemaValue: acctest.GenerateFakeCredentialsJson("test"), |
| ExpectedConfigValue: acctest.GenerateFakeCredentialsJson("test"), |
| }, |
| "when credentials is unset in the config, environment variables are used: GOOGLE_CREDENTIALS used first": { |
| EnvVariables: map[string]string{ |
| "GOOGLE_CREDENTIALS": acctest.GenerateFakeCredentialsJson("GOOGLE_CREDENTIALS"), |
| "GOOGLE_CLOUD_KEYFILE_JSON": acctest.GenerateFakeCredentialsJson("GOOGLE_CLOUD_KEYFILE_JSON"), |
| "GCLOUD_KEYFILE_JSON": acctest.GenerateFakeCredentialsJson("GCLOUD_KEYFILE_JSON"), |
| "GOOGLE_APPLICATION_CREDENTIALS": acctest.GenerateFakeCredentialsJson("GOOGLE_APPLICATION_CREDENTIALS"), |
| }, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: acctest.GenerateFakeCredentialsJson("GOOGLE_CREDENTIALS"), |
| }, |
| "when credentials is unset in the config, environment variables are used: GOOGLE_CLOUD_KEYFILE_JSON used second": { |
| EnvVariables: map[string]string{ |
| // GOOGLE_CREDENTIALS not set |
| "GOOGLE_CLOUD_KEYFILE_JSON": acctest.GenerateFakeCredentialsJson("GOOGLE_CLOUD_KEYFILE_JSON"), |
| "GCLOUD_KEYFILE_JSON": acctest.GenerateFakeCredentialsJson("GCLOUD_KEYFILE_JSON"), |
| "GOOGLE_APPLICATION_CREDENTIALS": acctest.GenerateFakeCredentialsJson("GOOGLE_APPLICATION_CREDENTIALS"), |
| }, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: acctest.GenerateFakeCredentialsJson("GOOGLE_CLOUD_KEYFILE_JSON"), |
| }, |
| "when credentials is unset in the config, environment variables are used: GCLOUD_KEYFILE_JSON used third": { |
| EnvVariables: map[string]string{ |
| // GOOGLE_CREDENTIALS not set |
| // GOOGLE_CLOUD_KEYFILE_JSON not set |
| "GCLOUD_KEYFILE_JSON": acctest.GenerateFakeCredentialsJson("GCLOUD_KEYFILE_JSON"), |
| "GOOGLE_APPLICATION_CREDENTIALS": acctest.GenerateFakeCredentialsJson("GOOGLE_APPLICATION_CREDENTIALS"), |
| }, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: acctest.GenerateFakeCredentialsJson("GCLOUD_KEYFILE_JSON"), |
| }, |
| "when credentials is unset in the config (and access_token unset), GOOGLE_APPLICATION_CREDENTIALS is used for auth but not to set values in the config": { |
| EnvVariables: map[string]string{ |
| "GOOGLE_APPLICATION_CREDENTIALS": transport_tpg.TestFakeCredentialsPath, // needs to be a path to a file when used |
| }, |
| ExpectFieldUnset: true, |
| ExpectedSchemaValue: "", |
| }, |
| // Handling empty strings in config |
| "when credentials is set to an empty string in the config (and access_token unset), GOOGLE_APPLICATION_CREDENTIALS is used": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": "", |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_APPLICATION_CREDENTIALS": transport_tpg.TestFakeCredentialsPath, // needs to be a path to a file when used |
| }, |
| ExpectFieldUnset: true, |
| ExpectedSchemaValue: "", |
| }, |
| // Error states |
| // NOTE: these tests can't run in Cloud Build due to ADC locating credentials despite `GOOGLE_APPLICATION_CREDENTIALS` being unset |
| // See https://cloud.google.com/docs/authentication/application-default-credentials#search_order |
| // Also, when running these tests locally you need to run `gcloud auth application-default revoke` to ensure your machine isn't supplying ADCs |
| // "error returned if credentials is set as an empty string and GOOGLE_APPLICATION_CREDENTIALS is unset": { |
| // ConfigValues: map[string]interface{}{ |
| // "credentials": "", |
| // }, |
| // EnvVariables: map[string]string{ |
| // "GOOGLE_APPLICATION_CREDENTIALS": "", |
| // }, |
| // ExpectError: true, |
| // }, |
| // "error returned if neither credentials nor access_token set in the provider config, and GOOGLE_APPLICATION_CREDENTIALS is unset": { |
| // EnvVariables: map[string]string{ |
| // "GOOGLE_APPLICATION_CREDENTIALS": "", |
| // }, |
| // ExpectError: true, |
| // }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("credentials") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected credentials value set in provider config data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected credentials value to not be set in provider config data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| v, ok := d.GetOk("credentials") |
| val := v.(string) |
| if ok && tc.ExpectFieldUnset { |
| t.Fatal("expected credentials value to be unset in provider config data") |
| } |
| if v != tc.ExpectedSchemaValue { |
| t.Fatalf("expected credentials value set in provider config data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if config.Credentials != tc.ExpectedConfigValue { |
| t.Fatalf("expected credentials value set in Config struct to be to be %s, got %s", tc.ExpectedConfigValue, config.Credentials) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_accessToken(t *testing.T) { |
| |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectedSchemaValue string |
| ExpectedConfigValue string |
| ExpectError bool |
| ExpectFieldUnset bool |
| }{ |
| "access_token configured in the provider can be invalid without resulting in errors": { |
| ConfigValues: map[string]interface{}{ |
| "access_token": "This is not a valid token string", |
| }, |
| EnvVariables: map[string]string{}, |
| ExpectedSchemaValue: "This is not a valid token string", |
| ExpectedConfigValue: "This is not a valid token string", |
| }, |
| "access_token set in the provider config is not overridden by environment variables": { |
| ConfigValues: map[string]interface{}{ |
| "access_token": "value-from-config", |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_OAUTH_ACCESS_TOKEN": "value-from-env", |
| }, |
| ExpectedSchemaValue: "value-from-config", |
| ExpectedConfigValue: "value-from-config", |
| }, |
| "when access_token is unset in the config, the GOOGLE_OAUTH_ACCESS_TOKEN environment variable is used": { |
| EnvVariables: map[string]string{ |
| "GOOGLE_OAUTH_ACCESS_TOKEN": "value-from-GOOGLE_OAUTH_ACCESS_TOKEN", |
| }, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "value-from-GOOGLE_OAUTH_ACCESS_TOKEN", |
| }, |
| "when no access_token values are provided via config or environment variables there's no error": { |
| ConfigValues: map[string]interface{}{ |
| // access_token unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "", |
| }, |
| // Handle empty strings in config |
| "when access_token is set as an empty string the field is treated as if it's unset, without error": { |
| ConfigValues: map[string]interface{}{ |
| "access_token": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "", |
| }, |
| "when access_token is set as an empty string in the config, an environment variable is used": { |
| ConfigValues: map[string]interface{}{ |
| "access_token": "", |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_OAUTH_ACCESS_TOKEN": "value-from-GOOGLE_OAUTH_ACCESS_TOKEN", |
| }, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "value-from-GOOGLE_OAUTH_ACCESS_TOKEN", |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("access_token") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected access_token value set in provider config data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected access_token value to not be set in provider config data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| v, ok := d.GetOk("access_token") |
| val := v.(string) |
| if ok && tc.ExpectFieldUnset { |
| t.Fatal("expected access_token value to be unset in provider config data") |
| } |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected access_token value set in provider config data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if config.AccessToken != tc.ExpectedConfigValue { |
| t.Fatalf("expected access_token value set in Config struct to be to be %s, got %s", tc.ExpectedConfigValue, config.AccessToken) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_impersonateServiceAccount(t *testing.T) { |
| |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectedValue string |
| ExpectError bool |
| ExpectFieldUnset bool |
| }{ |
| "impersonate_service_account value set in the provider schema is not overridden by environment variables": { |
| ConfigValues: map[string]interface{}{ |
| "impersonate_service_account": "value-from-config@example.com", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_IMPERSONATE_SERVICE_ACCOUNT": "value-from-env@example.com", |
| }, |
| ExpectedValue: "value-from-config@example.com", |
| }, |
| "impersonate_service_account value can be set by environment variable": { |
| ConfigValues: map[string]interface{}{ |
| // impersonate_service_account unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_IMPERSONATE_SERVICE_ACCOUNT": "value-from-env@example.com", |
| }, |
| ExpectedValue: "value-from-env@example.com", |
| }, |
| "when no impersonate_service_account values are provided via config or environment variables, the field remains unset without error": { |
| ConfigValues: map[string]interface{}{ |
| // impersonate_service_account unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedValue: "", |
| }, |
| // Handling empty strings in config |
| "when impersonate_service_account is set as an empty string the field is treated as if it's unset, without error": { |
| ConfigValues: map[string]interface{}{ |
| "impersonate_service_account": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedValue: "", |
| }, |
| "when impersonate_service_account is set as an empty string in the config, an environment variable is used": { |
| ConfigValues: map[string]interface{}{ |
| "impersonate_service_account": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_IMPERSONATE_SERVICE_ACCOUNT": "value-from-env@example.com", |
| }, |
| ExpectedValue: "value-from-env@example.com", |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("impersonate_service_account") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedValue { |
| t.Fatalf("expected impersonate_service_account value set in provider config data to be %s, got %s", tc.ExpectedValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected impersonate_service_account value to not be set in provider config data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| v, ok := d.GetOk("impersonate_service_account") |
| val := v.(string) |
| if ok && tc.ExpectFieldUnset { |
| t.Fatal("expected impersonate_service_account value to be unset in provider config data") |
| } |
| if val != tc.ExpectedValue { |
| t.Fatalf("expected impersonate_service_account value set in provider config data to be %s, got %s", tc.ExpectedValue, val) |
| } |
| if config.ImpersonateServiceAccount != tc.ExpectedValue { |
| t.Fatalf("expected impersonate_service_account value in Config struct to be %s, got %s", tc.ExpectedValue, config.ImpersonateServiceAccount) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_impersonateServiceAccountDelegates(t *testing.T) { |
| |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectedValue []string |
| ExpectError bool |
| ExpectFieldUnset bool |
| }{ |
| "impersonate_service_account_delegates value can be set in the provider schema": { |
| ConfigValues: map[string]interface{}{ |
| "impersonate_service_account_delegates": []string{ |
| "projects/-/serviceAccounts/my-service-account-1@example.iam.gserviceaccount.com", |
| "projects/-/serviceAccounts/my-service-account-2@example.iam.gserviceaccount.com", |
| }, |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedValue: []string{ |
| "projects/-/serviceAccounts/my-service-account-1@example.iam.gserviceaccount.com", |
| "projects/-/serviceAccounts/my-service-account-2@example.iam.gserviceaccount.com", |
| }, |
| }, |
| // No environment variables can be used for impersonate_service_account_delegates |
| "when no impersonate_service_account_delegates value is provided via config, the field remains unset without error": { |
| ConfigValues: map[string]interface{}{ |
| // impersonate_service_account_delegates unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedValue: nil, |
| }, |
| // Handling empty values in config |
| "when impersonate_service_account_delegates is set as an empty array the field is treated as if it's unset, without error": { |
| ConfigValues: map[string]interface{}{ |
| "impersonate_service_account_delegates": []string{}, |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedValue: nil, |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("impersonate_service_account_delegates") |
| if ok { |
| val := v.([]interface{}) |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected impersonate_service_account_delegates value to not be set in provider config data, got %#v", val) |
| } |
| if len(val) != len(tc.ExpectedValue) { |
| t.Fatalf("expected impersonate_service_account_delegates value set in provider config data to be %#v, got %#v", tc.ExpectedValue, val) |
| } |
| for i := 0; i < len(val); i++ { |
| if val[i].(string) != tc.ExpectedValue[i] { |
| t.Fatalf("expected impersonate_service_account_delegates value set in provider config data to be %#v, got %#v", tc.ExpectedValue, val) |
| } |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| v, ok := d.GetOk("impersonate_service_account_delegates") |
| val := v.([]interface{}) |
| if ok && tc.ExpectFieldUnset { |
| t.Fatal("expected impersonate_service_account_delegates value to be unset in provider config data") |
| } |
| if len(val) != len(tc.ExpectedValue) { |
| t.Fatalf("expected impersonate_service_account_delegates value set in provider config data to be %#v, got %#v", tc.ExpectedValue, val) |
| } |
| for i := 0; i < len(val); i++ { |
| if val[i].(string) != tc.ExpectedValue[i] { |
| t.Fatalf("expected impersonate_service_account_delegates value set in provider config data to be %#v, got %#v", tc.ExpectedValue, val) |
| } |
| if config.ImpersonateServiceAccountDelegates[i] != tc.ExpectedValue[i] { |
| t.Fatalf("expected impersonate_service_account_delegates value set in Config struct to be to be %#v, got %#v", tc.ExpectedValue, config.ImpersonateServiceAccountDelegates) |
| } |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_project(t *testing.T) { |
| |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectedValue string |
| ExpectError bool |
| ExpectFieldUnset bool |
| }{ |
| "project value set in the provider schema is not overridden by environment variables": { |
| ConfigValues: map[string]interface{}{ |
| "project": "project-from-config", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_PROJECT": "project-from-GOOGLE_PROJECT", |
| "GOOGLE_CLOUD_PROJECT": "project-from-GOOGLE_CLOUD_PROJECT", |
| "GCLOUD_PROJECT": "project-from-GCLOUD_PROJECT", |
| "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", |
| }, |
| ExpectedValue: "project-from-config", |
| }, |
| "project value can be set by environment variable: GOOGLE_PROJECT is used first": { |
| ConfigValues: map[string]interface{}{ |
| // project unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_PROJECT": "project-from-GOOGLE_PROJECT", |
| "GOOGLE_CLOUD_PROJECT": "project-from-GOOGLE_CLOUD_PROJECT", |
| "GCLOUD_PROJECT": "project-from-GCLOUD_PROJECT", |
| "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", |
| }, |
| ExpectedValue: "project-from-GOOGLE_PROJECT", |
| }, |
| "project value can be set by environment variable: GOOGLE_CLOUD_PROJECT is used second": { |
| ConfigValues: map[string]interface{}{ |
| // project unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| // GOOGLE_PROJECT unset |
| "GOOGLE_CLOUD_PROJECT": "project-from-GOOGLE_CLOUD_PROJECT", |
| "GCLOUD_PROJECT": "project-from-GCLOUD_PROJECT", |
| "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", |
| }, |
| ExpectedValue: "project-from-GOOGLE_CLOUD_PROJECT", |
| }, |
| "project value can be set by environment variable: GCLOUD_PROJECT is used third": { |
| ConfigValues: map[string]interface{}{ |
| // project unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| // GOOGLE_PROJECT unset |
| // GOOGLE_CLOUD_PROJECT unset |
| "GCLOUD_PROJECT": "project-from-GCLOUD_PROJECT", |
| "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", |
| }, |
| ExpectedValue: "project-from-GCLOUD_PROJECT", |
| }, |
| "project value can be set by environment variable: CLOUDSDK_CORE_PROJECT is used fourth": { |
| ConfigValues: map[string]interface{}{ |
| // project unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| // GOOGLE_PROJECT unset |
| // GOOGLE_CLOUD_PROJECT unset |
| // GCLOUD_PROJECT unset |
| "CLOUDSDK_CORE_PROJECT": "project-from-CLOUDSDK_CORE_PROJECT", |
| }, |
| ExpectedValue: "project-from-CLOUDSDK_CORE_PROJECT", |
| }, |
| "when no project values are provided via config or environment variables, the field remains unset without error": { |
| ConfigValues: map[string]interface{}{ |
| // project unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedValue: "", |
| }, |
| // Handling empty strings in config |
| "when project is set as an empty string the field is treated as if it's unset, without error": { |
| ConfigValues: map[string]interface{}{ |
| "project": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedValue: "", |
| }, |
| "when project is set as an empty string an environment variable will be used": { |
| ConfigValues: map[string]interface{}{ |
| "project": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_PROJECT": "project-from-GOOGLE_PROJECT", |
| }, |
| ExpectedValue: "project-from-GOOGLE_PROJECT", |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("project") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedValue { |
| t.Fatalf("expected project value set in provider config data to be %s, got %s", tc.ExpectedValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected project value to not be set in provider config data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| v, ok := d.GetOk("project") |
| val := v.(string) |
| if ok && tc.ExpectFieldUnset { |
| t.Fatal("expected project value to be unset in provider config data") |
| } |
| if val != tc.ExpectedValue { |
| t.Fatalf("expected project value set in provider config data to be %s, got %s", tc.ExpectedValue, val) |
| } |
| if config.Project != tc.ExpectedValue { |
| t.Fatalf("expected project value set in Config struct to be to be %s, got %s", tc.ExpectedValue, config.Project) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_billingProject(t *testing.T) { |
| |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectedValue string |
| ExpectError bool |
| ExpectFieldUnset bool |
| }{ |
| "billing_project value set in the provider config is not overridden by ENVs": { |
| ConfigValues: map[string]interface{}{ |
| "billing_project": "billing-project-from-config", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_BILLING_PROJECT": "billing-project-from-env", |
| }, |
| ExpectedValue: "billing-project-from-config", |
| }, |
| "billing_project can be set by environment variable, when no value supplied via the config": { |
| ConfigValues: map[string]interface{}{ |
| // billing_project unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_BILLING_PROJECT": "billing-project-from-env", |
| }, |
| ExpectedValue: "billing-project-from-env", |
| }, |
| "when no billing_project values are provided via config or environment variables, the field remains unset without error": { |
| ConfigValues: map[string]interface{}{ |
| // billing_project unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedValue: "", |
| }, |
| // Handling empty strings in config |
| "when billing_project is set as an empty string the field is treated as if it's unset, without error": { |
| ConfigValues: map[string]interface{}{ |
| "billing_project": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectFieldUnset: true, |
| ExpectedValue: "", |
| }, |
| "when billing_project is set as an empty string an environment variable will be used": { |
| ConfigValues: map[string]interface{}{ |
| "billing_project": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_BILLING_PROJECT": "billing-project-from-env", |
| }, |
| ExpectedValue: "billing-project-from-env", |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("billing_project") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedValue { |
| t.Fatalf("expected billing_project value set in provider config data to be %s, got %s", tc.ExpectedValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected billing_project value to not be set in provider config data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| v, ok := d.GetOk("billing_project") |
| val := v.(string) |
| if ok && tc.ExpectFieldUnset { |
| t.Fatal("expected billing_project value to be unset in provider config data") |
| } |
| if val != tc.ExpectedValue { |
| t.Fatalf("expected billing_project value set in provider config data to be %s, got %s", tc.ExpectedValue, val) |
| } |
| if config.BillingProject != tc.ExpectedValue { |
| t.Fatalf("expected billing_project value set in Config struct to be to be %s, got %s", tc.ExpectedValue, config.BillingProject) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_region(t *testing.T) { |
| |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectedSchemaValue string |
| ExpectedConfigValue string |
| ExpectError bool |
| ExpectFieldUnset bool |
| }{ |
| "region value set in the provider config is not overridden by ENVs": { |
| ConfigValues: map[string]interface{}{ |
| "region": "region-from-config", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_REGION": "region-from-env", |
| }, |
| ExpectedSchemaValue: "region-from-config", |
| ExpectedConfigValue: "region-from-config", |
| }, |
| "region values can be supplied as a self link": { |
| ConfigValues: map[string]interface{}{ |
| "region": "https://www.googleapis.com/compute/v1/projects/my-project/regions/us-central1", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedSchemaValue: "https://www.googleapis.com/compute/v1/projects/my-project/regions/us-central1", |
| ExpectedConfigValue: "us-central1", |
| }, |
| "region value can be set by environment variable: GOOGLE_REGION is used": { |
| ConfigValues: map[string]interface{}{ |
| // region unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_REGION": "region-from-env", |
| }, |
| ExpectedSchemaValue: "region-from-env", |
| ExpectedConfigValue: "region-from-env", |
| }, |
| "when no region values are provided via config or environment variables, the field remains unset without error": { |
| ConfigValues: map[string]interface{}{ |
| // region unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "", |
| }, |
| // Handling empty strings in config |
| "when region is set as an empty string the field is treated as if it's unset, without error": { |
| ConfigValues: map[string]interface{}{ |
| "region": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectFieldUnset: true, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "", |
| }, |
| "when region is set as an empty string an environment variable will be used": { |
| ConfigValues: map[string]interface{}{ |
| "region": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_REGION": "region-from-env", |
| }, |
| ExpectedSchemaValue: "region-from-env", |
| ExpectedConfigValue: "region-from-env", |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("region") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected region value set in provider config data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected region value to not be set in provider config data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| v, ok := d.GetOk("region") |
| val := v.(string) |
| if ok && tc.ExpectFieldUnset { |
| t.Fatal("expected region value to be unset in provider config data") |
| } |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected region value set in provider config data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if config.Region != tc.ExpectedConfigValue { |
| t.Fatalf("expected region value set in Config struct to be to be %s, got %s", tc.ExpectedConfigValue, config.Region) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_zone(t *testing.T) { |
| |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectedSchemaValue string |
| ExpectedConfigValue string |
| ExpectError bool |
| ExpectFieldUnset bool |
| }{ |
| "zone value set in the provider config is not overridden by ENVs": { |
| ConfigValues: map[string]interface{}{ |
| "zone": "zone-from-config", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_ZONE": "zone-from-env", |
| }, |
| ExpectedSchemaValue: "zone-from-config", |
| ExpectedConfigValue: "zone-from-config", |
| }, |
| "does not shorten zone values when provided as a self link": { |
| ConfigValues: map[string]interface{}{ |
| "zone": "https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedSchemaValue: "https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1", |
| ExpectedConfigValue: "https://www.googleapis.com/compute/v1/projects/my-project/zones/us-central1", // Value is not shortened from URI to name |
| }, |
| "when multiple zone environment variables are provided, `GOOGLE_ZONE` is used first": { |
| ConfigValues: map[string]interface{}{ |
| // zone unset, |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_ZONE": "zone-from-GOOGLE_ZONE", |
| "GCLOUD_ZONE": "zone-from-GCLOUD_ZONE", |
| "CLOUDSDK_COMPUTE_ZONE": "zone-from-CLOUDSDK_COMPUTE_ZONE", |
| }, |
| ExpectedSchemaValue: "zone-from-GOOGLE_ZONE", |
| ExpectedConfigValue: "zone-from-GOOGLE_ZONE", |
| }, |
| "when multiple zone environment variables are provided, `GCLOUD_ZONE` is used second": { |
| ConfigValues: map[string]interface{}{ |
| // zone unset, |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| // GOOGLE_ZONE unset |
| "GCLOUD_ZONE": "zone-from-GCLOUD_ZONE", |
| "CLOUDSDK_COMPUTE_ZONE": "zone-from-CLOUDSDK_COMPUTE_ZONE", |
| }, |
| ExpectedSchemaValue: "zone-from-GCLOUD_ZONE", |
| ExpectedConfigValue: "zone-from-GCLOUD_ZONE", |
| }, |
| "when multiple zone environment variables are provided, `CLOUDSDK_COMPUTE_ZONE` is used third": { |
| ConfigValues: map[string]interface{}{ |
| // zone unset, |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| // GOOGLE_ZONE unset |
| // GCLOUD_ZONE unset |
| "CLOUDSDK_COMPUTE_ZONE": "zone-from-CLOUDSDK_COMPUTE_ZONE", |
| }, |
| ExpectedSchemaValue: "zone-from-CLOUDSDK_COMPUTE_ZONE", |
| ExpectedConfigValue: "zone-from-CLOUDSDK_COMPUTE_ZONE", |
| }, |
| "when no zone values are provided via config or environment variables, the field remains unset without error": { |
| ConfigValues: map[string]interface{}{ |
| // zone unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "", |
| }, |
| // Handling empty strings in config |
| "when zone is set as an empty string the field is treated as if it's unset, without error": { |
| ConfigValues: map[string]interface{}{ |
| "zone": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectFieldUnset: true, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "", |
| }, |
| "when zone is set as an empty string an environment variable will be used": { |
| ConfigValues: map[string]interface{}{ |
| "zone": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "GOOGLE_ZONE": "zone-from-env", |
| }, |
| ExpectedSchemaValue: "zone-from-env", |
| ExpectedConfigValue: "zone-from-env", |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("zone") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected zone value set in provider config data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected zone value to not be set in provider config data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| v, ok := d.GetOk("zone") |
| val := v.(string) |
| if ok && tc.ExpectFieldUnset { |
| t.Fatal("expected zone value to be unset in provider config data") |
| } |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected zone value set in provider config data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if config.Zone != tc.ExpectedConfigValue { |
| t.Fatalf("expected zone value set in Config struct to be to be %s, got %s", tc.ExpectedConfigValue, config.Zone) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_userProjectOverride(t *testing.T) { |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectedValue bool |
| ExpectFieldUnset bool |
| ExpectError bool |
| }{ |
| "user_project_override value set in the provider schema is not overridden by ENVs": { |
| ConfigValues: map[string]interface{}{ |
| "user_project_override": false, |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "USER_PROJECT_OVERRIDE": "true", |
| }, |
| ExpectedValue: false, |
| }, |
| "user_project_override can be set by environment variable: value = true": { |
| ConfigValues: map[string]interface{}{ |
| // user_project_override not set |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "USER_PROJECT_OVERRIDE": "true", |
| }, |
| ExpectedValue: true, |
| }, |
| "user_project_override can be set by environment variable: value = false": { |
| ConfigValues: map[string]interface{}{ |
| // user_project_override not set |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "USER_PROJECT_OVERRIDE": "false", |
| }, |
| ExpectedValue: false, |
| }, |
| "user_project_override can be set by environment variable: value = 1": { |
| ConfigValues: map[string]interface{}{ |
| // user_project_override not set |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "USER_PROJECT_OVERRIDE": "1", |
| }, |
| ExpectedValue: true, |
| }, |
| "user_project_override can be set by environment variable: value = 0": { |
| ConfigValues: map[string]interface{}{ |
| // user_project_override not set |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "USER_PROJECT_OVERRIDE": "0", |
| }, |
| ExpectedValue: false, |
| }, |
| "setting user_project_override using a non-boolean environment variables results in an error": { |
| EnvVariables: map[string]string{ |
| "USER_PROJECT_OVERRIDE": "I'm not a boolean", |
| }, |
| ExpectError: true, |
| }, |
| "when no user_project_override values are provided via config or environment variables, the field remains unset without error": { |
| ConfigValues: map[string]interface{}{ |
| // user_project_override unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, |
| ExpectedValue: false, |
| }, |
| // There isn't an equivalent test case for 'user sets value as empty string' because user_project_override is a boolean; true/false both valid. |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("user_project_override") |
| if ok { |
| val := v.(bool) |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected user_project_override value to not be set in provider config data, got %v", val) |
| } |
| if val != tc.ExpectedValue { |
| t.Fatalf("expected user_project_override value set in provider config data to be %v, got %v", tc.ExpectedValue, val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| v, ok := d.GetOk("user_project_override") |
| val := v.(bool) |
| if ok && tc.ExpectFieldUnset { |
| t.Fatal("expected user_project_override value to be unset in provider config data") |
| } |
| if val != tc.ExpectedValue { |
| t.Fatalf("expected user_project_override value set in provider config data to be %v, got %v", tc.ExpectedValue, val) |
| } |
| if config.UserProjectOverride != tc.ExpectedValue { |
| t.Fatalf("expected user_project_override value set in Config struct to be to be %v, got %v", tc.ExpectedValue, config.UserProjectOverride) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_scopes(t *testing.T) { |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectedSchemaValue []string |
| ExpectedConfigValue []string |
| ExpectFieldUnset bool |
| ExpectError bool |
| }{ |
| "scopes are set in the provider config as a list": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| "scopes": []string{"fizz", "buzz", "fizzbuzz"}, |
| }, |
| ExpectedSchemaValue: []string{"fizz", "buzz", "fizzbuzz"}, |
| ExpectedConfigValue: []string{"fizz", "buzz", "fizzbuzz"}, |
| }, |
| "scopes can be left unset in the provider config without any issues, and a default value is used": { |
| ConfigValues: map[string]interface{}{ |
| // scopes unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedSchemaValue: nil, |
| ExpectedConfigValue: transport_tpg.DefaultClientScopes, |
| }, |
| // Handling empty values in config |
| "scopes set as an empty list the field is treated as if it's unset and a default value is used without errors": { |
| ConfigValues: map[string]interface{}{ |
| "scopes": []string{}, |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectError: false, |
| ExpectFieldUnset: true, //unset in provider config data, not the subsequent Config struct |
| ExpectedSchemaValue: nil, |
| ExpectedConfigValue: transport_tpg.DefaultClientScopes, |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("scopes") |
| if ok { |
| val := v.([]interface{}) |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected scopes value to not be set in provider config data, got %#v", val) |
| } |
| if len(val) != len(tc.ExpectedSchemaValue) { |
| t.Fatalf("expected scopes value set in provider config data to be %#v, got %#v", tc.ExpectedSchemaValue, val) |
| } |
| for i := 0; i < len(val); i++ { |
| if val[i].(string) != tc.ExpectedSchemaValue[i] { |
| t.Fatalf("expected scopes value set in provider config data to be %#v, got %#v", tc.ExpectedSchemaValue, val) |
| } |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| v, ok := d.GetOk("scopes") |
| if ok { |
| val := v.([]interface{}) |
| |
| if len(val) != len(tc.ExpectedSchemaValue) { |
| t.Fatalf("expected %v scopes set in provider config data, got %v", len(tc.ExpectedSchemaValue), len(val)) |
| } |
| for i, el := range val { |
| scope := el.(string) |
| if scope != tc.ExpectedSchemaValue[i] { |
| t.Fatalf("expected scopes value set in provider config data to be %v, got %v", tc.ExpectedSchemaValue, val) |
| } |
| } |
| } |
| if !ok && (len(tc.ExpectedSchemaValue) > 0) { |
| t.Fatalf("expected %v scopes to be set in the provider data, but is unset", tc.ExpectedSchemaValue) |
| } |
| |
| if len(config.Scopes) != len(tc.ExpectedConfigValue) { |
| t.Fatalf("expected %v scopes set in the config struct, got %v", len(tc.ExpectedConfigValue), len(config.Scopes)) |
| } |
| for i, el := range config.Scopes { |
| if el != tc.ExpectedConfigValue[i] { |
| t.Fatalf("expected scopes value set in provider config data to be %v, got %v", tc.ExpectedConfigValue, config.Scopes) |
| } |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_requestTimeout(t *testing.T) { |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| ExpectedValue string |
| ExpectedSchemaValue string |
| ExpectError bool |
| ExpectFieldUnset bool |
| }{ |
| "if a valid request_timeout is configured in the provider, no error will occur": { |
| ConfigValues: map[string]interface{}{ |
| "request_timeout": "10s", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedValue: "10s", |
| ExpectedSchemaValue: "10s", |
| }, |
| "if an invalid request_timeout is configured in the provider, an error will occur": { |
| ConfigValues: map[string]interface{}{ |
| "request_timeout": "timeout", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedValue: "timeout", |
| ExpectedSchemaValue: "timeout", |
| ExpectError: true, |
| ExpectFieldUnset: false, |
| }, |
| // RequestTimeout is "0s" if unset by the user, and logic elsewhere will supply a different value. |
| // This can be seen in this part of the config code where the default value is set to "120s" |
| // https://github.com/hashicorp/terraform-provider-google/blob/09cb850ee64bcd78e4457df70905530c1ed75f19/google/transport/config.go#L1228-L1233 |
| "when request_timeout is unset in the config, the default value is 0s. (initially; this value is subsequently overwritten)": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedValue: "0s", |
| ExpectFieldUnset: true, |
| }, |
| "when request_timeout is set as an empty string, the default value is 0s. (initially; this value is subsequently overwritten)": { |
| ConfigValues: map[string]interface{}{ |
| "request_timeout": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedValue: "0s", |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("request_timeout") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected request_timeout value set in provider data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected request_timeout value to not be set in provider data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| v := d.Get("request_timeout") // checks for an empty or "0" string in order to set the default value |
| val := v.(string) |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected request_timeout value set in provider data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if config.RequestTimeout.String() != tc.ExpectedValue { |
| t.Fatalf("expected request_timeout value in provider struct to be %s, got %v", tc.ExpectedValue, config.RequestTimeout.String()) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_requestReason(t *testing.T) { |
| |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectError bool |
| ExpectFieldUnset bool |
| ExpectedSchemaValue string |
| ExpectedConfigValue string |
| }{ |
| "when request_reason is unset in the config, environment variable CLOUDSDK_CORE_REQUEST_REASON is used": { |
| ConfigValues: map[string]interface{}{ |
| // request_reason unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "CLOUDSDK_CORE_REQUEST_REASON": "test", |
| }, |
| ExpectedSchemaValue: "test", |
| ExpectedConfigValue: "test", |
| }, |
| "request_reason set in the config is not overridden by environment variables": { |
| ConfigValues: map[string]interface{}{ |
| "request_reason": "request test", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "CLOUDSDK_CORE_REQUEST_REASON": "test", |
| }, |
| ExpectedSchemaValue: "request test", |
| ExpectedConfigValue: "request test", |
| }, |
| "when no request_reason is provided via config or environment variables, the field remains unset without error": { |
| ConfigValues: map[string]interface{}{ |
| // request_reason unset |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "", |
| }, |
| // Handling empty values in config |
| "when request_reason is set as an empty string in the config it is overridden by environment variables": { |
| ConfigValues: map[string]interface{}{ |
| "request_reason": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| EnvVariables: map[string]string{ |
| "CLOUDSDK_CORE_REQUEST_REASON": "test", |
| }, |
| ExpectedSchemaValue: "test", |
| ExpectedConfigValue: "test", |
| }, |
| "when request_reason is set as an empty string in the config, the field remains unset without error": { |
| ConfigValues: map[string]interface{}{ |
| "request_reason": "", |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| }, |
| ExpectedSchemaValue: "", |
| ExpectedConfigValue: "", |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| acctest.SetupTestEnvs(t, tc.EnvVariables) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| c, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("request_reason") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedSchemaValue { |
| t.Fatalf("expected request_reason value set in provider data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected request_reason value to not be set in provider data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| v := d.Get("request_reason") |
| val := v.(string) |
| config := c.(*transport_tpg.Config) // Should be non-nil value, as test cases reaching this point experienced no errors |
| |
| if v != tc.ExpectedSchemaValue { |
| t.Fatalf("expected request_reason value set in provider data to be %s, got %s", tc.ExpectedSchemaValue, val) |
| } |
| if config.RequestReason != tc.ExpectedConfigValue { |
| t.Fatalf("expected request_reason value in provider struct to be %s, got %s", tc.ExpectedConfigValue, config.Credentials) |
| } |
| }) |
| } |
| } |
| |
| func TestProvider_ProviderConfigure_batching(t *testing.T) { |
| //var batch []interface{} |
| cases := map[string]struct { |
| ConfigValues map[string]interface{} |
| EnvVariables map[string]string |
| ExpectError bool |
| ExpectFieldUnset bool |
| ExpectedEnableBatchingValue bool |
| ExpectedSendAfterValue string |
| }{ |
| "batching can be configured with values for enable_batching and send_after": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| "batching": []interface{}{ |
| map[string]interface{}{ |
| "enable_batching": true, |
| "send_after": "45s", |
| }, |
| }, |
| }, |
| ExpectedEnableBatchingValue: true, |
| ExpectedSendAfterValue: "45s", |
| }, |
| "if batching is an empty block, it will set the default values for enable_batching and send_after": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| // batching not set |
| }, |
| // Although at the schema level it's shown that by default it's set to false, the actual default value |
| // is true and can be seen in the `ExpanderProviderBatchingConfig` struct |
| // https://github.com/GoogleCloudPlatform/magic-modules/blob/8cd4a506f0ac4db7b07a8cce914449d34df6f20b/mmv1/third_party/terraform/transport/config.go.erb#L504-L508 |
| ExpectedEnableBatchingValue: false, |
| ExpectedSendAfterValue: "", // uses "" value to be able to set the default value of 30s |
| ExpectFieldUnset: true, |
| }, |
| "when batching is configured with only enable_batching, send_after will be set to a default value": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| "batching": []interface{}{ |
| map[string]interface{}{ |
| "enable_batching": true, |
| }, |
| }, |
| }, |
| ExpectedEnableBatchingValue: true, |
| ExpectedSendAfterValue: "", |
| }, |
| "when batching is configured with only send_after, enable_batching will be set to a default value": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| "batching": []interface{}{ |
| map[string]interface{}{ |
| "send_after": "45s", |
| }, |
| }, |
| }, |
| ExpectedEnableBatchingValue: false, |
| ExpectedSendAfterValue: "45s", |
| }, |
| // Error states |
| "if batching is configured with send_after as an invalid value, there's an error": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| "batching": []interface{}{ |
| map[string]interface{}{ |
| "send_after": "invalid value", |
| }, |
| }, |
| }, |
| ExpectedSendAfterValue: "invalid value", |
| ExpectError: true, |
| }, |
| "if batching is configured with send_after as number value without seconds (s), there's an error": { |
| ConfigValues: map[string]interface{}{ |
| "credentials": transport_tpg.TestFakeCredentialsPath, |
| "batching": []interface{}{ |
| map[string]interface{}{ |
| "send_after": "10", |
| }, |
| }, |
| }, |
| ExpectedSendAfterValue: "10", |
| ExpectError: true, |
| }, |
| } |
| |
| for tn, tc := range cases { |
| t.Run(tn, func(t *testing.T) { |
| |
| // Arrange |
| ctx := context.Background() |
| acctest.UnsetTestProviderConfigEnvs(t) |
| p := provider.Provider() |
| d := tpgresource.SetupTestResourceDataFromConfigMap(t, p.Schema, tc.ConfigValues) |
| |
| // Act |
| _, diags := provider.ProviderConfigure(ctx, d, p) |
| |
| // Assert |
| if diags.HasError() && !tc.ExpectError { |
| t.Fatalf("unexpected error(s): %#v", diags) |
| } |
| if !diags.HasError() && tc.ExpectError { |
| t.Fatal("expected error(s) but got none") |
| } |
| if diags.HasError() && tc.ExpectError { |
| v, ok := d.GetOk("batching.0.enable_batching") |
| val := v.(bool) |
| if ok { |
| if val != tc.ExpectedEnableBatchingValue { |
| t.Fatalf("expected request_timeout value set in provider data to be %v, got %v", tc.ExpectedEnableBatchingValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected request_timeout value to not be set in provider data, got %v", val) |
| } |
| } |
| |
| v, ok = d.GetOk("batching.0.send_after") |
| if ok { |
| val := v.(string) |
| if val != tc.ExpectedSendAfterValue { |
| t.Fatalf("expected send_after value set in provider data to be %v, got %v", tc.ExpectedSendAfterValue, val) |
| } |
| if tc.ExpectFieldUnset { |
| t.Fatalf("expected send_after value to not be set in provider data, got %s", val) |
| } |
| } |
| // Return early in tests where errors expected |
| return |
| } |
| |
| v := d.Get("batching.0.enable_batching") |
| enableBatching := v.(bool) |
| if enableBatching != tc.ExpectedEnableBatchingValue { |
| t.Fatalf("expected enable_batching value set in provider data to be %v, got %v", tc.ExpectedEnableBatchingValue, enableBatching) |
| } |
| |
| v = d.Get("batching.0.send_after") // checks for an empty string in order to set the default value |
| sendAfter := v.(string) |
| if sendAfter != tc.ExpectedSendAfterValue { |
| t.Fatalf("expected send_after value set in provider data to be %s, got %s", tc.ExpectedSendAfterValue, sendAfter) |
| } |
| }) |
| } |
| } |