Skip to content

Commit

Permalink
tests/resource/aws_api_gateway_domain_name: Remove hardcoded environm…
Browse files Browse the repository at this point in the history
…ent variable handling, create public ACM certificate, improve state value checks (#16139)

Reference: #8316
Reference: #14664
Reference: #15737

Output from acceptance testing in AWS Commercial:

```
--- PASS: TestAccAWSAPIGatewayDomainName_disappears (20.54s)
--- PASS: TestAccAWSAPIGatewayDomainName_RegionalCertificateArn (81.84s)
--- PASS: TestAccAWSAPIGatewayDomainName_SecurityPolicy (139.42s)
--- PASS: TestAccAWSAPIGatewayDomainName_Tags (203.73s)
--- SKIP: TestAccAWSAPIGatewayDomainName_CertificateName (0.00s)
--- SKIP: TestAccAWSAPIGatewayDomainName_RegionalCertificateName (0.00s)
```

Output from acceptance testing in AWS GovCloud (US) (other tests failing with ACM quota limits):

```
--- SKIP: TestAccAWSAPIGatewayDomainName_CertificateArn (1.58s)
```
  • Loading branch information
bflad authored Nov 12, 2020
1 parent 66f22b1 commit 94161a5
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 33 deletions.
118 changes: 118 additions & 0 deletions aws/api_gateway_domain_name_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package aws

import (
"context"
"fmt"
"sync"
"testing"

"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/aws/endpoints"
"github.com/aws/aws-sdk-go/service/apigateway"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

// API Gateway Edge-Optimized Domain Name can only be created with ACM Certificates in specific regions.

// testAccApigatewayEdgeDomainNameRegion is the chosen API Gateway Domain Name testing region
//
// Cached to prevent issues should multiple regions become available.
var testAccApigatewayEdgeDomainNameRegion string

// testAccProviderApigatewayEdgeDomainName is the API Gateway Domain Name provider instance
//
// This Provider can be used in testing code for API calls without requiring
// the use of saving and referencing specific ProviderFactories instances.
//
// testAccPreCheckApigatewayEdgeDomainName(t) must be called before using this provider instance.
var testAccProviderApigatewayEdgeDomainName *schema.Provider

// testAccProviderApigatewayEdgeDomainNameConfigure ensures the provider is only configured once
var testAccProviderApigatewayEdgeDomainNameConfigure sync.Once

// testAccPreCheckApigatewayEdgeDomainName verifies AWS credentials and that API Gateway Domain Name is supported
func testAccPreCheckApigatewayEdgeDomainName(t *testing.T) {
testAccPartitionHasServicePreCheck(apigateway.EndpointsID, t)

// Since we are outside the scope of the Terraform configuration we must
// call Configure() to properly initialize the provider configuration.
testAccProviderApigatewayEdgeDomainNameConfigure.Do(func() {
testAccProviderApigatewayEdgeDomainName = Provider()

region := testAccGetApigatewayEdgeDomainNameRegion()

if region == "" {
t.Skip("API Gateway Domain Name not available in this AWS Partition")
}

config := map[string]interface{}{
"region": region,
}

diags := testAccProviderApigatewayEdgeDomainName.Configure(context.Background(), terraform.NewResourceConfigRaw(config))

if diags != nil && diags.HasError() {
for _, d := range diags {
if d.Severity == diag.Error {
t.Fatalf("error configuring API Gateway Domain Name provider: %s", d.Summary)
}
}
}
})
}

// testAccApigatewayEdgeDomainNameRegionProviderConfig is the Terraform provider configuration for API Gateway Domain Name region testing
//
// Testing API Gateway Domain Name assumes no other provider configurations
// are necessary and overwrites the "aws" provider configuration.
func testAccApigatewayEdgeDomainNameRegionProviderConfig() string {
return testAccRegionalProviderConfig(testAccGetApigatewayEdgeDomainNameRegion())
}

// testAccGetApigatewayEdgeDomainNameRegion returns the API Gateway Domain Name region for testing
func testAccGetApigatewayEdgeDomainNameRegion() string {
if testAccApigatewayEdgeDomainNameRegion != "" {
return testAccApigatewayEdgeDomainNameRegion
}

// AWS Commercial: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-custom-domains.html
// AWS GovCloud (US) - edge custom domain names not supported: https://docs.aws.amazon.com/govcloud-us/latest/UserGuide/govcloud-abp.html
// AWS China - edge custom domain names not supported: https://docs.amazonaws.cn/en_us/aws/latest/userguide/api-gateway.html
switch testAccGetPartition() {
case endpoints.AwsPartitionID:
testAccApigatewayEdgeDomainNameRegion = endpoints.UsEast1RegionID
}

return testAccApigatewayEdgeDomainNameRegion
}

// testAccCheckResourceAttrRegionalARNApigatewayEdgeDomainName ensures the Terraform state exactly matches the expected API Gateway Edge Domain Name format
func testAccCheckResourceAttrRegionalARNApigatewayEdgeDomainName(resourceName, attributeName, arnService string, domain string) resource.TestCheckFunc {
return func(s *terraform.State) error {
attributeValue := arn.ARN{
Partition: testAccGetPartition(),
Region: testAccGetApigatewayEdgeDomainNameRegion(),
Resource: fmt.Sprintf("/domainnames/%s", domain),
Service: arnService,
}.String()

return resource.TestCheckResourceAttr(resourceName, attributeName, attributeValue)(s)
}
}

// testAccCheckResourceAttrRegionalARNApigatewayRegionalDomainName ensures the Terraform state exactly matches the expected API Gateway Regional Domain Name format
func testAccCheckResourceAttrRegionalARNApigatewayRegionalDomainName(resourceName, attributeName, arnService string, domain string) resource.TestCheckFunc {
return func(s *terraform.State) error {
attributeValue := arn.ARN{
Partition: testAccGetPartition(),
Region: testAccGetRegion(),
Resource: fmt.Sprintf("/domainnames/%s", domain),
Service: arnService,
}.String()

return resource.TestCheckResourceAttr(resourceName, attributeName, attributeValue)(s)
}
}
104 changes: 72 additions & 32 deletions aws/resource_aws_api_gateway_domain_name_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,34 @@ import (
)

func TestAccAWSAPIGatewayDomainName_CertificateArn(t *testing.T) {
certificateArn := os.Getenv("AWS_API_GATEWAY_DOMAIN_NAME_CERTIFICATE_ARN")
if certificateArn == "" {
t.Skip(
"Environment variable AWS_API_GATEWAY_DOMAIN_NAME_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.")
}

// 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)
rootDomain := testAccAwsAcmCertificateDomainFromEnv(t)
domain := testAccAwsAcmCertificateRandomSubDomain(rootDomain)

var domainName apigateway.DomainName
acmCertificateResourceName := "aws_acm_certificate.test"
resourceName := "aws_api_gateway_domain_name.test"
rName := fmt.Sprintf("tf-acc-%s.terraformtest.com", acctest.RandString(8))

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSAPIGatewayDomainNameDestroy,
PreCheck: func() { testAccPreCheck(t); testAccPreCheckApigatewayEdgeDomainName(t) },
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccCheckAWSAPIGatewayDomainNameDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSAPIGatewayDomainNameConfig_CertificateArn(rName, certificateArn),
Config: testAccAWSAPIGatewayDomainNameConfig_CertificateArn(rootDomain, domain),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayDomainNameExists(resourceName, &domainName),
testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/+.`)),
resource.TestCheckResourceAttrSet(resourceName, "cloudfront_domain_name"),
testAccCheckResourceAttrRegionalARNApigatewayEdgeDomainName(resourceName, "arn", "apigateway", domain),
resource.TestCheckResourceAttrPair(resourceName, "certificate_arn", acmCertificateResourceName, "arn"),
resource.TestMatchResourceAttr(resourceName, "cloudfront_domain_name", regexp.MustCompile(`[a-z0-9]+.cloudfront.net`)),
resource.TestCheckResourceAttr(resourceName, "cloudfront_zone_id", "Z2FDTNDATAQYW2"),
resource.TestCheckResourceAttr(resourceName, "domain_name", rName),
resource.TestCheckResourceAttrPair(resourceName, "domain_name", acmCertificateResourceName, "domain_name"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}
Expand Down Expand Up @@ -131,9 +126,9 @@ func TestAccAWSAPIGatewayDomainName_RegionalCertificateArn(t *testing.T) {
Config: testAccAWSAPIGatewayDomainNameConfig_RegionalCertificateArn(rName, key, certificate),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayDomainNameExists(resourceName, &domainName),
testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/+.`)),
testAccCheckResourceAttrRegionalARNApigatewayRegionalDomainName(resourceName, "arn", "apigateway", rName),
resource.TestCheckResourceAttr(resourceName, "domain_name", rName),
resource.TestMatchResourceAttr(resourceName, "regional_domain_name", regexp.MustCompile(`.*\.execute-api\..*`)),
testAccMatchResourceAttrRegionalHostname(resourceName, "regional_domain_name", "execute-api", regexp.MustCompile(`d-[a-z0-9]+`)),
resource.TestMatchResourceAttr(resourceName, "regional_zone_id", regexp.MustCompile(`^Z`)),
),
},
Expand Down Expand Up @@ -174,14 +169,14 @@ func TestAccAWSAPIGatewayDomainName_RegionalCertificateName(t *testing.T) {
Config: testAccAWSAPIGatewayDomainNameConfig_RegionalCertificateName(rName, key, certificate, caCertificate),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayDomainNameExists(resourceName, &domainName),
testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/+.`)),
testAccCheckResourceAttrRegionalARNApigatewayRegionalDomainName(resourceName, "arn", "apigateway", rName),
resource.TestCheckResourceAttr(resourceName, "certificate_body", certificate),
resource.TestCheckResourceAttr(resourceName, "certificate_chain", caCertificate),
resource.TestCheckResourceAttr(resourceName, "certificate_name", "tf-acc-apigateway-domain-name"),
resource.TestCheckResourceAttr(resourceName, "certificate_private_key", key),
resource.TestCheckResourceAttrSet(resourceName, "certificate_upload_date"),
resource.TestCheckResourceAttr(resourceName, "domain_name", rName),
resource.TestMatchResourceAttr(resourceName, "regional_domain_name", regexp.MustCompile(`.*\.execute-api\..*`)),
testAccMatchResourceAttrRegionalHostname(resourceName, "regional_domain_name", "execute-api", regexp.MustCompile(`d-[a-z0-9]+`)),
resource.TestMatchResourceAttr(resourceName, "regional_zone_id", regexp.MustCompile(`^Z`)),
),
},
Expand All @@ -206,7 +201,6 @@ func TestAccAWSAPIGatewayDomainName_SecurityPolicy(t *testing.T) {
Config: testAccAWSAPIGatewayDomainNameConfig_SecurityPolicy(rName, key, certificate, apigateway.SecurityPolicyTls12),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayDomainNameExists(resourceName, &domainName),
testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/+.`)),
resource.TestCheckResourceAttr(resourceName, "security_policy", apigateway.SecurityPolicyTls12),
),
},
Expand Down Expand Up @@ -236,7 +230,6 @@ func TestAccAWSAPIGatewayDomainName_Tags(t *testing.T) {
Config: testAccAWSAPIGatewayDomainNameConfigTags1(rName, key, certificate, "key1", "value1"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayDomainNameExists(resourceName, &domainName),
testAccMatchResourceAttrRegionalARNNoAccount(resourceName, "arn", "apigateway", regexp.MustCompile(`/domainnames/+.`)),
resource.TestCheckResourceAttr(resourceName, "tags.%", "1"),
resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"),
),
Expand Down Expand Up @@ -348,17 +341,64 @@ func testAccCheckAWSAPIGatewayDomainNameDestroy(s *terraform.State) error {
return nil
}

func testAccAWSAPIGatewayDomainNameConfig_CertificateArn(domainName, certificateArn string) string {
return fmt.Sprintf(`
func testAccAWSAPIGatewayDomainNameConfig_CertificateArn(rootDomain string, domain string) string {
return composeConfig(
testAccApigatewayEdgeDomainNameRegionProviderConfig(),
fmt.Sprintf(`
data "aws_route53_zone" "test" {
name = %[1]q
private_zone = false
}
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_api_gateway_domain_name" "test" {
domain_name = "%s"
certificate_arn = "%s"
domain_name = aws_acm_certificate.test.domain_name
certificate_arn = aws_acm_certificate_validation.test.certificate_arn
endpoint_configuration {
types = ["EDGE"]
}
}
`, domainName, certificateArn)
`, rootDomain, domain))
}

func testAccAWSAPIGatewayDomainNameConfig_CertificateName(domainName, key, certificate, chainCertificate string) string {
Expand Down
1 change: 0 additions & 1 deletion docs/MAINTAINING.md
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,6 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi
| `AWS_ALTERNATE_SECRET_ACCESS_KEY` | AWS secret access key with access to a secondary AWS account for tests requiring multiple accounts. Requires `AWS_ALTERNATE_ACCESS_KEY_ID`. Conflicts with `AWS_ALTERNATE_PROFILE`. |
| `AWS_ALTERNATE_PROFILE` | AWS profile with access to a secondary AWS account for tests requiring multiple accounts. Conflicts with `AWS_ALTERNATE_ACCESS_KEY_ID` and `AWS_ALTERNATE_SECRET_ACCESS_KEY`. |
| `AWS_ALTERNATE_REGION` | Secondary AWS region for tests requiring multiple regions. Defaults to `us-east-1`. |
| `AWS_API_GATEWAY_DOMAIN_NAME_CERTIFICATE_ARN` | Amazon Resource Name of ACM Certificate in `us-east-1` for API Gateway Domain Name testing. |
| `AWS_API_GATEWAY_DOMAIN_NAME_CERTIFICATE_BODY` | Certificate body of publicly trusted certificate for API Gateway Domain Name testing. |
| `AWS_API_GATEWAY_DOMAIN_NAME_CERTIFICATE_CHAIN` | Certificate chain of publicly trusted certificate for API Gateway Domain Name testing. |
| `AWS_API_GATEWAY_DOMAIN_NAME_CERTIFICATE_PRIVATE_KEY` | Private key of publicly trusted certificate for API Gateway Domain Name testing. |
Expand Down

0 comments on commit 94161a5

Please sign in to comment.