Skip to content

Commit 0af4c82

Browse files
Add tests around how plugin framework provider configuration code handles user_project_override values, fix potential bug (#8862) (#15776)
* Add initial version of plugin framework provider config test affected by inaccessible functions * Refactor provider config tests to use plugin-framework types * Add test case about handling of Unknown values for `project` * Update tests to check values in BOTH the data model and provider config struct after `LoadAndValidateFramework` runs * Add some tests for `credentials` in plugin framework provider, including test case that fails * Update `LoadAndValidateFramework` to take a pointer to the provider data model, so mutations to the data within the function change the original struct This enables tests to track how the data is mutated * Add remaining `credentials` test cases to check PF/SDK config parity * Make tests unset ADC ENV automatically, update comments to tests setting ADC ENV * Add test for behaviour when credentials value is unknown * Add comment referring devs to where unknown value test is implemented * Remove duplicated test case * Fix filename so it's generated correctly * Remove fmt line * Update `project` tests that are affected by `LoadAndValidateFramework` now taking a pointer as an argument * Update `FrameworkProviderConfig` to use plugin framework types package for `UserProjectOverride` boolean * Add plugin framework version of tests for user_project_override, update test case names in SDK version of tests * Add `user_project_override` test case for handling of unknown value Signed-off-by: Modular Magician <[email protected]>
1 parent 27d8b17 commit 0af4c82

File tree

5 files changed

+140
-3
lines changed

5 files changed

+140
-3
lines changed

.changelog/8862.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
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+
```

google/fwtransport/framework_config.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type FrameworkProviderConfig struct {
4545
Scopes []string
4646
TokenSource oauth2.TokenSource
4747
UserAgent string
48-
UserProjectOverride bool
48+
UserProjectOverride types.Bool
4949

5050
// paths for client setup
5151
AccessApprovalBasePath string
@@ -289,6 +289,7 @@ func (p *FrameworkProviderConfig) LoadAndValidateFramework(ctx context.Context,
289289
p.Project = data.Project
290290
p.Region = data.Region
291291
p.Zone = data.Zone
292+
p.UserProjectOverride = data.UserProjectOverride
292293
p.PollInterval = 10 * time.Second
293294
p.RequestBatcherServiceUsage = transport_tpg.NewRequestBatcher("Service Usage", ctx, batchingConfig)
294295
p.RequestBatcherIam = transport_tpg.NewRequestBatcher("IAM", ctx, batchingConfig)

google/fwtransport/framework_config_test.go

+133
Original file line numberDiff line numberDiff line change
@@ -882,3 +882,136 @@ func TestFrameworkProvider_LoadAndValidateFramework_accessToken(t *testing.T) {
882882
})
883883
}
884884
}
885+
886+
func TestFrameworkProvider_LoadAndValidateFramework_userProjectOverride(t *testing.T) {
887+
888+
// Note: In the test function we need to set the below fields in test case's fwmodels.ProviderModel value
889+
// this is to stop the code under tests experiencing errors, and could be addressed in future refactoring.
890+
// - 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
891+
// - ImpersonateServiceAccountDelegates: If we don't set this, we get a nil pointer exception ¯\_(ツ)_/¯
892+
893+
cases := map[string]struct {
894+
ConfigValues fwmodels.ProviderModel
895+
EnvVariables map[string]string
896+
ExpectedDataModelValue basetypes.BoolValue
897+
ExpectedConfigStructValue basetypes.BoolValue
898+
ExpectError bool
899+
}{
900+
"user_project_override value set in the provider schema is not overridden by ENVs": {
901+
ConfigValues: fwmodels.ProviderModel{
902+
UserProjectOverride: types.BoolValue(false),
903+
},
904+
EnvVariables: map[string]string{
905+
"USER_PROJECT_OVERRIDE": "true",
906+
},
907+
ExpectedDataModelValue: types.BoolValue(false),
908+
ExpectedConfigStructValue: types.BoolValue(false),
909+
},
910+
"user_project_override can be set by environment variable: value = true": {
911+
ConfigValues: fwmodels.ProviderModel{
912+
UserProjectOverride: types.BoolNull(), // not set
913+
},
914+
EnvVariables: map[string]string{
915+
"USER_PROJECT_OVERRIDE": "true",
916+
},
917+
ExpectedDataModelValue: types.BoolValue(true),
918+
ExpectedConfigStructValue: types.BoolValue(true),
919+
},
920+
"user_project_override can be set by environment variable: value = false": {
921+
ConfigValues: fwmodels.ProviderModel{
922+
UserProjectOverride: types.BoolNull(), // not set
923+
},
924+
EnvVariables: map[string]string{
925+
"USER_PROJECT_OVERRIDE": "false",
926+
},
927+
ExpectedDataModelValue: types.BoolValue(false),
928+
ExpectedConfigStructValue: types.BoolValue(false),
929+
},
930+
"user_project_override can be set by environment variable: value = 1": {
931+
ConfigValues: fwmodels.ProviderModel{
932+
UserProjectOverride: types.BoolNull(), // not set
933+
},
934+
EnvVariables: map[string]string{
935+
"USER_PROJECT_OVERRIDE": "1",
936+
},
937+
ExpectedDataModelValue: types.BoolValue(true),
938+
ExpectedConfigStructValue: types.BoolValue(true),
939+
},
940+
"user_project_override can be set by environment variable: value = 0": {
941+
ConfigValues: fwmodels.ProviderModel{
942+
UserProjectOverride: types.BoolNull(), // not set
943+
},
944+
EnvVariables: map[string]string{
945+
"USER_PROJECT_OVERRIDE": "0",
946+
},
947+
ExpectedDataModelValue: types.BoolValue(false),
948+
ExpectedConfigStructValue: types.BoolValue(false),
949+
},
950+
"setting user_project_override using a non-boolean environment variables results in an error": {
951+
EnvVariables: map[string]string{
952+
"USER_PROJECT_OVERRIDE": "I'm not a boolean",
953+
},
954+
ExpectError: true,
955+
},
956+
"when no user_project_override values are provided via config or environment variables, the field remains unset without error": {
957+
ConfigValues: fwmodels.ProviderModel{
958+
UserProjectOverride: types.BoolNull(), // not set
959+
},
960+
ExpectedDataModelValue: types.BoolNull(),
961+
ExpectedConfigStructValue: types.BoolNull(),
962+
},
963+
// Handling unknown values
964+
// TODO(SarahFrench) make these tests pass to address: https://github.com/hashicorp/terraform-provider-google/issues/14444
965+
// "when user_project_override is an unknown value, the provider treats it as if it's unset (align to SDK behaviour)": {
966+
// ConfigValues: fwmodels.ProviderModel{
967+
// UserProjectOverride: types.BoolUnknown(),
968+
// },
969+
// ExpectedDataModelValue: types.BoolNull(),
970+
// ExpectedConfigStructValue: types.BoolNull(),
971+
// },
972+
}
973+
974+
for tn, tc := range cases {
975+
t.Run(tn, func(t *testing.T) {
976+
977+
// Arrange
978+
acctest.UnsetTestProviderConfigEnvs(t)
979+
acctest.SetupTestEnvs(t, tc.EnvVariables)
980+
981+
ctx := context.Background()
982+
tfVersion := "foobar"
983+
providerversion := "999"
984+
diags := diag.Diagnostics{}
985+
986+
data := tc.ConfigValues
987+
data.Credentials = types.StringValue(transport_tpg.TestFakeCredentialsPath)
988+
impersonateServiceAccountDelegates, _ := types.ListValue(types.StringType, []attr.Value{}) // empty list
989+
data.ImpersonateServiceAccountDelegates = impersonateServiceAccountDelegates
990+
991+
p := fwtransport.FrameworkProviderConfig{}
992+
993+
// Act
994+
p.LoadAndValidateFramework(ctx, &data, tfVersion, &diags, providerversion)
995+
996+
// Assert
997+
if diags.HasError() && tc.ExpectError {
998+
return
999+
}
1000+
if diags.HasError() && !tc.ExpectError {
1001+
for i, err := range diags.Errors() {
1002+
num := i + 1
1003+
t.Logf("unexpected error #%d : %s", num, err.Summary())
1004+
}
1005+
t.Fatalf("did not expect error, but [%d] error(s) occurred", diags.ErrorsCount())
1006+
}
1007+
// Checking mutation of the data model
1008+
if !data.UserProjectOverride.Equal(tc.ExpectedDataModelValue) {
1009+
t.Fatalf("want user_project_override in the `fwmodels.ProviderModel` struct to be `%s`, but got the value `%s`", tc.ExpectedDataModelValue, data.UserProjectOverride.String())
1010+
}
1011+
// Checking the value passed to the config structs
1012+
if !p.UserProjectOverride.Equal(tc.ExpectedConfigStructValue) {
1013+
t.Fatalf("want user_project_override in the `FrameworkProviderConfig` struct to be `%s`, but got the value `%s`", tc.ExpectedConfigStructValue, p.UserProjectOverride.String())
1014+
}
1015+
})
1016+
}
1017+
}

google/fwtransport/framework_transport.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func SendFrameworkRequestWithTimeout(p *FrameworkProviderConfig, method, project
2525
reqHeaders.Set("User-Agent", userAgent)
2626
reqHeaders.Set("Content-Type", "application/json")
2727

28-
if p.UserProjectOverride && project != "" {
28+
if p.UserProjectOverride.ValueBool() && project != "" {
2929
// When project is "NO_BILLING_PROJECT_OVERRIDE" in the function GetCurrentUserEmail,
3030
// set the header X-Goog-User-Project to be empty string.
3131
if project == "NO_BILLING_PROJECT_OVERRIDE" {

google/provider/provider_internal_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1175,7 +1175,7 @@ func TestProvider_ProviderConfigure_userProjectOverride(t *testing.T) {
11751175
},
11761176
ExpectedValue: false,
11771177
},
1178-
"error returned due to non-boolean environment variables": {
1178+
"setting user_project_override using a non-boolean environment variables results in an error": {
11791179
EnvVariables: map[string]string{
11801180
"USER_PROJECT_OVERRIDE": "I'm not a boolean",
11811181
},

0 commit comments

Comments
 (0)