Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests around how plugin framework provider configuration code handles user_project_override values, fix potential bug #6230

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/8862.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
provider: fixed a bug where `user_project_override` would not be not used correctly when provisioning resources implemented using the plugin framework. Currently there are no resources implemented this way, so no-one should have been impacted.
```
3 changes: 2 additions & 1 deletion google-beta/fwtransport/framework_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ type FrameworkProviderConfig struct {
Scopes []string
TokenSource oauth2.TokenSource
UserAgent string
UserProjectOverride bool
UserProjectOverride types.Bool

// paths for client setup
AccessApprovalBasePath string
Expand Down Expand Up @@ -319,6 +319,7 @@ func (p *FrameworkProviderConfig) LoadAndValidateFramework(ctx context.Context,
p.Project = data.Project
p.Region = data.Region
p.Zone = data.Zone
p.UserProjectOverride = data.UserProjectOverride
p.PollInterval = 10 * time.Second
p.RequestBatcherServiceUsage = transport_tpg.NewRequestBatcher("Service Usage", ctx, batchingConfig)
p.RequestBatcherIam = transport_tpg.NewRequestBatcher("IAM", ctx, batchingConfig)
Expand Down
133 changes: 133 additions & 0 deletions google-beta/fwtransport/framework_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -882,3 +882,136 @@ func TestFrameworkProvider_LoadAndValidateFramework_accessToken(t *testing.T) {
})
}
}

func TestFrameworkProvider_LoadAndValidateFramework_userProjectOverride(t *testing.T) {

// Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value
// this is to stop the code under tests experiencing errors, and could be addressed in future refactoring.
// - Credentials: If we don't set this then the test looks for application default credentials and can fail depending on the machine running the test
// - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯

cases := map[string]struct {
ConfigValues fwmodels.ProviderModel
EnvVariables map[string]string
ExpectedDataModelValue basetypes.BoolValue
ExpectedConfigStructValue basetypes.BoolValue
ExpectError bool
}{
"user_project_override value set in the provider schema is not overridden by ENVs": {
ConfigValues: fwmodels.ProviderModel{
UserProjectOverride: types.BoolValue(false),
},
EnvVariables: map[string]string{
"USER_PROJECT_OVERRIDE": "true",
},
ExpectedDataModelValue: types.BoolValue(false),
ExpectedConfigStructValue: types.BoolValue(false),
},
"user_project_override can be set by environment variable: value = true": {
ConfigValues: fwmodels.ProviderModel{
UserProjectOverride: types.BoolNull(), // not set
},
EnvVariables: map[string]string{
"USER_PROJECT_OVERRIDE": "true",
},
ExpectedDataModelValue: types.BoolValue(true),
ExpectedConfigStructValue: types.BoolValue(true),
},
"user_project_override can be set by environment variable: value = false": {
ConfigValues: fwmodels.ProviderModel{
UserProjectOverride: types.BoolNull(), // not set
},
EnvVariables: map[string]string{
"USER_PROJECT_OVERRIDE": "false",
},
ExpectedDataModelValue: types.BoolValue(false),
ExpectedConfigStructValue: types.BoolValue(false),
},
"user_project_override can be set by environment variable: value = 1": {
ConfigValues: fwmodels.ProviderModel{
UserProjectOverride: types.BoolNull(), // not set
},
EnvVariables: map[string]string{
"USER_PROJECT_OVERRIDE": "1",
},
ExpectedDataModelValue: types.BoolValue(true),
ExpectedConfigStructValue: types.BoolValue(true),
},
"user_project_override can be set by environment variable: value = 0": {
ConfigValues: fwmodels.ProviderModel{
UserProjectOverride: types.BoolNull(), // not set
},
EnvVariables: map[string]string{
"USER_PROJECT_OVERRIDE": "0",
},
ExpectedDataModelValue: types.BoolValue(false),
ExpectedConfigStructValue: types.BoolValue(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: fwmodels.ProviderModel{
UserProjectOverride: types.BoolNull(), // not set
},
ExpectedDataModelValue: types.BoolNull(),
ExpectedConfigStructValue: types.BoolNull(),
},
// Handling unknown values
// TODO(SarahFrench) make these tests pass to address: https://github.com/hashicorp/terraform-provider-google/issues/14444
// "when user_project_override is an unknown value, the provider treats it as if it's unset (align to SDK behaviour)": {
// ConfigValues: fwmodels.ProviderModel{
// UserProjectOverride: types.BoolUnknown(),
// },
// ExpectedDataModelValue: types.BoolNull(),
// ExpectedConfigStructValue: types.BoolNull(),
// },
}

for tn, tc := range cases {
t.Run(tn, func(t *testing.T) {

// Arrange
acctest.UnsetTestProviderConfigEnvs(t)
acctest.SetupTestEnvs(t, tc.EnvVariables)

ctx := context.Background()
tfVersion := "foobar"
providerversion := "999"
diags := diag.Diagnostics{}

data := tc.ConfigValues
data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath)
impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list
data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates

p := fwtransport.FrameworkProviderConfig{}

// Act
p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion)

// Assert
if diags.HasError() && tc.ExpectError {
return
}
if diags.HasError() && !tc.ExpectError {
for i, err := range diags.Errors() {
num := i + 1
t.Logf("unexpected error #%d : %s", num, err.Summary())
}
t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount())
}
// Checking mutation of the data model
if !data.UserProjectOverride.Equal(tc.ExpectedDataModelValue) {
t.Fatalf("want user_project_override in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.UserProjectOverride.String())
}
// Checking the value passed to the config structs
if !p.UserProjectOverride.Equal(tc.ExpectedConfigStructValue) {
t.Fatalf("want user_project_override in the `FrameworkProviderConfig` struct to be `%s`, but got the value `%s`", tc.ExpectedConfigStructValue, p.UserProjectOverride.String())
}
})
}
}
2 changes: 1 addition & 1 deletion google-beta/fwtransport/framework_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func SendFrameworkRequestWithTimeout(p *FrameworkProviderConfig, method, project
reqHeaders.Set("User-Agent", userAgent)
reqHeaders.Set("Content-Type", "application/json")

if p.UserProjectOverride && project != "" {
if p.UserProjectOverride.ValueBool() && project != "" {
// When project is "NO_BILLING_PROJECT_OVERRIDE" in the function GetCurrentUserEmail,
// set the header X-Goog-User-Project to be empty string.
if project == "NO_BILLING_PROJECT_OVERRIDE" {
Expand Down
2 changes: 1 addition & 1 deletion google-beta/provider/provider_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,7 @@ func TestProvider_ProviderConfigure_userProjectOverride(t *testing.T) {
},
ExpectedValue: false,
},
"error returned due to non-boolean environment variables": {
"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",
},
Expand Down