diff --git a/aws/cur_test.go b/aws/cur_test.go new file mode 100644 index 00000000000..d6fc0b9263a --- /dev/null +++ b/aws/cur_test.go @@ -0,0 +1,83 @@ +package aws + +import ( + "context" + "sync" + "testing" + + "github.com/aws/aws-sdk-go/aws/endpoints" + "github.com/aws/aws-sdk-go/service/costandusagereportservice" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +// testAccCurRegion is the chosen Cost and Usage Reporting testing region +// +// Cached to prevent issues should multiple regions become available. +var testAccCurRegion string + +// testAccProviderCur is the Cost and Usage Reporting provider instance +// +// This Provider can be used in testing code for API calls without requiring +// the use of saving and referencing specific ProviderFactories instances. +// +// testAccPreCheckCur(t) must be called before using this provider instance. +var testAccProviderCur *schema.Provider + +// testAccProviderCurConfigure ensures the provider is only configured once +var testAccProviderCurConfigure sync.Once + +// testAccPreCheckCur verifies AWS credentials and that Cost and Usage Reporting is supported +func testAccPreCheckCur(t *testing.T) { + testAccPartitionHasServicePreCheck(costandusagereportservice.ServiceName, t) + + // Since we are outside the scope of the Terraform configuration we must + // call Configure() to properly initialize the provider configuration. + testAccProviderCurConfigure.Do(func() { + testAccProviderCur = Provider() + + config := map[string]interface{}{ + "region": testAccGetCurRegion(), + } + + err := testAccProviderCur.Configure(context.Background(), terraform.NewResourceConfigRaw(config)) + + if err != nil { + t.Fatal(err) + } + }) +} + +// testAccCurRegionProviderConfig is the Terraform provider configuration for Cost and Usage Reporting region testing +// +// Testing Cost and Usage Reporting assumes no other provider configurations +// are necessary and overwrites the "aws" provider configuration. +func testAccCurRegionProviderConfig() string { + return testAccRegionalProviderConfig(testAccGetCurRegion()) +} + +// testAccGetCurRegion returns the Cost and Usage Reporting region for testing +func testAccGetCurRegion() string { + if testAccCurRegion != "" { + return testAccCurRegion + } + + if rs, ok := endpoints.RegionsForService(endpoints.DefaultPartitions(), testAccGetPartition(), costandusagereportservice.ServiceName); ok { + // return available region (random if multiple) + for regionID := range rs { + testAccCurRegion = regionID + return testAccCurRegion + } + } + + testAccCurRegion = testAccGetRegion() + + return testAccCurRegion +} + +// testAccProviderFactoriesCur initializes providers for Cost and Usage Reporting testing. +// +// Deprecated: This will be replaced with testAccProviderFactories when it only returns the "aws" provider +func testAccProviderFactoriesCur() map[string]func() (*schema.Provider, error) { + return testAccProviderFactoriesInit(nil, []string{ProviderNameAws}) +} diff --git a/aws/data_source_aws_cur_report_definition_test.go b/aws/data_source_aws_cur_report_definition_test.go index 06125c94986..43a8c24a637 100644 --- a/aws/data_source_aws_cur_report_definition_test.go +++ b/aws/data_source_aws_cur_report_definition_test.go @@ -2,7 +2,6 @@ package aws import ( "fmt" - "os" "testing" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" @@ -11,12 +10,6 @@ import ( ) func TestAccDataSourceAwsCurReportDefinition_basic(t *testing.T) { - testAccPartitionHasServicePreCheck("cur", t) // This check must come before os.Setenv() or creds fail on GovCloud - - oldvar := os.Getenv("AWS_DEFAULT_REGION") - os.Setenv("AWS_DEFAULT_REGION", "us-east-1") // lintignore:AWSAT003 - defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - resourceName := "aws_cur_report_definition.test" datasourceName := "data.aws_cur_report_definition.test" @@ -24,9 +17,9 @@ func TestAccDataSourceAwsCurReportDefinition_basic(t *testing.T) { bucketName := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt()) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCur(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, + ProviderFactories: testAccProviderFactoriesCur(), + CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAwsCurReportDefinitionConfig_basic(reportName, bucketName), @@ -47,12 +40,6 @@ func TestAccDataSourceAwsCurReportDefinition_basic(t *testing.T) { } func TestAccDataSourceAwsCurReportDefinition_additional(t *testing.T) { - testAccPartitionHasServicePreCheck("cur", t) // This check must come before os.Setenv() or creds fail on GovCloud - - oldvar := os.Getenv("AWS_DEFAULT_REGION") - os.Setenv("AWS_DEFAULT_REGION", "us-east-1") //lintignore:AWSAT003 - defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - resourceName := "aws_cur_report_definition.test" datasourceName := "data.aws_cur_report_definition.test" @@ -60,9 +47,9 @@ func TestAccDataSourceAwsCurReportDefinition_additional(t *testing.T) { bucketName := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt()) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCur(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, + ProviderFactories: testAccProviderFactoriesCur(), + CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { Config: testAccDataSourceAwsCurReportDefinitionConfig_additional(reportName, bucketName), @@ -98,14 +85,10 @@ func testAccDataSourceAwsCurReportDefinitionCheckExists(datasourceName, resource } } -// note: cur report definitions are currently only supported in us-east-1 func testAccDataSourceAwsCurReportDefinitionConfig_basic(reportName string, bucketName string) string { - //lintignore:AWSAT003,AWSAT005 - return fmt.Sprintf(` -provider "aws" { - region = "us-east-1" -} - + return composeConfig( + testAccCurRegionProviderConfig(), + fmt.Sprintf(` data "aws_billing_service_account" "test" {} resource "aws_s3_bucket" "test" { @@ -165,16 +148,13 @@ resource "aws_cur_report_definition" "test" { data "aws_cur_report_definition" "test" { report_name = aws_cur_report_definition.test.report_name } -`, reportName, bucketName) +`, reportName, bucketName)) } func testAccDataSourceAwsCurReportDefinitionConfig_additional(reportName string, bucketName string) string { - //lintignore:AWSAT003,AWSAT005 - return fmt.Sprintf(` -provider "aws" { - region = "us-east-1" -} - + return composeConfig( + testAccCurRegionProviderConfig(), + fmt.Sprintf(` data "aws_billing_service_account" "test" {} resource "aws_s3_bucket" "test" { @@ -236,5 +216,5 @@ resource "aws_cur_report_definition" "test" { data "aws_cur_report_definition" "test" { report_name = aws_cur_report_definition.test.report_name } -`, reportName, bucketName) +`, reportName, bucketName)) } diff --git a/aws/resource_aws_cur_report_definition_test.go b/aws/resource_aws_cur_report_definition_test.go index 68a86aee374..ce522a7afa9 100644 --- a/aws/resource_aws_cur_report_definition_test.go +++ b/aws/resource_aws_cur_report_definition_test.go @@ -2,11 +2,9 @@ package aws import ( "fmt" - "os" "strings" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/costandusagereportservice" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" @@ -14,21 +12,15 @@ import ( ) func TestAccAwsCurReportDefinition_basic(t *testing.T) { - testAccPartitionHasServicePreCheck("cur", t) // This check must come before os.Setenv() or creds fail on GovCloud - - oldvar := os.Getenv("AWS_DEFAULT_REGION") - os.Setenv("AWS_DEFAULT_REGION", "us-east-1") // lintignore:AWSAT003 - defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") bucketName := fmt.Sprintf("tf-test-bucket-%d", acctest.RandInt()) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCur(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, + ProviderFactories: testAccProviderFactoriesCur(), + CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { Config: testAccAwsCurReportDefinitionConfig_basic(reportName, bucketName), @@ -49,12 +41,6 @@ func TestAccAwsCurReportDefinition_basic(t *testing.T) { } func TestAccAwsCurReportDefinition_textOrCsv(t *testing.T) { - testAccPartitionHasServicePreCheck("cur", t) // This check must come before os.Setenv() or creds fail on GovCloud - - oldvar := os.Getenv("AWS_DEFAULT_REGION") - os.Setenv("AWS_DEFAULT_REGION", "us-east-1") // lintignore:AWSAT003 - defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -67,9 +53,9 @@ func TestAccAwsCurReportDefinition_textOrCsv(t *testing.T) { reportVersioning := "CREATE_NEW_REPORT" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCur(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, + ProviderFactories: testAccProviderFactoriesCur(), + CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { Config: testAccAwsCurReportDefinitionConfig_additional(reportName, bucketName, bucketPrefix, format, compression, additionalArtifacts, refreshClosedReports, reportVersioning), @@ -93,12 +79,6 @@ func TestAccAwsCurReportDefinition_textOrCsv(t *testing.T) { } func TestAccAwsCurReportDefinition_parquet(t *testing.T) { - testAccPartitionHasServicePreCheck("cur", t) // This check must come before os.Setenv() or creds fail on GovCloud - - oldvar := os.Getenv("AWS_DEFAULT_REGION") - os.Setenv("AWS_DEFAULT_REGION", "us-east-1") // lintignore:AWSAT003 - defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -111,9 +91,9 @@ func TestAccAwsCurReportDefinition_parquet(t *testing.T) { reportVersioning := "CREATE_NEW_REPORT" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCur(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, + ProviderFactories: testAccProviderFactoriesCur(), + CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { Config: testAccAwsCurReportDefinitionConfig_additional(reportName, bucketName, bucketPrefix, format, compression, additionalArtifacts, refreshClosedReports, reportVersioning), @@ -136,12 +116,6 @@ func TestAccAwsCurReportDefinition_parquet(t *testing.T) { } func TestAccAwsCurReportDefinition_athena(t *testing.T) { - testAccPartitionHasServicePreCheck("cur", t) // This check must come before os.Setenv() or creds fail on GovCloud - - oldvar := os.Getenv("AWS_DEFAULT_REGION") - os.Setenv("AWS_DEFAULT_REGION", "us-east-1") // lintignore:AWSAT003 - defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -154,9 +128,9 @@ func TestAccAwsCurReportDefinition_athena(t *testing.T) { reportVersioning := "OVERWRITE_REPORT" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCur(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, + ProviderFactories: testAccProviderFactoriesCur(), + CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { Config: testAccAwsCurReportDefinitionConfig_additional(reportName, bucketName, bucketPrefix, format, compression, additionalArtifacts, refreshClosedReports, reportVersioning), @@ -180,12 +154,6 @@ func TestAccAwsCurReportDefinition_athena(t *testing.T) { } func TestAccAwsCurReportDefinition_refresh(t *testing.T) { - testAccPartitionHasServicePreCheck("cur", t) // This check must come before os.Setenv() or creds fail on GovCloud - - oldvar := os.Getenv("AWS_DEFAULT_REGION") - os.Setenv("AWS_DEFAULT_REGION", "us-east-1") // lintignore:AWSAT003 - defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -198,9 +166,9 @@ func TestAccAwsCurReportDefinition_refresh(t *testing.T) { reportVersioning := "CREATE_NEW_REPORT" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCur(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, + ProviderFactories: testAccProviderFactoriesCur(), + CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { Config: testAccAwsCurReportDefinitionConfig_additional(reportName, bucketName, bucketPrefix, format, compression, additionalArtifacts, refreshClosedReports, reportVersioning), @@ -224,12 +192,6 @@ func TestAccAwsCurReportDefinition_refresh(t *testing.T) { } func TestAccAwsCurReportDefinition_overwrite(t *testing.T) { - testAccPartitionHasServicePreCheck("cur", t) // This check must come before os.Setenv() or creds fail on GovCloud - - oldvar := os.Getenv("AWS_DEFAULT_REGION") - os.Setenv("AWS_DEFAULT_REGION", "us-east-1") // lintignore:AWSAT003 - defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - resourceName := "aws_cur_report_definition.test" s3BucketResourceName := "aws_s3_bucket.test" reportName := acctest.RandomWithPrefix("tf_acc_test") @@ -242,9 +204,9 @@ func TestAccAwsCurReportDefinition_overwrite(t *testing.T) { reportVersioning := "OVERWRITE_REPORT" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCur(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCur(t) }, + ProviderFactories: testAccProviderFactoriesCur(), + CheckDestroy: testAccCheckAwsCurReportDefinitionDestroy, Steps: []resource.TestStep{ { Config: testAccAwsCurReportDefinitionConfig_additional(reportName, bucketName, bucketPrefix, format, compression, additionalArtifacts, refreshClosedReports, reportVersioning), @@ -268,7 +230,7 @@ func TestAccAwsCurReportDefinition_overwrite(t *testing.T) { } func testAccCheckAwsCurReportDefinitionDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).costandusagereportconn + conn := testAccProviderCur.Meta().(*AWSClient).costandusagereportconn for _, rs := range s.RootModule().Resources { if rs.Type != "aws_cur_report_definition" { @@ -289,7 +251,7 @@ func testAccCheckAwsCurReportDefinitionDestroy(s *terraform.State) error { func testAccCheckAwsCurReportDefinitionExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).costandusagereportconn + conn := testAccProviderCur.Meta().(*AWSClient).costandusagereportconn rs, ok := s.RootModule().Resources[resourceName] if !ok { @@ -307,32 +269,10 @@ func testAccCheckAwsCurReportDefinitionExists(resourceName string) resource.Test } } -func testAccPreCheckAWSCur(t *testing.T) { - conn := testAccProvider.Meta().(*AWSClient).costandusagereportconn - - input := &costandusagereportservice.DescribeReportDefinitionsInput{ - MaxResults: aws.Int64(5), - } - - _, err := conn.DescribeReportDefinitions(input) - - if testAccPreCheckSkipError(err) || isAWSErr(err, "AccessDeniedException", "linked account is not allowed to modify report preference") { - t.Skipf("skipping acceptance testing: %s", err) - } - - if err != nil { - t.Fatalf("unexpected PreCheck error: %s", err) - } -} - -// note: cur report definitions are currently only supported in US East (Northern Va) func testAccAwsCurReportDefinitionConfig_basic(reportName string, bucketName string) string { - // lintignore:AWSAT003 - return fmt.Sprintf(` -provider "aws" { - region = "us-east-1" -} - + return composeConfig( + testAccCurRegionProviderConfig(), + fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = "%[2]s" acl = "private" @@ -388,7 +328,7 @@ resource "aws_cur_report_definition" "test" { s3_region = aws_s3_bucket.test.region additional_artifacts = ["REDSHIFT", "QUICKSIGHT"] } -`, reportName, bucketName) +`, reportName, bucketName)) } func testAccAwsCurReportDefinitionConfig_additional(reportName string, bucketName string, bucketPrefix string, format string, compression string, additionalArtifacts []string, refreshClosedReports bool, reportVersioning string) string { @@ -400,12 +340,9 @@ func testAccAwsCurReportDefinitionConfig_additional(reportName string, bucketNam artifactsStr = "" } - // lintignore:AWSAT003 - return fmt.Sprintf(` -provider "aws" { - region = "us-east-1" -} - + return composeConfig( + testAccCurRegionProviderConfig(), + fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = "%[2]s" acl = "private" @@ -463,7 +400,7 @@ resource "aws_cur_report_definition" "test" { refresh_closed_reports = %[7]t report_versioning = "%[8]s" } -`, reportName, bucketName, bucketPrefix, format, compression, artifactsStr, refreshClosedReports, reportVersioning) +`, reportName, bucketName, bucketPrefix, format, compression, artifactsStr, refreshClosedReports, reportVersioning)) } func TestCheckAwsCurReportDefinitionPropertyCombination(t *testing.T) {