diff --git a/aws/resource_aws_route53_resolver_rule_test.go b/aws/resource_aws_route53_resolver_rule_test.go index 64fcef77bb51..5278e20482c2 100644 --- a/aws/resource_aws_route53_resolver_rule_test.go +++ b/aws/resource_aws_route53_resolver_rule_test.go @@ -111,6 +111,64 @@ func TestAccAwsRoute53ResolverRule_basic(t *testing.T) { }) } +func TestAccAwsRoute53ResolverRule_justDotDomainName(t *testing.T) { + var rule route53resolver.ResolverRule + resourceName := "aws_route53_resolver_rule.example" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53ResolverRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ResolverRuleConfig("."), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverRuleExists(resourceName, &rule), + resource.TestCheckResourceAttr(resourceName, "domain_name", "."), + resource.TestCheckResourceAttr(resourceName, "rule_type", "SYSTEM"), + resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAwsRoute53ResolverRule_trailingDotDomainName(t *testing.T) { + var rule route53resolver.ResolverRule + resourceName := "aws_route53_resolver_rule.example" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRoute53ResolverRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRoute53ResolverRuleConfig("example.com."), + Check: resource.ComposeTestCheckFunc( + testAccCheckRoute53ResolverRuleExists(resourceName, &rule), + resource.TestCheckResourceAttr(resourceName, "domain_name", "example.com"), + resource.TestCheckResourceAttr(resourceName, "rule_type", "SYSTEM"), + resource.TestCheckResourceAttr(resourceName, "share_status", "NOT_SHARED"), + testAccCheckResourceAttrAccountID(resourceName, "owner_id"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAwsRoute53ResolverRule_tags(t *testing.T) { var rule route53resolver.ResolverRule resourceName := "aws_route53_resolver_rule.example" @@ -389,6 +447,15 @@ func testAccCheckRoute53ResolverRuleExists(n string, rule *route53resolver.Resol } } +func testAccRoute53ResolverRuleConfig(domainName string) string { + return fmt.Sprintf(` +resource "aws_route53_resolver_rule" "example" { + domain_name = %[1]q + rule_type = "SYSTEM" +} +`, domainName) +} + const testAccRoute53ResolverRuleConfig_basicNoTags = ` resource "aws_route53_resolver_rule" "example" { domain_name = "example.com" diff --git a/aws/resource_aws_route53_zone.go b/aws/resource_aws_route53_zone.go index cb7ff868f620..9b5b28bd1dd5 100644 --- a/aws/resource_aws_route53_zone.go +++ b/aws/resource_aws_route53_zone.go @@ -397,17 +397,23 @@ func cleanZoneID(ID string) string { // trimTrailingPeriod is used to remove the trailing period // of "name" or "domain name" attributes often returned from -// the Route53 API or provided as user input +// the Route53 API or provided as user input. +// The single dot (".") domain name is returned as-is. func trimTrailingPeriod(v interface{}) string { var str string switch value := v.(type) { case *string: - str = *value + str = aws.StringValue(value) case string: str = value default: return "" } + + if str == "." { + return str + } + return strings.TrimSuffix(str, ".") } diff --git a/aws/resource_aws_route53_zone_test.go b/aws/resource_aws_route53_zone_test.go index 29dbef7fa393..347f9f90aad5 100644 --- a/aws/resource_aws_route53_zone_test.go +++ b/aws/resource_aws_route53_zone_test.go @@ -50,11 +50,19 @@ func TestCleanChangeID(t *testing.T) { func TestTrimTrailingPeriod(t *testing.T) { cases := []struct { - Input, Output string + Input interface{} + Output string }{ {"example.com", "example.com"}, {"example.com.", "example.com"}, {"www.example.com.", "www.example.com"}, + {"", ""}, + {".", "."}, + {aws.String("example.com"), "example.com"}, + {aws.String("example.com."), "example.com"}, + {(*string)(nil), ""}, + {42, ""}, + {nil, ""}, } for _, tc := range cases {