helper/resource: TestCheckResourceAttrPair allow nonexist

This checking helper is frequently used in provider tests for data
sources, as a shorthand to verify that an attribute of the data source
matches with the corresponding attribute on a managed resource.

Since we now leave empty collections null in more cases, this function is
sometimes effectively asked to verify that a given attribute is _unset_
in both the data source and the resource, so here we slightly adjust the
definition of the check to consider two nulls to be equal to one another,
which at this layer manifests as the keys not being present in the state
attributes map at all.

This check function didn't previously have tests, so this commit also adds
a basic suite of tests, including coverage for the new behavior.
This commit is contained in:
Martin Atkins 2019-02-01 08:03:07 -08:00
parent 70eeec8083
commit 4c99864dad
2 changed files with 161 additions and 7 deletions

View File

@ -1146,14 +1146,17 @@ func TestCheckModuleResourceAttrPair(mpFirst []string, nameFirst string, keyFirs
}
func testCheckResourceAttrPair(isFirst *terraform.InstanceState, nameFirst string, keyFirst string, isSecond *terraform.InstanceState, nameSecond string, keySecond string) error {
vFirst, ok := isFirst.Attributes[keyFirst]
if !ok {
return fmt.Errorf("%s: Attribute '%s' not found", nameFirst, keyFirst)
vFirst, okFirst := isFirst.Attributes[keyFirst]
vSecond, okSecond := isSecond.Attributes[keySecond]
if okFirst != okSecond {
if !okFirst {
return fmt.Errorf("%s: Attribute %q not set, but %q is set in %s as %q", nameFirst, keyFirst, keySecond, nameSecond, vSecond)
}
return fmt.Errorf("%s: Attribute %q is %q, but %q is not set in %s", nameFirst, keyFirst, vFirst, keySecond, nameSecond)
}
vSecond, ok := isSecond.Attributes[keySecond]
if !ok {
return fmt.Errorf("%s: Attribute '%s' not found", nameSecond, keySecond)
if !(okFirst || okSecond) {
// If they both don't exist then they are equally unset, so that's okay.
return nil
}
if vFirst != vSecond {

View File

@ -1175,3 +1175,154 @@ func TestCheckNoResourceAttr_empty(t *testing.T) {
})
}
}
func TestTestCheckResourceAttrPair(t *testing.T) {
tests := map[string]struct {
state *terraform.State
wantErr string
}{
"exist match": {
&terraform.State{
Modules: []*terraform.ModuleState{
{
Path: []string{"root"},
Resources: map[string]*terraform.ResourceState{
"test.a": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{
"a": "boop",
},
},
},
"test.b": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{
"b": "boop",
},
},
},
},
},
},
},
``,
},
"nonexist match": {
&terraform.State{
Modules: []*terraform.ModuleState{
{
Path: []string{"root"},
Resources: map[string]*terraform.ResourceState{
"test.a": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{},
},
},
"test.b": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{},
},
},
},
},
},
},
``,
},
"exist nonmatch": {
&terraform.State{
Modules: []*terraform.ModuleState{
{
Path: []string{"root"},
Resources: map[string]*terraform.ResourceState{
"test.a": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{
"a": "beep",
},
},
},
"test.b": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{
"b": "boop",
},
},
},
},
},
},
},
`test.a: Attribute 'a' expected "boop", got "beep"`,
},
"inconsistent exist a": {
&terraform.State{
Modules: []*terraform.ModuleState{
{
Path: []string{"root"},
Resources: map[string]*terraform.ResourceState{
"test.a": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{
"a": "beep",
},
},
},
"test.b": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{},
},
},
},
},
},
},
`test.a: Attribute "a" is "beep", but "b" is not set in test.b`,
},
"inconsistent exist b": {
&terraform.State{
Modules: []*terraform.ModuleState{
{
Path: []string{"root"},
Resources: map[string]*terraform.ResourceState{
"test.a": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{},
},
},
"test.b": {
Primary: &terraform.InstanceState{
Attributes: map[string]string{
"b": "boop",
},
},
},
},
},
},
},
`test.a: Attribute "a" not set, but "b" is set in test.b as "boop"`,
},
}
for name, test := range tests {
t.Run(name, func(t *testing.T) {
fn := TestCheckResourceAttrPair("test.a", "a", "test.b", "b")
err := fn(test.state)
if test.wantErr != "" {
if err == nil {
t.Fatalf("succeeded; want error\nwant: %s", test.wantErr)
}
if got, want := err.Error(), test.wantErr; got != want {
t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want)
}
return
}
if err != nil {
t.Fatalf("failed; want success\ngot: %s", err.Error())
}
})
}
}