-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Add acceptance tests for how provider handles scopes
argument
#11860
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
Merged
SarahFrench
merged 3 commits into
GoogleCloudPlatform:main
from
SarahFrench:mux-refactor-12-add-scopes-acctests
Sep 30, 2024
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
190 changes: 190 additions & 0 deletions
190
mmv1/third_party/terraform/fwprovider/framework_provider_scopes_test.go.tmpl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
package fwprovider_test | ||
|
||
import ( | ||
"fmt" | ||
{{- if ne $.TargetVersionName "ga" }} | ||
"regexp" | ||
{{- end }} | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-testing/helper/resource" | ||
"github.com/hashicorp/terraform-provider-google/google/acctest" | ||
"github.com/hashicorp/terraform-provider-google/google/transport" | ||
) | ||
|
||
// TestAccFwProvider_scopes is a series of acc tests asserting how the PF provider handles scopes arguments | ||
// It is PF specific because the HCL used provisions PF-implemented resources | ||
// It is a counterpart to TestAccSdkProvider_scopes | ||
func TestAccFwProvider_scopes(t *testing.T) { | ||
testCases := map[string]func(t *testing.T){ | ||
// Configuring the provider using inputs | ||
"default scopes are used when there are no user inputs": testAccFwProvider_scopes_providerDefault, | ||
"scopes can be set in config": testAccFwProvider_scopes_setInConfig, | ||
//no ENVs to test | ||
|
||
// Schema-level validation | ||
"when scopes is set to an empty array in the config the value is ignored and default scopes are used": testAccFwProvider_scopes_emptyArray, | ||
|
||
// Usage | ||
{{- if ne $.TargetVersionName "ga" }} | ||
// Beta-only generation is needed because we need to access a PF-implemented data source linked to resource in an API. | ||
// Currently this only exists in TPGB. | ||
"the scopes argument impacts provisioning resources": testAccFwProvider_scopes_usage, | ||
{{- else }} | ||
// No usage test cases are implemented in the GA provider because the only PF-implemented data sources are Beta-only | ||
{{- end }} | ||
} | ||
|
||
for name, tc := range testCases { | ||
// shadow the tc variable into scope so that when | ||
// the loop continues, if t.Run hasn't executed tc(t) | ||
// yet, we don't have a race condition | ||
// see https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables | ||
tc := tc | ||
t.Run(name, func(t *testing.T) { | ||
tc(t) | ||
}) | ||
} | ||
} | ||
|
||
func testAccFwProvider_scopes_providerDefault(t *testing.T) { | ||
acctest.SkipIfVcr(t) // Test doesn't interact with API | ||
|
||
acctest.VcrTest(t, resource.TestCase{ | ||
// No PreCheck for checking ENVs | ||
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccFwProvider_scopes_unset(), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "scopes.#", fmt.Sprintf("%d", len(transport.DefaultClientScopes))), | ||
resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "scopes.0", transport.DefaultClientScopes[0]), | ||
resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "scopes.1", transport.DefaultClientScopes[1]), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccFwProvider_scopes_setInConfig(t *testing.T) { | ||
acctest.SkipIfVcr(t) // Test doesn't interact with API | ||
|
||
scopes := []string{"https://www.googleapis.com/auth/cloud-platform"} // first of the two default scopes | ||
context := map[string]interface{}{ | ||
"scopes": fmt.Sprintf("[\"%s\"]", scopes[0]), | ||
} | ||
|
||
acctest.VcrTest(t, resource.TestCase{ | ||
// No PreCheck for checking ENVs | ||
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccFwProvider_scopes_inProviderBlock(context), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "scopes.#", fmt.Sprintf("%d", len(scopes))), | ||
resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "scopes.0", scopes[0]), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccFwProvider_scopes_emptyArray(t *testing.T) { | ||
acctest.SkipIfVcr(t) // Test doesn't interact with API | ||
|
||
context := map[string]interface{}{ | ||
"scopes": "[]", | ||
} | ||
|
||
acctest.VcrTest(t, resource.TestCase{ | ||
// No PreCheck for checking ENVs | ||
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccFwProvider_scopes_inProviderBlock(context), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "scopes.#", fmt.Sprintf("%d", len(transport.DefaultClientScopes))), | ||
resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "scopes.0", transport.DefaultClientScopes[0]), | ||
resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "scopes.1", transport.DefaultClientScopes[1]), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
{{ if ne $.TargetVersionName `ga` -}} | ||
func testAccFwProvider_scopes_usage(t *testing.T) { | ||
acctest.SkipIfVcr(t) // Skip because Firebase is weird with VCR, and we have to use Firebase resources in the test | ||
|
||
// We include scopes that aren't sufficient to enable provisioning the resources in the config below | ||
context := map[string]interface{}{ | ||
"scopes": "[\"https://www.googleapis.com/auth/pubsub\"]", | ||
"random_suffix": acctest.RandString(t, 10), | ||
|
||
"bundle_id": "apple.app." + acctest.RandString(t, 5), | ||
"display_name": "tf-test Display Name AppleAppConfig DataSource", | ||
"app_store_id": 12345, | ||
"team_id": 1234567890, | ||
} | ||
|
||
acctest.VcrTest(t, resource.TestCase{ | ||
// No PreCheck for checking ENVs | ||
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccFwProvider_access_token_useScopes(context), | ||
ExpectError: regexp.MustCompile("Request had insufficient authentication scopes"), | ||
}, | ||
}, | ||
}) | ||
} | ||
{{- end }} | ||
|
||
// testAccFwProvider_scopes_inProviderBlock allows setting the scopes argument in a provider block. | ||
// This function uses data.google_provider_config_plugin_framework because it is implemented with the PF | ||
func testAccFwProvider_scopes_inProviderBlock(context map[string]interface{}) string { | ||
return acctest.Nprintf(` | ||
provider "google" { | ||
scopes = %{scopes} | ||
} | ||
|
||
data "google_provider_config_plugin_framework" "default" {} | ||
`, context) | ||
} | ||
|
||
// testAccFwProvider_scopes_inEnvsOnly allows testing when the scopes argument is not set | ||
func testAccFwProvider_scopes_unset() string { | ||
return ` | ||
data "google_provider_config_plugin_framework" "default" {} | ||
` | ||
} | ||
|
||
{{ if ne $.TargetVersionName `ga` -}} | ||
func testAccFwProvider_access_token_useScopes(context map[string]interface{}) string { | ||
return acctest.Nprintf(` | ||
provider "google" {} // default scopes used | ||
|
||
provider "google" { | ||
alias = "under-scoped" | ||
scopes = %{scopes} | ||
} | ||
|
||
data "google_provider_config_plugin_framework" "default" { | ||
} | ||
|
||
resource "google_firebase_apple_app" "my_app_config" { | ||
project = data.google_provider_config_plugin_framework.default.project | ||
bundle_id = "%{bundle_id}" | ||
display_name = "%{display_name}" | ||
app_store_id = "%{app_store_id}" | ||
team_id = "%{team_id}" | ||
} | ||
|
||
// This is implemented with plugin-framework so tests our use of scopes in a PF specific way | ||
data "google_firebase_apple_app_config" "my_app_config" { | ||
provider = google.under-scoped | ||
app_id = google_firebase_apple_app.my_app_config.app_id | ||
} | ||
`, context) | ||
} | ||
{{- end }} |
161 changes: 161 additions & 0 deletions
161
mmv1/third_party/terraform/provider/provider_scopes_test.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
package provider_test | ||
|
||
import ( | ||
"fmt" | ||
"regexp" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-testing/helper/resource" | ||
"github.com/hashicorp/terraform-provider-google/google/acctest" | ||
"github.com/hashicorp/terraform-provider-google/google/transport" | ||
) | ||
|
||
// TestAccSdkProvider_scopes is a series of acc tests asserting how the SDK provider handles scopes arguments | ||
// It is SDK specific because the HCL used provisions SDK-implemented resources | ||
// It is a counterpart to TestAccFwProvider_scopes | ||
func TestAccSdkProvider_scopes(t *testing.T) { | ||
testCases := map[string]func(t *testing.T){ | ||
// Configuring the provider using inputs | ||
"default scopes are used when there are no user inputs": testAccSdkProvider_scopes_providerDefault, | ||
"scopes can be set in config": testAccSdkProvider_scopes_setInConfig, | ||
//no ENVs to test | ||
|
||
// Schema-level validation | ||
"when scopes is set to an empty array in the config the value is ignored and default scopes are used": testAccSdkProvider_scopes_emptyArray, | ||
|
||
// Usage | ||
"the scopes argument impacts provisioning resources": testAccSdkProvider_scopes_usage, | ||
} | ||
|
||
for name, tc := range testCases { | ||
// shadow the tc variable into scope so that when | ||
// the loop continues, if t.Run hasn't executed tc(t) | ||
// yet, we don't have a race condition | ||
// see https://github.com/golang/go/wiki/CommonMistakes#using-goroutines-on-loop-iterator-variables | ||
tc := tc | ||
t.Run(name, func(t *testing.T) { | ||
tc(t) | ||
}) | ||
} | ||
} | ||
|
||
func testAccSdkProvider_scopes_providerDefault(t *testing.T) { | ||
acctest.SkipIfVcr(t) // Test doesn't interact with API | ||
|
||
acctest.VcrTest(t, resource.TestCase{ | ||
// No PreCheck for checking ENVs | ||
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccSdkProvider_scopes_unset(), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "scopes.#", fmt.Sprintf("%d", len(transport.DefaultClientScopes))), | ||
resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "scopes.0", transport.DefaultClientScopes[0]), | ||
resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "scopes.1", transport.DefaultClientScopes[1]), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccSdkProvider_scopes_setInConfig(t *testing.T) { | ||
acctest.SkipIfVcr(t) // Test doesn't interact with API | ||
|
||
scopes := []string{"https://www.googleapis.com/auth/cloud-platform"} // first of the two default scopes | ||
context := map[string]interface{}{ | ||
"scopes": fmt.Sprintf("[\"%s\"]", scopes[0]), | ||
} | ||
|
||
acctest.VcrTest(t, resource.TestCase{ | ||
// No PreCheck for checking ENVs | ||
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccSdkProvider_scopes_inProviderBlock(context), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "scopes.#", fmt.Sprintf("%d", len(scopes))), | ||
resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "scopes.0", scopes[0]), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccSdkProvider_scopes_emptyArray(t *testing.T) { | ||
acctest.SkipIfVcr(t) // Test doesn't interact with API | ||
|
||
context := map[string]interface{}{ | ||
"scopes": "[]", | ||
} | ||
|
||
acctest.VcrTest(t, resource.TestCase{ | ||
// No PreCheck for checking ENVs | ||
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccSdkProvider_scopes_inProviderBlock(context), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "scopes.#", fmt.Sprintf("%d", len(transport.DefaultClientScopes))), | ||
resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "scopes.0", transport.DefaultClientScopes[0]), | ||
resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "scopes.1", transport.DefaultClientScopes[1]), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccSdkProvider_scopes_usage(t *testing.T) { | ||
acctest.SkipIfVcr(t) // Test doesn't interact with API | ||
|
||
// We include scopes that aren't sufficient to enable provisioning the resources in the config below | ||
context := map[string]interface{}{ | ||
"scopes": "[\"https://www.googleapis.com/auth/pubsub\"]", | ||
"random_suffix": acctest.RandString(t, 10), | ||
} | ||
|
||
acctest.VcrTest(t, resource.TestCase{ | ||
// No PreCheck for checking ENVs | ||
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccSdkProvider_scopes_affectsProvisioning(context), | ||
ExpectError: regexp.MustCompile("Request had insufficient authentication scopes"), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
// testAccSdkProvider_scopes_inProviderBlock allows setting the scopes argument in a provider block. | ||
// This function uses data.google_provider_config_sdk because it is implemented with the SDK | ||
func testAccSdkProvider_scopes_inProviderBlock(context map[string]interface{}) string { | ||
return acctest.Nprintf(` | ||
provider "google" { | ||
scopes = %{scopes} | ||
} | ||
|
||
data "google_provider_config_sdk" "default" {} | ||
`, context) | ||
} | ||
|
||
// testAccSdkProvider_scopes_inEnvsOnly allows testing when the scopes argument is not set | ||
func testAccSdkProvider_scopes_unset() string { | ||
return ` | ||
data "google_provider_config_sdk" "default" {} | ||
` | ||
} | ||
|
||
// testAccSdkProvider_scopes_affectsProvisioning allows testing the impact of the scopes argument on provisioning | ||
func testAccSdkProvider_scopes_affectsProvisioning(context map[string]interface{}) string { | ||
return acctest.Nprintf(` | ||
provider "google" { | ||
scopes = %{scopes} | ||
} | ||
|
||
data "google_provider_config_sdk" "default" {} | ||
|
||
resource "google_service_account" "default" { | ||
account_id = "tf-test-%{random_suffix}" | ||
display_name = "AccTest Service Account" | ||
} | ||
`, context) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice capturing this case!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks 😁 We could add some validation in future to make the scenario more explicit, i.e. block empty arrays so users aren't lulled into a false sense of using no scopes, but that'd be a breaking change. And I don't even know if setting zero scopes is something users would attempt to do, but I can imagine there's someone out there doing it!