don't count empty containers in diff.Apply

If there were no matching keys, and there was no diff at all, don't set
a zero count for the container. Normally Providers can't reliably detect
empty vs unset here, but there are some cases that worked.
This commit is contained in:
James Bardin 2019-01-23 19:17:10 -05:00
parent 37b5e2dc87
commit 7dd0acc46b
2 changed files with 109 additions and 13 deletions

View File

@ -24,9 +24,95 @@ resource "test_resource" "foo" {
} }
} }
`), `),
Check: func(s *terraform.State) error { Check: resource.ComposeTestCheckFunc(
return nil resource.TestCheckNoResourceAttr(
}, "test_resource.foo", "list.#",
),
),
},
},
})
}
func TestResource_changedList(t *testing.T) {
resource.UnitTest(t, resource.TestCase{
Providers: testAccProviders,
CheckDestroy: testAccCheckResourceDestroy,
Steps: []resource.TestStep{
{
Config: strings.TrimSpace(`
resource "test_resource" "foo" {
required = "yep"
required_map = {
key = "value"
}
}
`),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckNoResourceAttr(
"test_resource.foo", "list.#",
),
),
},
{
Config: strings.TrimSpace(`
resource "test_resource" "foo" {
required = "yep"
required_map = {
key = "value"
}
list = ["a"]
}
`),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"test_resource.foo", "list.#", "1",
),
resource.TestCheckResourceAttr(
"test_resource.foo", "list.0", "a",
),
),
},
{
Config: strings.TrimSpace(`
resource "test_resource" "foo" {
required = "yep"
required_map = {
key = "value"
}
list = ["a", "b"]
}
`),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"test_resource.foo", "list.#", "2",
),
resource.TestCheckResourceAttr(
"test_resource.foo", "list.0", "a",
),
resource.TestCheckResourceAttr(
"test_resource.foo", "list.1", "b",
),
),
},
{
Config: strings.TrimSpace(`
resource "test_resource" "foo" {
required = "yep"
required_map = {
key = "value"
}
list = ["b"]
}
`),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(
"test_resource.foo", "list.#", "1",
),
resource.TestCheckResourceAttr(
"test_resource.foo", "list.0", "b",
),
),
}, },
}, },
}) })
@ -165,9 +251,6 @@ resource "test_resource" "foo" {
} }
} }
`), `),
Check: func(s *terraform.State) error {
return nil
},
}, },
resource.TestStep{ resource.TestStep{
Config: strings.TrimSpace(` Config: strings.TrimSpace(`

View File

@ -454,10 +454,10 @@ func (d *InstanceDiff) Apply(attrs map[string]string, schema *configschema.Block
return result, nil return result, nil
} }
return d.blockDiff(nil, attrs, schema) return d.applyBlockDiff(nil, attrs, schema)
} }
func (d *InstanceDiff) blockDiff(path []string, attrs map[string]string, schema *configschema.Block) (map[string]string, error) { func (d *InstanceDiff) applyBlockDiff(path []string, attrs map[string]string, schema *configschema.Block) (map[string]string, error) {
result := map[string]string{} result := map[string]string{}
name := "" name := ""
@ -564,7 +564,7 @@ func (d *InstanceDiff) blockDiff(path []string, attrs map[string]string, schema
} }
for k := range candidateKeys { for k := range candidateKeys {
newAttrs, err := d.blockDiff(append(path, n, k), attrs, &block.Block) newAttrs, err := d.applyBlockDiff(append(path, n, k), attrs, &block.Block)
if err != nil { if err != nil {
return result, err return result, err
} }
@ -735,24 +735,37 @@ func (d *InstanceDiff) applyCollectionDiff(path []string, attrs map[string]strin
} }
// collect all the keys from the diff and the old state // collect all the keys from the diff and the old state
noDiff := true
keys := map[string]bool{} keys := map[string]bool{}
for k := range d.Attributes { for k := range d.Attributes {
if !strings.HasPrefix(k, currentKey+".") {
continue
}
noDiff = false
keys[k] = true keys[k] = true
} }
noAttrs := true
for k := range attrs { for k := range attrs {
if !strings.HasPrefix(k, currentKey+".") {
continue
}
noAttrs = false
keys[k] = true keys[k] = true
} }
// If there's no diff and no attrs, then there's no value at all.
// This prevents an unexpected zero-count attribute in the attributes.
if noDiff && noAttrs {
return result, nil
}
idx := "#" idx := "#"
if attrSchema.Type.IsMapType() { if attrSchema.Type.IsMapType() {
idx = "%" idx = "%"
} }
for k := range keys { for k := range keys {
if !strings.HasPrefix(k, currentKey+".") {
continue
}
// generate an schema placeholder for the values // generate an schema placeholder for the values
elSchema := &configschema.Attribute{ elSchema := &configschema.Attribute{
Type: attrSchema.Type.ElementType(), Type: attrSchema.Type.ElementType(),