Skip to content

Commit

Permalink
Implement TypeSet resource.TestCheckFuncs
Browse files Browse the repository at this point in the history
  • Loading branch information
appilon committed May 29, 2020
1 parent 02322fa commit d67c362
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 11 deletions.
128 changes: 128 additions & 0 deletions aws/internal/test/testing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package test

import (
"fmt"
"strconv"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
)

// TestCheckTypeSetElemNestedAttrs is a resource.TestCheckFunc that accepts a resource
// name and flatmap style key to a schema.TypeSet attribute. The function checks
// if it appears to be a schema.TypeSet and then verifies that an element in
// the set matches all nested attribute/value pairs.
//
// Use this function over SDK provided TestCheckFunctions when validating a
// TypeSet where its elements are a nested object with their own attrs/values.
//
// Please note, if the provided value map is not granular enough, there exists
// the possibility you match an element you were not intending to, in the TypeSet.
// Provide a full mapping of attributes to be sure the unique element exists.
func TestCheckTypeSetElemNestedAttrs(name, key string, values map[string]string) resource.TestCheckFunc {
return func(s *terraform.State) error {
ms := s.RootModule()
rs, ok := ms.Resources[name]
if !ok {
return fmt.Errorf("Not found: %s in %s", name, ms.Path)
}

is := rs.Primary
if is == nil {
return fmt.Errorf("No primary instance: %s in %s", name, ms.Path)
}

// A TypeSet should have a special count attribute
countStr, ok := is.Attributes[key+".#"]
if !ok {
return fmt.Errorf("%q %q does not appear to be a TypeSet", name, key)
}
count, err := strconv.ParseInt(countStr, 10, 64)
if err != nil {
return err
}

// unflatten the TypeSet from State
passedKeyParts := strings.Split(key, ".")
elements := make(map[string]map[string]string, count)
for stateKey, stateValue := range is.Attributes {
stateKeyParts := strings.Split(stateKey, ".")
if strings.HasPrefix(stateKey, key) {
id := stateKeyParts[len(passedKeyParts)]
if id != "#" {
element, ok := elements[id]
if !ok {
elements[id] = make(map[string]string)
element = elements[id]
}

element[strings.Join(stateKeyParts[len(passedKeyParts)+1:], ".")] = stateValue

// this maybe be redundant.. never sure
elements[id] = element
}
}
}

// Sanity check
// This is helpful for me but maybe shouldn't exist? As stated it indicates
// a bug in this function or something unexpected in State?
if len(elements) != int(count) {
fmt.Errorf("Expecting the number of set items to be %d, got %d.\nThis could be a bug in the TestCheckTypeSetElemNestedAttrs function, or less likely a bug in the SDK/State", count, len(elements))
}

// check if an element is a full match with the passed values map
for _, element := range elements {
var matches int
for k, v := range values {
if stateValue, keyExists := element[k]; keyExists && stateValue == v {
matches++
}
}
if matches == len(values) {
return nil
}
}

return fmt.Errorf("No TypeSet element with attr/value pairs: %#v in state: %#v", values, is.Attributes)
}
}

// TestCheckTypeSetElemAttr is a resource.TestCheckFunc that accepts a resource
// name and flatmap style key to a schema.TypeSet attribute. The function checks
// if it appears to be a schema.TypeSet and then verifies that an element in
// the set matches the passed value.
//
// Use this function over SDK provided TestCheckFunctions when validating a
// TypeSet where its elements are a simple value
func TestCheckTypeSetElemAttr(name, key, value string) resource.TestCheckFunc {
return func(s *terraform.State) error {
ms := s.RootModule()
rs, ok := ms.Resources[name]
if !ok {
return fmt.Errorf("Not found: %s in %s", name, ms.Path)
}

is := rs.Primary
if is == nil {
return fmt.Errorf("No primary instance: %s in %s", name, ms.Path)
}

// A TypeSet should have a special count attribute
if _, ok := is.Attributes[key+".#"]; !ok {
return fmt.Errorf("%s %q does not appear to be a TypeSet", name, key)
}

for stateKey, stateValue := range is.Attributes {
parts := strings.Split(stateKey, ".")
// ensure the passed key is in fact the direct path to the supposed
// TypeSet and the values match
if stateValue == value && key == strings.Join(parts[:len(parts)-1], ".") {
return nil
}
}

return fmt.Errorf("No TypeSet element with value: %q in state: %#v", value, is.Attributes)
}
}
11 changes: 6 additions & 5 deletions aws/resource_aws_apigatewayv2_api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"

"github.com/terraform-providers/terraform-provider-aws/aws/internal/test"
)

func init() {
Expand Down Expand Up @@ -374,10 +376,9 @@ func TestAccAWSAPIGatewayV2Api_CorsConfiguration(t *testing.T) {
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSAPIGatewayV2ApiDestroy,
DisableBinaryDriver: true,
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSAPIGatewayV2ApiDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSAPIGatewayV2ApiConfig_corsConfiguration(rName),
Expand All @@ -389,7 +390,7 @@ func TestAccAWSAPIGatewayV2Api_CorsConfiguration(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "cors_configuration.#", "1"),
resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_credentials", "false"),
resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_headers.#", "1"),
resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_headers.2053999599", "Authorization"),
test.TestCheckTypeSetElemAttr(resourceName, "cors_configuration.0.allow_headers", "Authorization"),
resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_methods.#", "2"),
resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_methods.4248514160", "GET"),
resource.TestCheckResourceAttr(resourceName, "cors_configuration.0.allow_methods.2928708052", "put"),
Expand Down
14 changes: 8 additions & 6 deletions aws/resource_aws_db_parameter_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/test"
)

func init() {
Expand Down Expand Up @@ -79,10 +80,9 @@ func TestAccAWSDBParameterGroup_basic(t *testing.T) {
groupName := fmt.Sprintf("parameter-group-test-terraform-%d", acctest.RandInt())

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBParameterGroupDestroy,
DisableBinaryDriver: true,
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSDBParameterGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSDBParameterGroupConfig(groupName),
Expand All @@ -91,8 +91,10 @@ func TestAccAWSDBParameterGroup_basic(t *testing.T) {
testAccCheckAWSDBParameterGroupAttributes(&v, groupName),
resource.TestCheckResourceAttr(resourceName, "name", groupName),
resource.TestCheckResourceAttr(resourceName, "family", "mysql5.6"),
resource.TestCheckResourceAttr(resourceName, "parameter.1708034931.name", "character_set_results"),
resource.TestCheckResourceAttr(resourceName, "parameter.1708034931.value", "utf8"),
test.TestCheckTypeSetElemNestedAttrs(resourceName, "parameter", map[string]string{
"name": "character_set_results",
"value": "utf8",
}),
resource.TestCheckResourceAttr(resourceName, "parameter.2421266705.name", "character_set_server"),
resource.TestCheckResourceAttr(resourceName, "parameter.2421266705.value", "utf8"),
resource.TestCheckResourceAttr(resourceName, "parameter.2478663599.name", "character_set_client"),
Expand Down

0 comments on commit d67c362

Please sign in to comment.