helper/schema: Final set of ResourceDiff tests, bug fixes

Final set of coverage for ResourceDiff and bug fixes to correct issues
the test cases brought up.

Will be dropping ClearAll in next commit, as with how this interface is
intended to be used, it does not really make much sense.
This commit is contained in:
Chris Marchesi 2017-05-27 18:17:41 -07:00 committed by Martin Atkins
parent a5fc664ea6
commit 22220fd0f7
3 changed files with 581 additions and 99 deletions

View File

@ -32,7 +32,7 @@ func (w *newValueWriter) WriteField(address []string, value interface{}, compute
w.lock.Lock()
defer w.lock.Unlock()
if w.result == nil {
if w.computedKeys == nil {
w.computedKeys = make(map[string]bool)
}
@ -46,7 +46,7 @@ func (w *newValueWriter) WriteField(address []string, value interface{}, compute
func (w *newValueWriter) ComputedKeysMap() map[string]bool {
w.lock.Lock()
defer w.lock.Unlock()
if w.result == nil {
if w.computedKeys == nil {
w.computedKeys = make(map[string]bool)
}
return w.computedKeys
@ -65,12 +65,22 @@ type newValueReader struct {
// ReadField reads the values from the underlying writer, returning the
// computed value if it is found as well.
func (r *newValueReader) ReadField(address []string) (FieldReadResult, error) {
addrKey := strings.Join(address, ".")
v, err := r.MapFieldReader.ReadField(address)
if err != nil {
return FieldReadResult{}, err
}
if _, ok := r.computedKeys[strings.Join(address, ".")]; ok {
v.Computed = true
for computedKey := range r.computedKeys {
if strings.HasPrefix(addrKey, computedKey) {
if strings.HasSuffix(addrKey, ".#") {
// This is a count value for a list or set that has been marked as
// computed, or a sub-list/sub-set of a complex resource that has
// been marked as computed. We need to pass through to other readers
// so that an accurate previous count can be fetched for the diff.
v.Exists = false
}
v.Computed = true
}
}
return v, nil
@ -126,13 +136,7 @@ func newResourceDiff(schema map[string]*Schema, config *terraform.ResourceConfig
config: config,
state: state,
diff: diff,
}
// Duplicate the passed in schema to ensure that any changes we make with
// functions like ForceNew don't affect the referenced schema.
d.schema = make(map[string]*Schema)
for k, v := range schema {
newSchema := *v
d.schema[k] = &newSchema
schema: schema,
}
d.oldWriter = &MapFieldWriter{Schema: d.schema}
@ -215,8 +219,17 @@ func (d *ResourceDiff) ClearAll() {
// any possibility of conflicts, but can be called on its own to just remove a
// specific key from the diff completely.
//
// Note that this does not wipe an override.
// Note that this does not wipe an override. This function is only allowed on
// computed keys.
func (d *ResourceDiff) Clear(key string) error {
if !d.schema[key].Computed {
return fmt.Errorf("Clear is allowed on computed attributes only - %s is not one", key)
}
return d.clear(key)
}
func (d *ResourceDiff) clear(key string) error {
// Check the schema to make sure that this key exists first.
if _, ok := d.schema[key]; !ok {
return fmt.Errorf("%s is not a valid key", key)
@ -233,6 +246,7 @@ func (d *ResourceDiff) Clear(key string) error {
// from ResourceDiff's own change data, in addition to existing diff, config, and state.
func (d *ResourceDiff) diffChange(key string) (interface{}, interface{}, bool, bool) {
old, new := d.getChange(key)
// log.Printf("\nkey:%s\n\nold:%s\n\nnew:%s\n", key, spew.Sdump(old), spew.Sdump(new))
if !old.Exists {
old.Value = nil
@ -262,7 +276,7 @@ func (d *ResourceDiff) SetNew(key string, value interface{}) error {
//
// This function is only allowed on computed keys.
func (d *ResourceDiff) SetNewComputed(key string) error {
return d.SetDiff(key, d.Get(key), d.schema[key].ZeroValue(), true)
return d.SetDiff(key, d.getExact(strings.Split(key, "."), "state").Value, d.schema[key].ZeroValue(), true)
}
// SetDiff allows the setting of both old and new values for the diff
@ -277,7 +291,11 @@ func (d *ResourceDiff) SetDiff(key string, old, new interface{}, computed bool)
return fmt.Errorf("SetNew, SetNewComputed, and SetDiff are allowed on computed attributes only - %s is not one", key)
}
if err := d.Clear(key); err != nil {
return d.setDiff(key, old, new, computed)
}
func (d *ResourceDiff) setDiff(key string, old, new interface{}, computed bool) error {
if err := d.clear(key); err != nil {
return err
}
@ -298,8 +316,7 @@ func (d *ResourceDiff) SetDiff(key string, old, new interface{}, computed bool)
// re-calculates its diff. This function is a no-op/error if there is no diff.
//
// Note that the change to schema is permanent for the lifecycle of this
// specific ResourceDiff instance, until ClearAll or Reset is called to start
// anew.
// specific ResourceDiff instance.
func (d *ResourceDiff) ForceNew(key string) error {
if !d.HasChange(key) {
return fmt.Errorf("ResourceDiff.ForceNew: No changes for %s", key)
@ -307,7 +324,7 @@ func (d *ResourceDiff) ForceNew(key string) error {
old, new := d.GetChange(key)
d.schema[key].ForceNew = true
return d.SetDiff(key, old, new, false)
return d.setDiff(key, old, new, false)
}
// Get hands off to ResourceData.Get.

View File

@ -19,19 +19,24 @@ func testSetFunc(v interface{}) int {
return m["foo"].(int) + m["bar"].(int)
}
func TestSetNew(t *testing.T) {
testCases := []struct {
Name string
Schema map[string]*Schema
State *terraform.InstanceState
Config *terraform.ResourceConfig
Diff *terraform.InstanceDiff
Key string
NewValue interface{}
Expected *terraform.InstanceDiff
ExpectedError bool
}{
{
// resourceDiffTestCase provides a test case struct for SetNew and SetDiff.
type resourceDiffTestCase struct {
Name string
Schema map[string]*Schema
State *terraform.InstanceState
Config *terraform.ResourceConfig
Diff *terraform.InstanceDiff
Key string
OldValue interface{}
NewValue interface{}
Expected *terraform.InstanceDiff
ExpectedError bool
}
// testDiffCases produces a list of test cases for use with SetNew and SetDiff.
func testDiffCases(t *testing.T, oldPrefix string, oldOffset int, computed bool) []resourceDiffTestCase {
return []resourceDiffTestCase{
resourceDiffTestCase{
Name: "basic primitive diff",
Schema: map[string]*Schema{
"foo": &Schema{
@ -57,17 +62,24 @@ func TestSetNew(t *testing.T) {
},
},
Key: "foo",
OldValue: fmt.Sprintf("%sbar", oldPrefix),
NewValue: "qux",
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "qux",
Old: fmt.Sprintf("%sbar", oldPrefix),
New: func() string {
if computed {
return ""
}
return "qux"
}(),
NewComputed: computed,
},
},
},
},
{
resourceDiffTestCase{
Name: "basic set diff",
Schema: map[string]*Schema{
"foo": &Schema{
@ -101,22 +113,33 @@ func TestSetNew(t *testing.T) {
},
},
Key: "foo",
OldValue: []interface{}{fmt.Sprintf("%sbar", oldPrefix)},
NewValue: []interface{}{"qux"},
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo.1996459178": &terraform.ResourceAttrDiff{
Old: "bar",
New: "",
NewRemoved: true,
},
"foo.2800005064": &terraform.ResourceAttrDiff{
Old: "",
New: "qux",
},
},
Attributes: func() map[string]*terraform.ResourceAttrDiff {
result := map[string]*terraform.ResourceAttrDiff{}
if computed {
result["foo.#"] = &terraform.ResourceAttrDiff{
Old: "1",
New: "",
NewComputed: true,
}
} else {
result["foo.2800005064"] = &terraform.ResourceAttrDiff{
Old: "",
New: "qux",
}
result[fmt.Sprintf("foo.%d", HashString(fmt.Sprintf("%sbar", oldPrefix)))] = &terraform.ResourceAttrDiff{
Old: fmt.Sprintf("%sbar", oldPrefix),
New: "",
NewRemoved: true,
}
}
return result
}(),
},
},
{
resourceDiffTestCase{
Name: "basic list diff",
Schema: map[string]*Schema{
"foo": &Schema{
@ -144,17 +167,28 @@ func TestSetNew(t *testing.T) {
},
},
Key: "foo",
OldValue: []interface{}{fmt.Sprintf("%sbar", oldPrefix)},
NewValue: []interface{}{"qux"},
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo.0": &terraform.ResourceAttrDiff{
Old: "bar",
New: "qux",
},
},
Attributes: func() map[string]*terraform.ResourceAttrDiff {
result := make(map[string]*terraform.ResourceAttrDiff)
if computed {
result["foo.#"] = &terraform.ResourceAttrDiff{
Old: "1",
New: "",
NewComputed: true,
}
} else {
result["foo.0"] = &terraform.ResourceAttrDiff{
Old: fmt.Sprintf("%sbar", oldPrefix),
New: "qux",
}
}
return result
}(),
},
},
{
resourceDiffTestCase{
Name: "basic map diff",
Schema: map[string]*Schema{
"foo": &Schema{
@ -181,17 +215,33 @@ func TestSetNew(t *testing.T) {
},
},
Key: "foo",
OldValue: map[string]interface{}{"bar": fmt.Sprintf("%sbaz", oldPrefix)},
NewValue: map[string]interface{}{"bar": "quux"},
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo.bar": &terraform.ResourceAttrDiff{
Old: "baz",
New: "quux",
},
},
Attributes: func() map[string]*terraform.ResourceAttrDiff {
result := make(map[string]*terraform.ResourceAttrDiff)
if computed {
result["foo.%"] = &terraform.ResourceAttrDiff{
Old: "",
New: "",
NewComputed: true,
}
result["foo.bar"] = &terraform.ResourceAttrDiff{
Old: "baz",
New: "",
NewRemoved: true,
}
} else {
result["foo.bar"] = &terraform.ResourceAttrDiff{
Old: fmt.Sprintf("%sbaz", oldPrefix),
New: "quux",
}
}
return result
}(),
},
},
{
resourceDiffTestCase{
Name: "additional diff with primitive",
Schema: map[string]*Schema{
"foo": &Schema{
@ -212,7 +262,6 @@ func TestSetNew(t *testing.T) {
},
Config: testConfig(t, map[string]interface{}{
"foo": "baz",
"one": "three",
}),
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
@ -220,13 +269,10 @@ func TestSetNew(t *testing.T) {
Old: "bar",
New: "baz",
},
"one": &terraform.ResourceAttrDiff{
Old: "two",
New: "three",
},
},
},
Key: "one",
OldValue: fmt.Sprintf("%stwo", oldPrefix),
NewValue: "four",
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
@ -235,13 +281,19 @@ func TestSetNew(t *testing.T) {
New: "baz",
},
"one": &terraform.ResourceAttrDiff{
Old: "two",
New: "four",
Old: fmt.Sprintf("%stwo", oldPrefix),
New: func() string {
if computed {
return ""
}
return "four"
}(),
NewComputed: computed,
},
},
},
},
{
resourceDiffTestCase{
Name: "additional diff with primitive computed only",
Schema: map[string]*Schema{
"foo": &Schema{
@ -271,6 +323,7 @@ func TestSetNew(t *testing.T) {
},
},
Key: "one",
OldValue: fmt.Sprintf("%stwo", oldPrefix),
NewValue: "three",
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
@ -279,13 +332,19 @@ func TestSetNew(t *testing.T) {
New: "baz",
},
"one": &terraform.ResourceAttrDiff{
Old: "two",
New: "three",
Old: fmt.Sprintf("%stwo", oldPrefix),
New: func() string {
if computed {
return ""
}
return "three"
}(),
NewComputed: computed,
},
},
},
},
{
resourceDiffTestCase{
Name: "complex-ish set diff",
Schema: map[string]*Schema{
"top": &Schema{
@ -351,6 +410,16 @@ func TestSetNew(t *testing.T) {
},
},
Key: "top",
OldValue: NewSet(testSetFunc, []interface{}{
map[string]interface{}{
"foo": 1,
"bar": 4 + oldOffset,
},
map[string]interface{}{
"foo": 13 + oldOffset,
"bar": 12,
},
}),
NewValue: NewSet(testSetFunc, []interface{}{
map[string]interface{}{
"foo": 1,
@ -365,47 +434,429 @@ func TestSetNew(t *testing.T) {
"bar": 22,
},
}),
Expected: &terraform.InstanceDiff{
Attributes: func() map[string]*terraform.ResourceAttrDiff {
result := make(map[string]*terraform.ResourceAttrDiff)
if computed {
result["top.#"] = &terraform.ResourceAttrDiff{
Old: "2",
New: "",
NewComputed: true,
}
} else {
result["top.#"] = &terraform.ResourceAttrDiff{
Old: "2",
New: "3",
}
result["top.5.foo"] = &terraform.ResourceAttrDiff{
Old: "",
New: "1",
}
result["top.5.bar"] = &terraform.ResourceAttrDiff{
Old: "",
New: "4",
}
result["top.25.foo"] = &terraform.ResourceAttrDiff{
Old: "",
New: "13",
}
result["top.25.bar"] = &terraform.ResourceAttrDiff{
Old: "",
New: "12",
}
result["top.43.foo"] = &terraform.ResourceAttrDiff{
Old: "",
New: "21",
}
result["top.43.bar"] = &terraform.ResourceAttrDiff{
Old: "",
New: "22",
}
}
return result
}(),
},
},
resourceDiffTestCase{
Name: "primitive, no diff, no refresh",
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeString,
Computed: true,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"foo": "bar",
},
},
Config: testConfig(t, map[string]interface{}{}),
Diff: &terraform.InstanceDiff{Attributes: map[string]*terraform.ResourceAttrDiff{}},
Key: "foo",
OldValue: fmt.Sprintf("%sbar", oldPrefix),
NewValue: "baz",
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"top.#": &terraform.ResourceAttrDiff{
Old: "2",
New: "3",
},
"top.5.foo": &terraform.ResourceAttrDiff{
Old: "",
New: "1",
},
"top.5.bar": &terraform.ResourceAttrDiff{
Old: "",
New: "4",
},
"top.25.foo": &terraform.ResourceAttrDiff{
Old: "",
New: "13",
},
"top.25.bar": &terraform.ResourceAttrDiff{
Old: "",
New: "12",
},
"top.43.foo": &terraform.ResourceAttrDiff{
Old: "",
New: "21",
},
"top.43.bar": &terraform.ResourceAttrDiff{
Old: "",
New: "22",
"foo": &terraform.ResourceAttrDiff{
Old: fmt.Sprintf("%sbar", oldPrefix),
New: func() string {
if computed {
return ""
}
return "baz"
}(),
NewComputed: computed,
},
},
},
},
resourceDiffTestCase{
Name: "non-computed key, should error",
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeString,
Required: true,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"foo": "bar",
},
},
Config: testConfig(t, map[string]interface{}{
"foo": "baz",
}),
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "baz",
},
},
},
Key: "foo",
OldValue: fmt.Sprintf("%sbar", oldPrefix),
NewValue: "qux",
ExpectedError: true,
},
}
}
func TestSetNew(t *testing.T) {
testCases := testDiffCases(t, "", 0, false)
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s", tc.Name), func(t *testing.T) {
t.Run(tc.Name, func(t *testing.T) {
m := schemaMap(tc.Schema)
d := newResourceDiff(tc.Schema, nil, tc.State, tc.Diff)
if err := d.SetNew(tc.Key, tc.NewValue); err != nil {
err := d.SetNew(tc.Key, tc.NewValue)
switch {
case err != nil && !tc.ExpectedError:
t.Fatalf("bad: %s", err)
case err == nil && tc.ExpectedError:
t.Fatalf("Expected error, got none")
case err != nil && tc.ExpectedError:
return
}
for _, k := range d.UpdatedKeys() {
if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {
t.Fatalf("bad: %s", err)
}
}
if !reflect.DeepEqual(tc.Expected, tc.Diff) {
t.Fatalf("Expected %s, got %s", spew.Sdump(tc.Expected), spew.Sdump(tc.Diff))
}
})
}
}
func TestSetNewComputed(t *testing.T) {
testCases := testDiffCases(t, "", 0, true)
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
m := schemaMap(tc.Schema)
d := newResourceDiff(tc.Schema, nil, tc.State, tc.Diff)
err := d.SetNewComputed(tc.Key)
switch {
case err != nil && !tc.ExpectedError:
t.Fatalf("bad: %s", err)
case err == nil && tc.ExpectedError:
t.Fatalf("Expected error, got none")
case err != nil && tc.ExpectedError:
return
}
for _, k := range d.UpdatedKeys() {
if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {
t.Fatalf("bad: %s", err)
}
}
if !reflect.DeepEqual(tc.Expected, tc.Diff) {
t.Fatalf("Expected %s, got %s", spew.Sdump(tc.Expected), spew.Sdump(tc.Diff))
}
})
}
}
func TestSetDiff(t *testing.T) {
testCases := testDiffCases(t, "testSetDiff", 1, false)
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
m := schemaMap(tc.Schema)
d := newResourceDiff(tc.Schema, nil, tc.State, tc.Diff)
err := d.SetDiff(tc.Key, tc.OldValue, tc.NewValue, false)
switch {
case err != nil && !tc.ExpectedError:
t.Fatalf("bad: %s", err)
case err == nil && tc.ExpectedError:
t.Fatalf("Expected error, got none")
case err != nil && tc.ExpectedError:
return
}
for _, k := range d.UpdatedKeys() {
if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {
t.Fatalf("bad: %s", err)
}
}
if !reflect.DeepEqual(tc.Expected, tc.Diff) {
t.Fatalf("Expected %s, got %s", spew.Sdump(tc.Expected), spew.Sdump(tc.Diff))
}
})
}
}
func TestForceNew(t *testing.T) {
cases := []resourceDiffTestCase{
resourceDiffTestCase{
Name: "basic primitive diff",
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeString,
Optional: true,
Computed: true,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"foo": "bar",
},
},
Config: testConfig(t, map[string]interface{}{
"foo": "baz",
}),
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "baz",
},
},
},
Key: "foo",
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "baz",
RequiresNew: true,
},
},
},
},
resourceDiffTestCase{
Name: "no change, should error",
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeString,
Optional: true,
Computed: true,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"foo": "bar",
},
},
Config: testConfig(t, map[string]interface{}{
"foo": "bar",
}),
ExpectedError: true,
},
resourceDiffTestCase{
Name: "basic primitive, non-computed key",
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeString,
Required: true,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"foo": "bar",
},
},
Config: testConfig(t, map[string]interface{}{
"foo": "baz",
}),
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "baz",
},
},
},
Key: "foo",
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "baz",
RequiresNew: true,
},
},
},
},
}
for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
m := schemaMap(tc.Schema)
d := newResourceDiff(m, nil, tc.State, tc.Diff)
err := d.ForceNew(tc.Key)
switch {
case err != nil && !tc.ExpectedError:
t.Fatalf("bad: %s", err)
case err == nil && tc.ExpectedError:
t.Fatalf("Expected error, got none")
case err != nil && tc.ExpectedError:
return
}
for _, k := range d.UpdatedKeys() {
if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {
t.Fatalf("bad: %s", err)
}
}
if !reflect.DeepEqual(tc.Expected, tc.Diff) {
t.Fatalf("Expected %s, got %s", spew.Sdump(tc.Expected), spew.Sdump(tc.Diff))
}
})
}
}
func TestClear(t *testing.T) {
cases := []resourceDiffTestCase{
resourceDiffTestCase{
Name: "basic primitive diff",
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeString,
Optional: true,
Computed: true,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"foo": "bar",
},
},
Config: testConfig(t, map[string]interface{}{
"foo": "baz",
}),
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "baz",
},
},
},
Key: "foo",
Expected: &terraform.InstanceDiff{Attributes: map[string]*terraform.ResourceAttrDiff{}},
},
resourceDiffTestCase{
Name: "non-computed key, should error",
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeString,
Required: true,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"foo": "bar",
},
},
Config: testConfig(t, map[string]interface{}{
"foo": "baz",
}),
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "baz",
},
},
},
Key: "foo",
ExpectedError: true,
},
resourceDiffTestCase{
Name: "multi-value, one removed",
Schema: map[string]*Schema{
"foo": &Schema{
Type: TypeString,
Optional: true,
Computed: true,
},
"one": &Schema{
Type: TypeString,
Optional: true,
Computed: true,
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"foo": "bar",
"one": "two",
},
},
Config: testConfig(t, map[string]interface{}{
"foo": "baz",
"one": "three",
}),
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "baz",
},
"one": &terraform.ResourceAttrDiff{
Old: "two",
New: "three",
},
},
},
Key: "one",
Expected: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "bar",
New: "baz",
},
},
},
},
}
for _, tc := range cases {
t.Run(tc.Name, func(t *testing.T) {
m := schemaMap(tc.Schema)
d := newResourceDiff(m, nil, tc.State, tc.Diff)
err := d.Clear(tc.Key)
switch {
case err != nil && !tc.ExpectedError:
t.Fatalf("bad: %s", err)
case err == nil && tc.ExpectedError:
t.Fatalf("Expected error, got none")
case err != nil && tc.ExpectedError:
return
}
for _, k := range d.UpdatedKeys() {
if err := m.diff(k, m[k], tc.Diff, d, false); err != nil {

View File

@ -5022,3 +5022,17 @@ func (e errorSort) Swap(i, j int) { e[i], e[j] = e[j], e[i] }
func (e errorSort) Less(i, j int) bool {
return e[i].Error() < e[j].Error()
}
func TestSchemaMapDeepCopy(t *testing.T) {
schema := map[string]*Schema{
"foo": &Schema{
Type: TypeString,
},
}
source := schemaMap(schema)
dest := source.DeepCopy()
dest["foo"].ForceNew = true
if reflect.DeepEqual(source, dest) {
t.Fatalf("source and dest should not match")
}
}