From a7680ad175bc2baa020fe78736c39a10461bf9e6 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Fri, 7 Sep 2018 12:19:27 -0700 Subject: [PATCH] core: Shim to old p.ApplyFn interface in MockProvider This is a pretty basic attempt to turn a pair of values into an old-school diff. It probably won't work correctly for all tests, but hopefully works well enough that we can just update the remaining tests in-place to use the new API directly. --- terraform/provider_mock.go | 77 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/terraform/provider_mock.go b/terraform/provider_mock.go index 502177bfe..e5fc2e9ec 100644 --- a/terraform/provider_mock.go +++ b/terraform/provider_mock.go @@ -7,6 +7,7 @@ import ( "github.com/zclconf/go-cty/cty" + "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config/hcl2shim" "github.com/hashicorp/terraform/providers" "github.com/hashicorp/terraform/tfdiags" @@ -286,10 +287,80 @@ func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeReques p.ApplyResourceChangeRequest = r p.Unlock() - if p.DiffFn != nil { - return providers.ApplyResourceChangeResponse{ - Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("legacy ApplyFn handling in MockProvider not actually implemented yet")), + if p.ApplyFn != nil { + // ApplyFn is a special callback fashioned after our old provider + // interface, which expected to be given an actual diff rather than + // separate old/new values to apply. Therefore we need to approximate + // a diff here well enough that _most_ of our legacy ApplyFns in old + // tests still see the behavior they are expecting. New tests should + // not use this, and should instead use ApplyResourceChangeFn directly. + providerSchema := p.GetSchema() + schema, ok := providerSchema.ResourceTypes[r.TypeName] + if !ok { + return providers.ApplyResourceChangeResponse{ + Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Errorf("no mocked schema available for resource type %s", r.TypeName)), + } } + + info := &InstanceInfo{ + Type: r.TypeName, + } + + priorVal := r.PriorState + plannedVal := r.PlannedState + priorMap := hcl2shim.FlatmapValueFromHCL2(priorVal) + plannedMap := hcl2shim.FlatmapValueFromHCL2(plannedVal) + s := NewInstanceStateShimmedFromValue(priorVal, 0) + d := &InstanceDiff{ + Attributes: make(map[string]*ResourceAttrDiff), + } + if plannedMap == nil { // destroying, then + d.Destroy = true + // Destroy diffs don't have any attribute diffs + } else { + if priorMap == nil { // creating, then + // We'll just make an empty prior map to make things easier below. + priorMap = make(map[string]string) + } + + for k, new := range plannedMap { + old := priorMap[k] + newComputed := false + if new == config.UnknownVariableValue { + new = "" + newComputed = true + } + d.Attributes[k] = &ResourceAttrDiff{ + Old: old, + New: new, + NewComputed: newComputed, + Type: DiffAttrInput, // not generally used in tests, so just hard-coded + } + } + // Also need any attributes that were removed in "planned" + for k, old := range priorMap { + if _, ok := plannedMap[k]; ok { + continue + } + d.Attributes[k] = &ResourceAttrDiff{ + Old: old, + NewRemoved: true, + Type: DiffAttrInput, + } + } + } + newState, err := p.ApplyFn(info, s, d) + resp := providers.ApplyResourceChangeResponse{} + if err != nil { + resp.Diagnostics = resp.Diagnostics.Append(err) + } + newVal, err := newState.AttrsAsObjectValue(schema.Block.ImpliedType()) + if err != nil { + resp.Diagnostics = resp.Diagnostics.Append(err) + } + resp.NewState = newVal + + return resp } if p.ApplyResourceChangeFn != nil { return p.ApplyResourceChangeFn(r)