replace testDiffFn and testApplyFn
Replace the old mock provider test functions with modern equivalents. There were a lot of inconsistencies in how they were used, so we needed to update a lot of tests to match the correct behavior.
This commit is contained in:
parent
ca7b5bc28b
commit
0a6853a3f8
File diff suppressed because it is too large
Load Diff
|
@ -30,7 +30,14 @@ func TestContext2Input_provider(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ResourceTypes: map[string]*configschema.Block{
|
ResourceTypes: map[string]*configschema.Block{
|
||||||
"aws_instance": {},
|
"aws_instance": {
|
||||||
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"id": {
|
||||||
|
Type: cty.String,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,7 +105,14 @@ func TestContext2Input_providerMulti(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ResourceTypes: map[string]*configschema.Block{
|
ResourceTypes: map[string]*configschema.Block{
|
||||||
"aws_instance": {},
|
"aws_instance": {
|
||||||
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"id": {
|
||||||
|
Type: cty.String,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,25 +173,6 @@ func TestContext2Input_providerOnce(t *testing.T) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
//count := 0
|
|
||||||
/*p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
||||||
count++
|
|
||||||
_, set := c.Config["from_input"]
|
|
||||||
|
|
||||||
if count == 1 {
|
|
||||||
if set {
|
|
||||||
return nil, errors.New("from_input should not be set")
|
|
||||||
}
|
|
||||||
c.Config["from_input"] = "x"
|
|
||||||
}
|
|
||||||
|
|
||||||
if count > 1 && !set {
|
|
||||||
return nil, errors.New("from_input should be set")
|
|
||||||
}
|
|
||||||
|
|
||||||
return c, nil
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if diags := ctx.Input(InputModeStd); diags.HasErrors() {
|
if diags := ctx.Input(InputModeStd); diags.HasErrors() {
|
||||||
t.Fatalf("input errors: %s", diags.Err())
|
t.Fatalf("input errors: %s", diags.Err())
|
||||||
}
|
}
|
||||||
|
@ -202,7 +197,14 @@ func TestContext2Input_providerId(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ResourceTypes: map[string]*configschema.Block{
|
ResourceTypes: map[string]*configschema.Block{
|
||||||
"aws_instance": {},
|
"aws_instance": {
|
||||||
|
Attributes: map[string]*configschema.Attribute{
|
||||||
|
"id": {
|
||||||
|
Type: cty.String,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -726,6 +726,7 @@ func TestContext2Refresh_output(t *testing.T) {
|
||||||
"foo": {
|
"foo": {
|
||||||
Type: cty.String,
|
Type: cty.String,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,16 +5,13 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
"github.com/hashicorp/go-version"
|
"github.com/hashicorp/go-version"
|
||||||
|
@ -22,7 +19,6 @@ import (
|
||||||
"github.com/hashicorp/terraform/configs/configload"
|
"github.com/hashicorp/terraform/configs/configload"
|
||||||
"github.com/hashicorp/terraform/configs/configschema"
|
"github.com/hashicorp/terraform/configs/configschema"
|
||||||
"github.com/hashicorp/terraform/configs/hcl2shim"
|
"github.com/hashicorp/terraform/configs/hcl2shim"
|
||||||
"github.com/hashicorp/terraform/flatmap"
|
|
||||||
"github.com/hashicorp/terraform/plans"
|
"github.com/hashicorp/terraform/plans"
|
||||||
"github.com/hashicorp/terraform/plans/planfile"
|
"github.com/hashicorp/terraform/plans/planfile"
|
||||||
"github.com/hashicorp/terraform/providers"
|
"github.com/hashicorp/terraform/providers"
|
||||||
|
@ -132,300 +128,98 @@ func testContext2(t *testing.T, opts *ContextOpts) *Context {
|
||||||
return ctx
|
return ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDataApplyFn(
|
func testApplyFn(req providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
|
||||||
info *InstanceInfo,
|
resp.NewState = req.PlannedState
|
||||||
d *InstanceDiff) (*InstanceState, error) {
|
if req.PlannedState.IsNull() {
|
||||||
return testApplyFn(info, new(InstanceState), d)
|
resp.NewState = cty.NullVal(req.PriorState.Type())
|
||||||
}
|
return
|
||||||
|
|
||||||
func testDataDiffFn(
|
|
||||||
info *InstanceInfo,
|
|
||||||
c *ResourceConfig) (*InstanceDiff, error) {
|
|
||||||
return testDiffFn(info, new(InstanceState), c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testApplyFn(
|
|
||||||
info *InstanceInfo,
|
|
||||||
s *InstanceState,
|
|
||||||
d *InstanceDiff) (*InstanceState, error) {
|
|
||||||
if d.Destroy {
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the OLD id, which is probably in the ID field for now, but eventually
|
planned := req.PlannedState.AsValueMap()
|
||||||
// ID should only be in one place.
|
if planned == nil {
|
||||||
id := s.ID
|
planned = map[string]cty.Value{}
|
||||||
if id == "" {
|
|
||||||
id = s.Attributes["id"]
|
|
||||||
}
|
|
||||||
if idAttr, ok := d.Attributes["id"]; ok && !idAttr.NewComputed {
|
|
||||||
id = idAttr.New
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if id == "" || id == hcl2shim.UnknownVariableValue {
|
id, ok := planned["id"]
|
||||||
id = "foo"
|
if !ok || id.IsNull() || !id.IsKnown() {
|
||||||
|
planned["id"] = cty.StringVal("foo")
|
||||||
}
|
}
|
||||||
|
|
||||||
result := &InstanceState{
|
// our default schema has a computed "type" attr
|
||||||
ID: id,
|
if ty, ok := planned["type"]; ok && !ty.IsNull() {
|
||||||
Attributes: make(map[string]string),
|
planned["type"] = cty.StringVal(req.TypeName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy all the prior attributes
|
if cmp, ok := planned["compute"]; ok && !cmp.IsNull() {
|
||||||
for k, v := range s.Attributes {
|
computed := cmp.AsString()
|
||||||
result.Attributes[k] = v
|
if val, ok := planned[computed]; ok && !val.IsKnown() {
|
||||||
|
planned[computed] = cty.StringVal("computed_value")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if d != nil {
|
for k, v := range planned {
|
||||||
result = result.MergeDiff(d)
|
if k == "unknown" {
|
||||||
}
|
// "unknown" should cause an error
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// The id attribute always matches ID for the sake of this mock
|
if !v.IsKnown() {
|
||||||
// implementation, since it's following the pre-0.12 assumptions where
|
switch k {
|
||||||
// these two were treated as synonyms.
|
case "type":
|
||||||
result.Attributes["id"] = result.ID
|
planned[k] = cty.StringVal(req.TypeName)
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func testDiffFn(
|
|
||||||
info *InstanceInfo,
|
|
||||||
s *InstanceState,
|
|
||||||
c *ResourceConfig) (*InstanceDiff, error) {
|
|
||||||
diff := new(InstanceDiff)
|
|
||||||
diff.Attributes = make(map[string]*ResourceAttrDiff)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
log.Printf("[TRACE] testDiffFn: generated diff is:\n%s", spew.Sdump(diff))
|
|
||||||
}()
|
|
||||||
|
|
||||||
if s != nil {
|
|
||||||
diff.DestroyTainted = s.Tainted
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range c.Raw {
|
|
||||||
// Ignore __-prefixed keys since they're used for magic
|
|
||||||
if k[0] == '_' && k[1] == '_' {
|
|
||||||
// ...though we do still need to include them in the diff, to
|
|
||||||
// simulate normal provider behaviors.
|
|
||||||
old := s.Attributes[k]
|
|
||||||
var new string
|
|
||||||
switch tv := v.(type) {
|
|
||||||
case string:
|
|
||||||
new = tv
|
|
||||||
default:
|
default:
|
||||||
new = fmt.Sprintf("%#v", v)
|
planned[k] = cty.NullVal(v.Type())
|
||||||
}
|
|
||||||
if new == hcl2shim.UnknownVariableValue {
|
|
||||||
diff.Attributes[k] = &ResourceAttrDiff{
|
|
||||||
Old: old,
|
|
||||||
New: "",
|
|
||||||
NewComputed: true,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
diff.Attributes[k] = &ResourceAttrDiff{
|
|
||||||
Old: old,
|
|
||||||
New: new,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if k == "nil" {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// This key is used for other purposes
|
|
||||||
if k == "compute_value" {
|
|
||||||
if old, ok := s.Attributes["compute_value"]; !ok || old != v.(string) {
|
|
||||||
diff.Attributes["compute_value"] = &ResourceAttrDiff{
|
|
||||||
Old: old,
|
|
||||||
New: v.(string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if k == "compute" {
|
|
||||||
// The "compute" value itself must be included in the diff if it
|
|
||||||
// has changed since prior.
|
|
||||||
if old, ok := s.Attributes["compute"]; !ok || old != v.(string) {
|
|
||||||
diff.Attributes["compute"] = &ResourceAttrDiff{
|
|
||||||
Old: old,
|
|
||||||
New: v.(string),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if v == hcl2shim.UnknownVariableValue || v == "unknown" {
|
|
||||||
// compute wasn't set in the config, so don't use these
|
|
||||||
// computed values from the schema.
|
|
||||||
delete(c.Raw, k)
|
|
||||||
delete(c.Raw, "compute_value")
|
|
||||||
|
|
||||||
// we need to remove this from the list of ComputedKeys too,
|
|
||||||
// since it would get re-added to the diff further down
|
|
||||||
newComputed := make([]string, 0, len(c.ComputedKeys))
|
|
||||||
for _, ck := range c.ComputedKeys {
|
|
||||||
if ck == "compute" || ck == "compute_value" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
newComputed = append(newComputed, ck)
|
|
||||||
}
|
|
||||||
c.ComputedKeys = newComputed
|
|
||||||
|
|
||||||
if v == "unknown" {
|
|
||||||
diff.Attributes["unknown"] = &ResourceAttrDiff{
|
|
||||||
Old: "",
|
|
||||||
New: "",
|
|
||||||
NewComputed: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ComputedKeys = append(c.ComputedKeys, "unknown")
|
|
||||||
}
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
attrDiff := &ResourceAttrDiff{
|
|
||||||
Old: "",
|
|
||||||
New: "",
|
|
||||||
NewComputed: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
if cv, ok := c.Config["compute_value"]; ok {
|
|
||||||
if cv.(string) == "1" {
|
|
||||||
attrDiff.NewComputed = false
|
|
||||||
attrDiff.New = fmt.Sprintf("computed_%s", v.(string))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff.Attributes[v.(string)] = attrDiff
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this key is not computed, then look it up in the
|
|
||||||
// cleaned config.
|
|
||||||
found := false
|
|
||||||
for _, ck := range c.ComputedKeys {
|
|
||||||
if ck == k {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
v = c.Config[k]
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, attrDiff := range testFlatAttrDiffs(k, v) {
|
|
||||||
// we need to ignore 'id' for now, since it's always inferred to be
|
|
||||||
// computed.
|
|
||||||
if k == "id" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if k == "require_new" {
|
|
||||||
attrDiff.RequiresNew = true
|
|
||||||
}
|
|
||||||
if _, ok := c.Raw["__"+k+"_requires_new"]; ok {
|
|
||||||
attrDiff.RequiresNew = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if attr, ok := s.Attributes[k]; ok {
|
|
||||||
attrDiff.Old = attr
|
|
||||||
}
|
|
||||||
|
|
||||||
diff.Attributes[k] = attrDiff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, k := range c.ComputedKeys {
|
|
||||||
if k == "id" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
old := ""
|
|
||||||
if s != nil {
|
|
||||||
old = s.Attributes[k]
|
|
||||||
}
|
|
||||||
diff.Attributes[k] = &ResourceAttrDiff{
|
|
||||||
Old: old,
|
|
||||||
NewComputed: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we recreate this resource because it's tainted, we keep all attrs
|
|
||||||
if !diff.RequiresNew() {
|
|
||||||
for k, v := range diff.Attributes {
|
|
||||||
if v.NewComputed {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
old, ok := s.Attributes[k]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if old == v.New {
|
|
||||||
delete(diff.Attributes, k)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !diff.Empty() {
|
resp.NewState = cty.ObjectVal(planned)
|
||||||
diff.Attributes["type"] = &ResourceAttrDiff{
|
return
|
||||||
Old: "",
|
|
||||||
New: info.Type,
|
|
||||||
}
|
|
||||||
if s != nil && s.Attributes != nil {
|
|
||||||
diff.Attributes["type"].Old = s.Attributes["type"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return diff, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate ResourceAttrDiffs for nested data structures in tests
|
func testDiffFn(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
|
||||||
func testFlatAttrDiffs(k string, i interface{}) map[string]*ResourceAttrDiff {
|
var planned map[string]cty.Value
|
||||||
diffs := make(map[string]*ResourceAttrDiff)
|
if !req.ProposedNewState.IsNull() {
|
||||||
// check for strings and empty containers first
|
planned = req.ProposedNewState.AsValueMap()
|
||||||
switch t := i.(type) {
|
}
|
||||||
case string:
|
if planned == nil {
|
||||||
diffs[k] = &ResourceAttrDiff{New: t}
|
planned = map[string]cty.Value{}
|
||||||
return diffs
|
}
|
||||||
case map[string]interface{}:
|
|
||||||
if len(t) == 0 {
|
// id is always computed for the tests
|
||||||
diffs[k] = &ResourceAttrDiff{New: ""}
|
if id, ok := planned["id"]; ok && id.IsNull() {
|
||||||
return diffs
|
planned["id"] = cty.UnknownVal(cty.String)
|
||||||
}
|
}
|
||||||
case []interface{}:
|
|
||||||
if len(t) == 0 {
|
// the old tests have require_new replace on every plan
|
||||||
diffs[k] = &ResourceAttrDiff{New: ""}
|
if _, ok := planned["require_new"]; ok {
|
||||||
return diffs
|
resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: "require_new"}})
|
||||||
|
}
|
||||||
|
|
||||||
|
for k := range planned {
|
||||||
|
requiresNewKey := "__" + k + "_requires_new"
|
||||||
|
_, ok := planned[requiresNewKey]
|
||||||
|
if ok {
|
||||||
|
resp.RequiresReplace = append(resp.RequiresReplace, cty.Path{cty.GetAttrStep{Name: requiresNewKey}})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
flat := flatmap.Flatten(map[string]interface{}{k: i})
|
if v, ok := planned["compute"]; ok && !v.IsNull() {
|
||||||
|
k := v.AsString()
|
||||||
for k, v := range flat {
|
unknown := cty.UnknownVal(cty.String)
|
||||||
attrDiff := &ResourceAttrDiff{
|
if strings.HasSuffix(k, ".#") {
|
||||||
Old: "",
|
k = k[:len(k)-2]
|
||||||
New: v,
|
unknown = cty.UnknownVal(cty.List(cty.String))
|
||||||
}
|
}
|
||||||
diffs[k] = attrDiff
|
planned[k] = unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
// The legacy flatmap-based diff producing done by helper/schema would
|
if t, ok := planned["type"]; ok && t.IsNull() {
|
||||||
// additionally insert a k+".%" key here recording the length of the map,
|
planned["type"] = cty.UnknownVal(cty.String)
|
||||||
// which is for some reason not also done by flatmap.Flatten. To make our
|
|
||||||
// mock shims helper/schema-compatible, we'll just fake that up here.
|
|
||||||
switch t := i.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
attrDiff := &ResourceAttrDiff{
|
|
||||||
Old: "",
|
|
||||||
New: strconv.Itoa(len(t)),
|
|
||||||
}
|
|
||||||
diffs[k+".%"] = attrDiff
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return diffs
|
resp.PlannedState = cty.ObjectVal(planned)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func testProvider(prefix string) *MockProvider {
|
func testProvider(prefix string) *MockProvider {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
@ -89,14 +88,12 @@ type MockProvider struct {
|
||||||
CloseCalled bool
|
CloseCalled bool
|
||||||
CloseError error
|
CloseError error
|
||||||
|
|
||||||
// Legacy callbacks: if these are set, we will shim incoming calls for
|
|
||||||
// new-style methods to these old-fashioned terraform.ResourceProvider
|
|
||||||
// mock callbacks, for the benefit of older tests that were written against
|
|
||||||
// the old mock API.
|
|
||||||
ValidateFn func(c *ResourceConfig) (ws []string, es []error)
|
ValidateFn func(c *ResourceConfig) (ws []string, es []error)
|
||||||
ConfigureFn func(c *ResourceConfig) error
|
ConfigureFn func(c *ResourceConfig) error
|
||||||
DiffFn func(info *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error)
|
//ValidateFn func(providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse
|
||||||
ApplyFn func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error)
|
//ConfigureFn func(providers.ConfigureRequest) providers.ConfigureResponse
|
||||||
|
DiffFn func(providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse
|
||||||
|
ApplyFn func(providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MockProvider) GetSchema() providers.GetSchemaResponse {
|
func (p *MockProvider) GetSchema() providers.GetSchemaResponse {
|
||||||
|
@ -297,47 +294,7 @@ func (p *MockProvider) PlanResourceChange(r providers.PlanResourceChangeRequest)
|
||||||
p.PlanResourceChangeRequest = r
|
p.PlanResourceChangeRequest = r
|
||||||
|
|
||||||
if p.DiffFn != nil {
|
if p.DiffFn != nil {
|
||||||
ps := p.getSchema()
|
return p.DiffFn(r)
|
||||||
if ps.ResourceTypes == nil || ps.ResourceTypes[r.TypeName].Block == nil {
|
|
||||||
return providers.PlanResourceChangeResponse{
|
|
||||||
Diagnostics: tfdiags.Diagnostics(nil).Append(fmt.Printf("mock provider has no schema for resource type %s", r.TypeName)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
schema := ps.ResourceTypes[r.TypeName].Block
|
|
||||||
info := &InstanceInfo{
|
|
||||||
Type: r.TypeName,
|
|
||||||
}
|
|
||||||
priorState := NewInstanceStateShimmedFromValue(r.PriorState, 0)
|
|
||||||
cfg := NewResourceConfigShimmed(r.ProposedNewState, schema)
|
|
||||||
|
|
||||||
legacyDiff, err := p.DiffFn(info, priorState, cfg)
|
|
||||||
|
|
||||||
var res providers.PlanResourceChangeResponse
|
|
||||||
res.PlannedState = r.ProposedNewState
|
|
||||||
if err != nil {
|
|
||||||
res.Diagnostics = res.Diagnostics.Append(err)
|
|
||||||
}
|
|
||||||
if legacyDiff != nil {
|
|
||||||
newVal, err := legacyDiff.ApplyToValue(r.PriorState, schema)
|
|
||||||
if err != nil {
|
|
||||||
res.Diagnostics = res.Diagnostics.Append(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
res.PlannedState = newVal
|
|
||||||
|
|
||||||
var requiresNew []string
|
|
||||||
for attr, d := range legacyDiff.Attributes {
|
|
||||||
if d.RequiresNew {
|
|
||||||
requiresNew = append(requiresNew, attr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
requiresReplace, err := hcl2shim.RequiresReplace(requiresNew, schema.ImpliedType())
|
|
||||||
if err != nil {
|
|
||||||
res.Diagnostics = res.Diagnostics.Append(err)
|
|
||||||
}
|
|
||||||
res.RequiresReplace = requiresReplace
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
if p.PlanResourceChangeFn != nil {
|
if p.PlanResourceChangeFn != nil {
|
||||||
return p.PlanResourceChangeFn(r)
|
return p.PlanResourceChangeFn(r)
|
||||||
|
@ -353,90 +310,7 @@ func (p *MockProvider) ApplyResourceChange(r providers.ApplyResourceChangeReques
|
||||||
p.Unlock()
|
p.Unlock()
|
||||||
|
|
||||||
if p.ApplyFn != nil {
|
if p.ApplyFn != nil {
|
||||||
// ApplyFn is a special callback fashioned after our old provider
|
return p.ApplyFn(r)
|
||||||
// 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 == hcl2shim.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)
|
|
||||||
}
|
|
||||||
if newState != nil {
|
|
||||||
var newVal cty.Value
|
|
||||||
if newState != nil {
|
|
||||||
var err error
|
|
||||||
newVal, err = newState.AttrsAsObjectValue(schema.Block.ImpliedType())
|
|
||||||
if err != nil {
|
|
||||||
resp.Diagnostics = resp.Diagnostics.Append(err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If apply returned a nil new state then that's the old way to
|
|
||||||
// indicate that the object was destroyed. Our new interface calls
|
|
||||||
// for that to be signalled as a null value.
|
|
||||||
newVal = cty.NullVal(schema.Block.ImpliedType())
|
|
||||||
}
|
|
||||||
resp.NewState = newVal
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp
|
|
||||||
}
|
}
|
||||||
if p.ApplyResourceChangeFn != nil {
|
if p.ApplyResourceChangeFn != nil {
|
||||||
return p.ApplyResourceChangeFn(r)
|
return p.ApplyResourceChangeFn(r)
|
||||||
|
|
|
@ -414,12 +414,15 @@ aws_instance.bar:
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
aws_instance.foo.2:
|
aws_instance.foo.2:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyProviderAliasStr = `
|
const testTerraformApplyProviderAliasStr = `
|
||||||
|
@ -439,9 +442,11 @@ const testTerraformApplyProviderAliasConfigStr = `
|
||||||
another_instance.bar:
|
another_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/another"].two
|
provider = provider["registry.terraform.io/hashicorp/another"].two
|
||||||
|
type = another_instance
|
||||||
another_instance.foo:
|
another_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/another"]
|
provider = provider["registry.terraform.io/hashicorp/another"]
|
||||||
|
type = another_instance
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyEmptyModuleStr = `
|
const testTerraformApplyEmptyModuleStr = `
|
||||||
|
@ -487,6 +492,7 @@ const testTerraformApplyCancelStr = `
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
value = 2
|
value = 2
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -590,9 +596,11 @@ aws_instance.bar:
|
||||||
aws_instance.foo.0:
|
aws_instance.foo.0:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
aws_instance.foo.1:
|
aws_instance.foo.1:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
`
|
`
|
||||||
const testTerraformApplyForEachVariableStr = `
|
const testTerraformApplyForEachVariableStr = `
|
||||||
aws_instance.foo["b15c6d616d6143248c575900dff57325eb1de498"]:
|
aws_instance.foo["b15c6d616d6143248c575900dff57325eb1de498"]:
|
||||||
|
@ -613,18 +621,22 @@ aws_instance.foo["e30a7edcc42a846684f2a4eea5f3cd261d33c46d"]:
|
||||||
aws_instance.one["a"]:
|
aws_instance.one["a"]:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
aws_instance.one["b"]:
|
aws_instance.one["b"]:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
aws_instance.two["a"]:
|
aws_instance.two["a"]:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.one
|
aws_instance.one
|
||||||
aws_instance.two["b"]:
|
aws_instance.two["b"]:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.one`
|
aws_instance.one`
|
||||||
|
@ -632,9 +644,11 @@ const testTerraformApplyMinimalStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyModuleStr = `
|
const testTerraformApplyModuleStr = `
|
||||||
|
@ -688,9 +702,11 @@ module.child:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
test_instance.foo:
|
test_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/test"]
|
provider = provider["registry.terraform.io/hashicorp/test"]
|
||||||
|
type = test_instance
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyModuleProviderAliasStr = `
|
const testTerraformApplyModuleProviderAliasStr = `
|
||||||
|
@ -699,6 +715,7 @@ module.child:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = module.child.provider["registry.terraform.io/hashicorp/aws"].eu
|
provider = module.child.provider["registry.terraform.io/hashicorp/aws"].eu
|
||||||
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyModuleVarRefExistingStr = `
|
const testTerraformApplyModuleVarRefExistingStr = `
|
||||||
|
@ -706,6 +723,7 @@ aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
foo = bar
|
foo = bar
|
||||||
|
type = aws_instance
|
||||||
|
|
||||||
module.child:
|
module.child:
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
|
@ -733,6 +751,7 @@ const testTerraformApplyProvisionerStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
|
@ -752,12 +771,14 @@ module.child:
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyProvisionerFailStr = `
|
const testTerraformApplyProvisionerFailStr = `
|
||||||
aws_instance.bar: (tainted)
|
aws_instance.bar: (tainted)
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
@ -769,6 +790,7 @@ const testTerraformApplyProvisionerFailCreateStr = `
|
||||||
aws_instance.bar: (tainted)
|
aws_instance.bar: (tainted)
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyProvisionerFailCreateNoIdStr = `
|
const testTerraformApplyProvisionerFailCreateNoIdStr = `
|
||||||
|
@ -850,14 +872,16 @@ const testTerraformApplyDestroyStr = `
|
||||||
|
|
||||||
const testTerraformApplyErrorStr = `
|
const testTerraformApplyErrorStr = `
|
||||||
aws_instance.bar: (tainted)
|
aws_instance.bar: (tainted)
|
||||||
ID = bar
|
ID =
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
foo = 2
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
value = 2
|
value = 2
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -866,6 +890,7 @@ aws_instance.bar:
|
||||||
ID = bar
|
ID = bar
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
require_new = abc
|
require_new = abc
|
||||||
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
|
||||||
const testTerraformApplyErrorDestroyCreateBeforeDestroyStr = `
|
const testTerraformApplyErrorDestroyCreateBeforeDestroyStr = `
|
||||||
|
@ -881,12 +906,14 @@ const testTerraformApplyErrorPartialStr = `
|
||||||
aws_instance.bar:
|
aws_instance.bar:
|
||||||
ID = bar
|
ID = bar
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
aws_instance.foo
|
aws_instance.foo
|
||||||
aws_instance.foo:
|
aws_instance.foo:
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
|
type = aws_instance
|
||||||
value = 2
|
value = 2
|
||||||
`
|
`
|
||||||
|
|
||||||
|
@ -1107,7 +1134,6 @@ const testTerraformApplyUnknownAttrStr = `
|
||||||
aws_instance.foo: (tainted)
|
aws_instance.foo: (tainted)
|
||||||
ID = foo
|
ID = foo
|
||||||
provider = provider["registry.terraform.io/hashicorp/aws"]
|
provider = provider["registry.terraform.io/hashicorp/aws"]
|
||||||
compute = unknown
|
|
||||||
num = 2
|
num = 2
|
||||||
type = aws_instance
|
type = aws_instance
|
||||||
`
|
`
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
variable "require_new" {
|
||||||
|
type = string
|
||||||
|
}
|
||||||
|
|
||||||
resource "aws_instance" "web" {
|
resource "aws_instance" "web" {
|
||||||
// require_new is a special attribute recognized by testDiffFn that forces
|
// require_new is a special attribute recognized by testDiffFn that forces
|
||||||
// a new resource on every apply
|
// a new resource on every apply
|
||||||
require_new = "yes"
|
require_new = var.require_new
|
||||||
lifecycle {
|
lifecycle {
|
||||||
create_before_destroy = true
|
create_before_destroy = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
resource "aws_instance" "foo" {
|
resource "aws_instance" "foo" {
|
||||||
num = "2"
|
num = "2"
|
||||||
compute = "unknown"
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue