From 8e30f45c6dc700db3dba50a1116b783cbe8e5370 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Wed, 11 Nov 2020 08:57:34 -0500 Subject: [PATCH] tests/resource/aws_cognito_user_pool_domain: Remove hardcoded region handling and create public ACM Certificate Reference: https://github.com/hashicorp/terraform-provider-aws/issues/8316 Reference: https://github.com/hashicorp/terraform-provider-aws/issues/15737 Output from acceptance testing in AWS Commercial: ``` --- PASS: TestAccAWSCognitoUserPoolDomain_custom (816.97s) ``` Output from acceptance testing in AWS GovCloud (US): ``` --- SKIP: TestAccAWSCognitoUserPoolDomain_custom (1.64s) ``` --- aws/cognito_user_pool_domain_test.go | 87 ++++++++++++ aws/resource_aws_acm_certificate_test.go | 5 +- ...ource_aws_cognito_user_pool_domain_test.go | 124 +++++++++++------- docs/MAINTAINING.md | 2 - 4 files changed, 170 insertions(+), 48 deletions(-) create mode 100644 aws/cognito_user_pool_domain_test.go diff --git a/aws/cognito_user_pool_domain_test.go b/aws/cognito_user_pool_domain_test.go new file mode 100644 index 00000000000..9264b46735d --- /dev/null +++ b/aws/cognito_user_pool_domain_test.go @@ -0,0 +1,87 @@ +package aws + +import ( + "context" + "sync" + "testing" + + "github.com/aws/aws-sdk-go/aws/endpoints" + "github.com/aws/aws-sdk-go/service/cognitoidentityprovider" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +// Cognito User Pool Custom Domains can only be created with ACM Certificates in specific regions. + +// testAccCognitoUserPoolCustomDomainRegion is the chosen Cognito User Pool Custom Domains testing region +// +// Cached to prevent issues should multiple regions become available. +var testAccCognitoUserPoolCustomDomainRegion string + +// testAccProviderCognitoUserPoolCustomDomain is the Cognito User Pool Custom Domains provider instance +// +// This Provider can be used in testing code for API calls without requiring +// the use of saving and referencing specific ProviderFactories instances. +// +// testAccPreCheckCognitoUserPoolCustomDomain(t) must be called before using this provider instance. +var testAccProviderCognitoUserPoolCustomDomain *schema.Provider + +// testAccProviderCognitoUserPoolCustomDomainConfigure ensures the provider is only configured once +var testAccProviderCognitoUserPoolCustomDomainConfigure sync.Once + +// testAccPreCheckCognitoUserPoolCustomDomain verifies AWS credentials and that Cognito User Pool Custom Domains is supported +func testAccPreCheckCognitoUserPoolCustomDomain(t *testing.T) { + testAccPartitionHasServicePreCheck(cognitoidentityprovider.EndpointsID, t) + + // Since we are outside the scope of the Terraform configuration we must + // call Configure() to properly initialize the provider configuration. + testAccProviderCognitoUserPoolCustomDomainConfigure.Do(func() { + testAccProviderCognitoUserPoolCustomDomain = Provider() + + region := testAccGetCognitoUserPoolCustomDomainRegion() + + if region == "" { + t.Skip("Cognito User Pool Custom Domains not available in this AWS Partition") + } + + config := map[string]interface{}{ + "region": region, + } + + diags := testAccProviderCognitoUserPoolCustomDomain.Configure(context.Background(), terraform.NewResourceConfigRaw(config)) + + if diags != nil && diags.HasError() { + for _, d := range diags { + if d.Severity == diag.Error { + t.Fatalf("error configuring Cognito User Pool Custom Domains provider: %s", d.Summary) + } + } + } + }) +} + +// testAccCognitoUserPoolCustomDomainRegionProviderConfig is the Terraform provider configuration for Cognito User Pool Custom Domains region testing +// +// Testing Cognito User Pool Custom Domains assumes no other provider configurations +// are necessary and overwrites the "aws" provider configuration. +func testAccCognitoUserPoolCustomDomainRegionProviderConfig() string { + return testAccRegionalProviderConfig(testAccGetCognitoUserPoolCustomDomainRegion()) +} + +// testAccGetCognitoUserPoolCustomDomainRegion returns the Cognito User Pool Custom Domains region for testing +func testAccGetCognitoUserPoolCustomDomainRegion() string { + if testAccCognitoUserPoolCustomDomainRegion != "" { + return testAccCognitoUserPoolCustomDomainRegion + } + + // AWS Commercial: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-add-custom-domain.html + // AWS GovCloud (US) - not supported: https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-cog.html + // AWS China - not supported: https://docs.amazonaws.cn/en_us/aws/latest/userguide/cognito.html + switch testAccGetPartition() { + case endpoints.AwsPartitionID: + testAccCognitoUserPoolCustomDomainRegion = endpoints.UsEast1RegionID + } + + return testAccCognitoUserPoolCustomDomainRegion +} diff --git a/aws/resource_aws_acm_certificate_test.go b/aws/resource_aws_acm_certificate_test.go index bb062a3c749..f25cafafc12 100644 --- a/aws/resource_aws_acm_certificate_test.go +++ b/aws/resource_aws_acm_certificate_test.go @@ -107,12 +107,13 @@ func testAccAwsAcmCertificateDomainFromEnv(t *testing.T) string { } // ACM domain names cannot be longer than 64 characters +// Other resources, e.g. Cognito User Pool Domains, limit this to 63 func testAccAwsAcmCertificateRandomSubDomain(rootDomain string) string { - // Max length (64) + // Max length (63) // Subtract "tf-acc-" prefix (7) // Subtract "." between prefix and root domain (1) // Subtract length of root domain - return fmt.Sprintf("tf-acc-%s.%s", acctest.RandString(56-len(rootDomain)), rootDomain) + return fmt.Sprintf("tf-acc-%s.%s", acctest.RandString(55-len(rootDomain)), rootDomain) } func TestAccAWSAcmCertificate_emailValidation(t *testing.T) { diff --git a/aws/resource_aws_cognito_user_pool_domain_test.go b/aws/resource_aws_cognito_user_pool_domain_test.go index 4163094871a..ba196dd2a3f 100644 --- a/aws/resource_aws_cognito_user_pool_domain_test.go +++ b/aws/resource_aws_cognito_user_pool_domain_test.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" "log" - "os" + "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -104,49 +104,38 @@ func TestAccAWSCognitoUserPoolDomain_basic(t *testing.T) { } func TestAccAWSCognitoUserPoolDomain_custom(t *testing.T) { + rootDomain := testAccAwsAcmCertificateDomainFromEnv(t) + domain := testAccAwsAcmCertificateRandomSubDomain(rootDomain) poolName := fmt.Sprintf("tf-acc-test-pool-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) - // This test must always run in us-east-1 - // BadRequestException: Invalid certificate ARN: arn:aws:acm:us-west-2:123456789012:certificate/xxxxx. Certificate must be in 'us-east-1'. - oldvar := os.Getenv("AWS_DEFAULT_REGION") - os.Setenv("AWS_DEFAULT_REGION", "us-east-1") - defer os.Setenv("AWS_DEFAULT_REGION", oldvar) - - customDomainName := os.Getenv("AWS_COGNITO_USER_POOL_DOMAIN_ROOT_DOMAIN") - if customDomainName == "" { - t.Skip( - "Environment variable AWS_COGNITO_USER_POOL_DOMAIN_ROOT_DOMAIN is not set. " + - "This environment variable must be set to the fqdn of " + - "an ISSUED ACM certificate in us-east-1 to enable this test.") - } - customSubDomainName := fmt.Sprintf("%s.%s", fmt.Sprintf("tf-acc-test-domain-%d", acctest.RandInt()), customDomainName) - // For now, use an environment variable to limit running this test - certificateArn := os.Getenv("AWS_COGNITO_USER_POOL_DOMAIN_CERTIFICATE_ARN") - if certificateArn == "" { - t.Skip( - "Environment variable AWS_COGNITO_USER_POOL_DOMAIN_CERTIFICATE_ARN is not set. " + - "This environment variable must be set to the ARN of " + - "an ISSUED ACM certificate in us-east-1 to enable this test.") - } + acmCertificateResourceName := "aws_acm_certificate.test" + cognitoUserPoolResourceName := "aws_cognito_user_pool.test" + resourceName := "aws_cognito_user_pool_domain.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSCognitoIdentityProvider(t) }, - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSCognitoUserPoolDomainDestroy, + PreCheck: func() { testAccPreCheck(t); testAccPreCheckCognitoUserPoolCustomDomain(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAWSCognitoUserPoolDomainDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSCognitoUserPoolDomainConfig_custom(customSubDomainName, poolName, certificateArn), + Config: testAccAWSCognitoUserPoolDomainConfig_custom(rootDomain, domain, poolName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckAWSCognitoUserPoolDomainExists("aws_cognito_user_pool_domain.main"), - resource.TestCheckResourceAttr("aws_cognito_user_pool_domain.main", "domain", customSubDomainName), - resource.TestCheckResourceAttr("aws_cognito_user_pool_domain.main", "certificate_arn", certificateArn), - resource.TestCheckResourceAttr("aws_cognito_user_pool.main", "name", poolName), - resource.TestCheckResourceAttrSet("aws_cognito_user_pool_domain.main", "aws_account_id"), - resource.TestCheckResourceAttrSet("aws_cognito_user_pool_domain.main", "cloudfront_distribution_arn"), - resource.TestCheckResourceAttrSet("aws_cognito_user_pool_domain.main", "s3_bucket"), - resource.TestCheckResourceAttrSet("aws_cognito_user_pool_domain.main", "version"), + testAccCheckAWSCognitoUserPoolDomainExists(resourceName), + testAccCheckResourceAttrAccountID(resourceName, "aws_account_id"), + resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", acmCertificateResourceName, "arn"), + //lintignore:AWSAT001 // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/11666 + resource.TestMatchResourceAttr(resourceName, "cloudfront_distribution_arn", regexp.MustCompile(`[a-z0-9]+.cloudfront.net$`)), + resource.TestCheckResourceAttrPair(resourceName, "domain", acmCertificateResourceName, "domain_name"), + resource.TestMatchResourceAttr(resourceName, "s3_bucket", regexp.MustCompile(`^.+$`)), + resource.TestCheckResourceAttrPair(resourceName, "user_pool_id", cognitoUserPoolResourceName, "id"), + resource.TestMatchResourceAttr(resourceName, "version", regexp.MustCompile(`^.+$`)), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, }, }) } @@ -230,16 +219,63 @@ resource "aws_cognito_user_pool" "main" { `, domainName, poolName) } -func testAccAWSCognitoUserPoolDomainConfig_custom(customSubDomainName, poolName, certificateArn string) string { - return fmt.Sprintf(` -resource "aws_cognito_user_pool_domain" "main" { - domain = "%s" - user_pool_id = aws_cognito_user_pool.main.id - certificate_arn = "%s" +func testAccAWSCognitoUserPoolDomainConfig_custom(rootDomain string, domain string, poolName string) string { + return composeConfig( + testAccCognitoUserPoolCustomDomainRegionProviderConfig(), + fmt.Sprintf(` +data "aws_route53_zone" "test" { + name = %[1]q + private_zone = false } -resource "aws_cognito_user_pool" "main" { - name = "%s" +resource "aws_acm_certificate" "test" { + domain_name = %[2]q + validation_method = "DNS" +} + +# +# for_each acceptance testing requires: +# https://github.com/hashicorp/terraform-plugin-sdk/issues/536 +# +# resource "aws_route53_record" "test" { +# for_each = { +# for dvo in aws_acm_certificate.test.domain_validation_options: dvo.domain_name => { +# name = dvo.resource_record_name +# record = dvo.resource_record_value +# type = dvo.resource_record_type +# } +# } + +# allow_overwrite = true +# name = each.value.name +# records = [each.value.record] +# ttl = 60 +# type = each.value.type +# zone_id = data.aws_route53_zone.test.zone_id +# } + +resource "aws_route53_record" "test" { + allow_overwrite = true + name = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_name + records = [tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_value] + ttl = 60 + type = tolist(aws_acm_certificate.test.domain_validation_options)[0].resource_record_type + zone_id = data.aws_route53_zone.test.zone_id +} + +resource "aws_acm_certificate_validation" "test" { + certificate_arn = aws_acm_certificate.test.arn + validation_record_fqdns = [aws_route53_record.test.fqdn] +} + +resource "aws_cognito_user_pool" "test" { + name = %[3]q +} + +resource "aws_cognito_user_pool_domain" "test" { + certificate_arn = aws_acm_certificate_validation.test.certificate_arn + domain = aws_acm_certificate.test.domain_name + user_pool_id = aws_cognito_user_pool.test.id } -`, customSubDomainName, certificateArn, poolName) +`, rootDomain, domain, poolName)) } diff --git a/docs/MAINTAINING.md b/docs/MAINTAINING.md index f30a296d7fd..6c3620cec80 100644 --- a/docs/MAINTAINING.md +++ b/docs/MAINTAINING.md @@ -400,8 +400,6 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi | `AWS_API_GATEWAY_DOMAIN_NAME_REGIONAL_CERTIFICATE_NAME_ENABLED` | Flag to enable API Gateway Domain Name regional certificate upload testing. | | `AWS_CODEBUILD_BITBUCKET_SOURCE_LOCATION` | BitBucket source URL for CodeBuild testing. CodeBuild must have access to this repository via OAuth or Source Credentials. Defaults to `https://terraform@bitbucket.org/terraform/aws-test.git`. | | `AWS_CODEBUILD_GITHUB_SOURCE_LOCATION` | GitHub source URL for CodeBuild testing. CodeBuild must have access to this repository via OAuth or Source Credentials. Defaults to `https://github.com/hashibot-test/aws-test.git`. | -| `AWS_COGNITO_USER_POOL_DOMAIN_CERTIFICATE_ARN` | Amazon Resource Name of ACM Certificate in `us-east-1` for Cognito User Pool Domain Name testing. | -| `AWS_COGNITO_USER_POOL_DOMAIN_ROOT_DOMAIN` | Root domain name to use with Cognito User Pool Domain testing. | | `AWS_DEFAULT_REGION` | Primary AWS region for tests. Defaults to `us-west-2`. | | `AWS_EC2_CLASSIC_REGION` | AWS region for EC2-Classic testing. Defaults to `us-east-1` in AWS Commercial and `AWS_DEFAULT_REGION` otherwise. | | `AWS_EC2_CLIENT_VPN_LIMIT` | Concurrency limit for Client VPN acceptance tests. [Default is 5](https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/limits.html) if not specified. |