updating context plan test

This commit is contained in:
James Bardin 2018-09-14 18:40:09 -04:00 committed by Martin Atkins
parent b738cdb19f
commit f63bba78c9
3 changed files with 600 additions and 218 deletions

View File

@ -10,6 +10,12 @@ import (
"sync" "sync"
"testing" "testing"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/plans"
"github.com/hashicorp/terraform/states"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
@ -49,10 +55,32 @@ func TestContext2Plan_basic(t *testing.T) {
t.Errorf("wrong ProviderSHA256s %#v; want %#v", plan.ProviderSHA256s, ctx.providerSHA256s) t.Errorf("wrong ProviderSHA256s %#v; want %#v", plan.ProviderSHA256s, ctx.providerSHA256s)
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) if !ctx.State().Empty() {
expected := strings.TrimSpace(testTerraformPlanStr) t.Fatalf("expected empty state, got %#v\n", ctx.State())
if actual != expected { }
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
ty := schema.ImpliedType()
for _, r := range plan.Changes.Resources {
val, err := r.Decode(ty)
if err != nil {
t.Fatal(err)
}
switch i := val.Addr.String(); i {
case "aws_instance.bar":
foo := val.After.GetAttr("foo").AsString()
if foo != "2" {
t.Fatalf("incorrect plan for 'bar': %#v", val.After)
}
case "aws_instance.foo":
num, _ := val.After.GetAttr("num").AsBigFloat().Int64()
if num != 3 {
t.Fatalf("incorrect plan for 'foo': %#v", val.After)
}
default:
t.Fatal("unknown instance:", i)
}
} }
} }
@ -70,9 +98,17 @@ func TestContext2Plan_createBefore_deposed(t *testing.T) {
Type: "aws_instance", Type: "aws_instance",
Primary: &InstanceState{ Primary: &InstanceState{
ID: "baz", ID: "baz",
Attributes: map[string]string{
"id": "baz",
},
}, },
Deposed: []*InstanceState{ Deposed: []*InstanceState{
&InstanceState{ID: "foo"}, &InstanceState{
ID: "foo",
Attributes: map[string]string{
"id": "foo",
},
},
}, },
}, },
}, },
@ -95,21 +131,37 @@ func TestContext2Plan_createBefore_deposed(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) // the state should still show one deposed
expected := strings.TrimSpace(` expectedState := strings.TrimSpace(`
DIFF: aws_instance.foo: (1 deposed)
DESTROY: aws_instance.foo (deposed only)
STATE:
aws_instance.foo: (1 deposed)
ID = baz ID = baz
Deposed ID 1 = foo provider = provider.aws
`) Deposed ID 00000001 = foo`)
if actual != expected {
t.Fatalf("expected:\n%s, got:\n%s", expected, actual) if ctx.State().String() != expectedState {
t.Fatalf("\nexpected: %q\ngot: %q\n", expectedState, ctx.State().String())
} }
schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
ty := schema.ImpliedType()
res := plan.Changes.Resources[0]
if res.DeposedKey != states.NotDeposed {
t.Fatal("primary resource should not be deposed")
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
// the existing instance should only have an unchanged id
expected, err := schema.CoerceValue(cty.ObjectVal(map[string]cty.Value{"id": cty.StringVal("baz")}))
if err != nil {
t.Fatal(err)
}
checkVals(t, expected, val.After)
} }
func TestContext2Plan_createBefore_maintainRoot(t *testing.T) { func TestContext2Plan_createBefore_maintainRoot(t *testing.T) {
@ -136,21 +188,19 @@ func TestContext2Plan_createBefore_maintainRoot(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) if !ctx.State().Empty() {
expected := strings.TrimSpace(` t.Fatal("expected empty state, got:", ctx.State())
DIFF: }
CREATE: aws_instance.bar.0 if len(plan.Changes.Resources) != 4 {
CREATE: aws_instance.bar.1 t.Error("expected 4 resource in plan, got", len(plan.Changes.Resources))
CREATE: aws_instance.foo.0 }
CREATE: aws_instance.foo.1
STATE: for _, res := range plan.Changes.Resources {
// these should all be creates
<no state> if res.Action != plans.Create {
`) t.Fatalf("unexpected action %s for %s", res.Action, res.Addr.String())
if actual != expected { }
t.Fatalf("expected:\n%s, got:\n%s", expected, actual)
} }
} }
@ -178,10 +228,26 @@ func TestContext2Plan_emptyDiff(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) if !ctx.State().Empty() {
expected := strings.TrimSpace(testTerraformPlanEmptyStr) t.Fatal("expected empty state, got:", ctx.State())
if actual != expected { }
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
if len(plan.Changes.Resources) != 2 {
t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources))
}
actions := map[string]plans.Action{}
for _, res := range plan.Changes.Resources {
actions[res.Addr.String()] = res.Action
}
expected := map[string]plans.Action{
"aws_instance.foo": plans.Create,
"aws_instance.bar": plans.Create,
}
if !cmp.Equal(expected, actions) {
t.Fatal(cmp.Diff(expected, actions))
} }
} }
@ -203,11 +269,30 @@ func TestContext2Plan_escapedVar(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) if len(plan.Changes.Resources) != 1 {
expected := strings.TrimSpace(testTerraformPlanEscapedVarStr) t.Error("expected 1 resource in plan, got", len(plan.Changes.Resources))
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
} }
res := plan.Changes.Resources[0]
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
ty := schema.ImpliedType()
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
expected := objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.StringVal("bar-${baz}"),
"type": cty.StringVal("aws_instance")},
)
checkVals(t, expected, val.After)
} }
func TestContext2Plan_minimal(t *testing.T) { func TestContext2Plan_minimal(t *testing.T) {
@ -228,10 +313,26 @@ func TestContext2Plan_minimal(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) if !ctx.State().Empty() {
expected := strings.TrimSpace(testTerraformPlanEmptyStr) t.Fatal("expected empty state, got:", ctx.State())
if actual != expected { }
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
if len(plan.Changes.Resources) != 2 {
t.Error("expected 2 resource in plan, got", len(plan.Changes.Resources))
}
actions := map[string]plans.Action{}
for _, res := range plan.Changes.Resources {
actions[res.Addr.String()] = res.Action
}
expected := map[string]plans.Action{
"aws_instance.foo": plans.Create,
"aws_instance.bar": plans.Create,
}
if !cmp.Equal(expected, actions) {
t.Fatal(cmp.Diff(expected, actions))
} }
} }
@ -253,10 +354,47 @@ func TestContext2Plan_modules(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) if len(plan.Changes.Resources) != 3 {
expected := strings.TrimSpace(testTerraformPlanModulesStr) t.Error("expected 3 resource in plan, got", len(plan.Changes.Resources))
if actual != expected { }
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
ty := schema.ImpliedType()
expectFoo := objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.StringVal("2"),
"type": cty.StringVal("aws_instance")},
)
expectNum := objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"num": cty.NumberIntVal(2),
"type": cty.StringVal("aws_instance")},
)
for _, res := range plan.Changes.Resources {
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
var expected cty.Value
switch i := val.Addr.String(); i {
case "aws_instance.bar":
expected = expectFoo
case "aws_instance.foo":
expected = expectNum
case "module.child.aws_instance.foo":
expected = expectNum
default:
t.Fatal("unknown instance:", i)
}
checkVals(t, expected, val.After)
} }
} }
@ -270,6 +408,7 @@ func TestContext2Plan_moduleCycle(t *testing.T) {
Attributes: map[string]*configschema.Attribute{ Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Computed: true}, "id": {Type: cty.String, Computed: true},
"some_input": {Type: cty.String, Optional: true}, "some_input": {Type: cty.String, Optional: true},
"type": {Type: cty.String, Optional: true},
}, },
}, },
}, },
@ -290,10 +429,39 @@ func TestContext2Plan_moduleCycle(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
expected := strings.TrimSpace(testTerraformPlanModuleCycleStr) ty := schema.ImpliedType()
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) if len(plan.Changes.Resources) != 2 {
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
}
for _, res := range plan.Changes.Resources {
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
var expected cty.Value
switch i := val.Addr.String(); i {
case "aws_instance.b":
expected = objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
})
case "aws_instance.c":
expected = objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"some_input": cty.UnknownVal(cty.String),
"type": cty.StringVal("aws_instance"),
})
default:
t.Fatal("unknown instance:", i)
}
checkVals(t, expected, val.After)
} }
} }
@ -317,21 +485,30 @@ func TestContext2Plan_moduleDeadlock(t *testing.T) {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
expected := strings.TrimSpace(` ty := schema.ImpliedType()
DIFF:
module.child: for _, res := range plan.Changes.Resources {
CREATE: aws_instance.foo.0 if res.Action != plans.Create {
CREATE: aws_instance.foo.1 t.Fatalf("expected resource creation, got %s", res.Action)
CREATE: aws_instance.foo.2 }
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
STATE: expected := objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
})
switch i := val.Addr.String(); i {
case "module.child.aws_instance.foo[0]":
case "module.child.aws_instance.foo[1]":
case "module.child.aws_instance.foo[2]":
default:
t.Fatal("unknown instance:", i)
}
<no state> checkVals(t, expected, val.After)
`)
if actual != expected {
t.Fatalf("expected:\n%sgot:\n%s", expected, actual)
} }
}) })
} }
@ -354,10 +531,42 @@ func TestContext2Plan_moduleInput(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
expected := strings.TrimSpace(testTerraformPlanModuleInputStr) ty := schema.ImpliedType()
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) if len(plan.Changes.Resources) != 2 {
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
}
for _, res := range plan.Changes.Resources {
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
var expected cty.Value
switch i := val.Addr.String(); i {
case "aws_instance.bar":
expected = objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.StringVal("2"),
"type": cty.StringVal("aws_instance"),
})
case "module.child.aws_instance.foo":
expected = objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.StringVal("42"),
"type": cty.StringVal("aws_instance"),
})
default:
t.Fatal("unknown instance:", i)
}
checkVals(t, expected, val.After)
} }
} }
@ -379,10 +588,38 @@ func TestContext2Plan_moduleInputComputed(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
expected := strings.TrimSpace(testTerraformPlanModuleInputComputedStr) ty := schema.ImpliedType()
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) if len(plan.Changes.Resources) != 2 {
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
}
for _, res := range plan.Changes.Resources {
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
switch i := val.Addr.String(); i {
case "aws_instance.bar":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.UnknownVal(cty.String),
"type": cty.StringVal("aws_instance"),
}), val.After)
case "module.child.aws_instance.foo":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.UnknownVal(cty.String),
"type": cty.StringVal("aws_instance"),
}), val.After)
default:
t.Fatal("unknown instance:", i)
}
} }
} }
@ -410,10 +647,38 @@ func TestContext2Plan_moduleInputFromVar(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
expected := strings.TrimSpace(testTerraformPlanModuleInputVarStr) ty := schema.ImpliedType()
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) if len(plan.Changes.Resources) != 2 {
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
}
for _, res := range plan.Changes.Resources {
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
switch i := val.Addr.String(); i {
case "aws_instance.bar":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.StringVal("2"),
"type": cty.StringVal("aws_instance"),
}), val.After)
case "module.child.aws_instance.foo":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.StringVal("52"),
"type": cty.StringVal("aws_instance"),
}), val.After)
default:
t.Fatal("unknown instance:", i)
}
} }
} }
@ -447,10 +712,50 @@ func TestContext2Plan_moduleMultiVar(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
expected := strings.TrimSpace(testTerraformPlanModuleMultiVarStr) ty := schema.ImpliedType()
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) if len(plan.Changes.Resources) != 5 {
t.Fatal("expected 5 changes, got", len(plan.Changes.Resources))
}
for _, res := range plan.Changes.Resources {
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
switch i := val.Addr.String(); i {
case "aws_instance.parent[0]":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
}), val.After)
case "aws_instance.parent[1]":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
}), val.After)
case "module.child.aws_instance.bar[0]":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"baz": cty.StringVal("baz"),
}), val.After)
case "module.child.aws_instance.bar[1]":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"baz": cty.StringVal("baz"),
}), val.After)
case "module.child.aws_instance.foo":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.StringVal("baz,baz"),
}), val.After)
default:
t.Fatal("unknown instance:", i)
}
} }
} }
@ -468,6 +773,7 @@ func TestContext2Plan_moduleOrphans(t *testing.T) {
Primary: &InstanceState{ Primary: &InstanceState{
ID: "baz", ID: "baz",
}, },
Provider: "provider.aws",
}, },
}, },
}, },
@ -487,11 +793,47 @@ func TestContext2Plan_moduleOrphans(t *testing.T) {
if diags.HasErrors() { if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
ty := schema.ImpliedType()
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) if len(plan.Changes.Resources) != 2 {
expected := strings.TrimSpace(testTerraformPlanModuleOrphansStr) t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
if actual != expected { }
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
for _, res := range plan.Changes.Resources {
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
switch i := val.Addr.String(); i {
case "aws_instance.foo":
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"num": cty.NumberIntVal(2),
"type": cty.StringVal("aws_instance"),
}), val.After)
case "module.child.aws_instance.foo":
if res.Action != plans.Delete {
t.Fatalf("expected resource delete, got %s", res.Action)
}
default:
t.Fatal("unknown instance:", i)
}
}
expectedState := `<no state>
module.child:
aws_instance.foo:
ID = baz
provider = provider.aws`
if ctx.State().String() != expectedState {
t.Fatalf("\nexpected state: %q\n\ngot: %q", expectedState, ctx.State().String())
} }
} }
@ -522,6 +864,7 @@ func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
Primary: &InstanceState{ Primary: &InstanceState{
ID: "baz", ID: "baz",
}, },
Provider: "provider.aws",
}, },
}, },
}, },
@ -533,6 +876,7 @@ func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
Primary: &InstanceState{ Primary: &InstanceState{
ID: "baz", ID: "baz",
}, },
Provider: "provider.aws",
}, },
}, },
}, },
@ -556,29 +900,53 @@ func TestContext2Plan_moduleOrphansWithProvisioner(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
expected := strings.TrimSpace(` ty := schema.ImpliedType()
DIFF:
module.parent.module.childone: if len(plan.Changes.Resources) != 3 {
DESTROY: aws_instance.foo t.Error("expected 3 planned resources, got", len(plan.Changes.Resources))
module.parent.module.childtwo: }
DESTROY: aws_instance.foo
STATE: for _, res := range plan.Changes.Resources {
aws_instance.top: val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
switch i := val.Addr.String(); i {
case "module.parent.module.childone.aws_instance.foo":
if res.Action != plans.Delete {
t.Fatalf("expected resource Delete, got %s", res.Action)
}
case "module.parent.module.childtwo.aws_instance.foo":
if res.Action != plans.Delete {
t.Fatalf("expected resource Delete, got %s", res.Action)
}
case "aws_instance.top":
if res.Action != plans.NoOp {
t.Fatal("expected no change, got", res.Action)
}
default:
t.Fatalf("unknown instance: %s\nafter: %#v", i, hcl2shim.ConfigValueFromHCL2(val.After))
}
}
expectedState := `aws_instance.top:
ID = top ID = top
provider = provider.aws
module.parent.childone: module.parent.childone:
aws_instance.foo: aws_instance.foo:
ID = baz ID = baz
provider = provider.aws
module.parent.childtwo: module.parent.childtwo:
aws_instance.foo: aws_instance.foo:
ID = baz ID = baz
`) provider = provider.aws`
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) if expectedState != ctx.State().String() {
t.Fatalf("\nexpect state: %q\ngot state: %q\n", expectedState, ctx.State().String())
} }
} }
@ -813,10 +1181,30 @@ func TestContext2Plan_moduleProviderVar(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
expected := strings.TrimSpace(testTerraformPlanModuleProviderVarStr) ty := schema.ImpliedType()
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) if len(plan.Changes.Resources) != 1 {
t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
}
for _, res := range plan.Changes.Resources {
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
switch i := val.Addr.String(); i {
case "module.child.aws_instance.test":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"value": cty.StringVal("hello"),
}), val.After)
default:
t.Fatal("unknown instance:", i)
}
} }
} }
@ -838,10 +1226,42 @@ func TestContext2Plan_moduleVar(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
expected := strings.TrimSpace(testTerraformPlanModuleVarStr) ty := schema.ImpliedType()
if actual != expected {
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) if len(plan.Changes.Resources) != 2 {
t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
}
for _, res := range plan.Changes.Resources {
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
var expected cty.Value
switch i := val.Addr.String(); i {
case "aws_instance.bar":
expected = objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.StringVal("2"),
"type": cty.StringVal("aws_instance"),
})
case "module.child.aws_instance.foo":
expected = objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"num": cty.NumberIntVal(2),
"type": cty.StringVal("aws_instance"),
})
default:
t.Fatal("unknown instance:", i)
}
checkVals(t, expected, val.After)
} }
} }
@ -919,11 +1339,38 @@ func TestContext2Plan_moduleVarComputed(t *testing.T) {
if diags.HasErrors() { if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
ty := schema.ImpliedType()
actual := strings.TrimSpace(legacyPlanComparisonString(ctx.State(), plan.Changes)) if len(plan.Changes.Resources) != 2 {
expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr) t.Fatal("expected 2 changes, got", len(plan.Changes.Resources))
if actual != expected { }
t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected)
for _, res := range plan.Changes.Resources {
if res.Action != plans.Create {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
switch i := val.Addr.String(); i {
case "aws_instance.bar":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.UnknownVal(cty.String),
"type": cty.StringVal("aws_instance"),
}), val.After)
case "module.child.aws_instance.foo":
checkVals(t, objectVal(t, schema, map[string]cty.Value{
"id": cty.UnknownVal(cty.String),
"foo": cty.UnknownVal(cty.String),
"type": cty.StringVal("aws_instance"),
}), val.After)
default:
t.Fatal("unknown instance:", i)
}
} }
} }
@ -970,8 +1417,27 @@ func TestContext2Plan_nil(t *testing.T) {
t.Fatalf("unexpected errors: %s", diags.Err()) t.Fatalf("unexpected errors: %s", diags.Err())
} }
if len(plan.Changes.Resources) != 0 { if len(plan.Changes.Resources) != 1 {
t.Fatalf("bad: %#v", plan.Changes.Resources) t.Fatal("expected 1 changes, got", len(plan.Changes.Resources))
}
schema := p.GetSchemaReturn.ResourceTypes["aws_instance"]
ty := schema.ImpliedType()
for _, res := range plan.Changes.Resources {
if res.Action != plans.Update {
t.Fatalf("expected resource creation, got %s", res.Action)
}
val, err := res.Decode(ty)
if err != nil {
t.Fatal(err)
}
switch i := val.Addr.String(); i {
case "aws_instance.foo":
checkVals(t, cty.NullVal(schema.ImpliedType()), val.After)
default:
t.Fatal("unknown instance:", i)
}
} }
} }
@ -1048,7 +1514,7 @@ func TestContext2Plan_preventDestroy_good(t *testing.T) {
} }
if !plan.Changes.Empty() { if !plan.Changes.Empty() {
t.Fatalf("Expected empty plan, got %s", legacyDiffComparisonString(plan.Changes)) t.Fatalf("expected no changes, got %#v\n", plan.Changes)
} }
} }
@ -1458,7 +1924,7 @@ func TestContext2Plan_dataSourceTypeMismatch(t *testing.T) {
}, },
}, },
} }
p.ValidateResourceTypeConfigFn = func (req providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse { p.ValidateResourceTypeConfigFn = func(req providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse {
var diags tfdiags.Diagnostics var diags tfdiags.Diagnostics
if req.TypeName == "aws_instance" { if req.TypeName == "aws_instance" {
amiVal := req.Config.GetAttr("ami") amiVal := req.Config.GetAttr("ami")
@ -4043,7 +4509,7 @@ func TestContext2Plan_computedAttrRefTypeMismatch(t *testing.T) {
m := testModule(t, "plan-computed-attr-ref-type-mismatch") m := testModule(t, "plan-computed-attr-ref-type-mismatch")
p := testProvider("aws") p := testProvider("aws")
p.DiffFn = testDiffFn p.DiffFn = testDiffFn
p.ValidateResourceTypeConfigFn = func (req providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse { p.ValidateResourceTypeConfigFn = func(req providers.ValidateResourceTypeConfigRequest) providers.ValidateResourceTypeConfigResponse {
var diags tfdiags.Diagnostics var diags tfdiags.Diagnostics
if req.TypeName == "aws_instance" { if req.TypeName == "aws_instance" {
amiVal := req.Config.GetAttr("ami") amiVal := req.Config.GetAttr("ami")
@ -4224,3 +4690,22 @@ func TestContext2Plan_selfRefMultiAll(t *testing.T) {
t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr) t.Fatalf("missing expected error\ngot: %s\n\nwant: error containing %q", gotErrStr, wantErrStr)
} }
} }
func checkVals(t *testing.T, expected, got cty.Value) {
t.Helper()
if !cmp.Equal(expected, got, valueComparer, typeComparer, equateEmpty) {
t.Fatal(cmp.Diff(expected, got, valueTrans, equateEmpty))
}
}
func objectVal(t *testing.T, schema *configschema.Block, m map[string]cty.Value) cty.Value {
t.Helper()
return cty.ObjectVal(m)
v, err := schema.CoerceValue(
cty.ObjectVal(m),
)
if err != nil {
t.Fatal(err)
}
return v
}

View File

@ -39,6 +39,7 @@ var (
equateEmpty = cmpopts.EquateEmpty() equateEmpty = cmpopts.EquateEmpty()
typeComparer = cmp.Comparer(cty.Type.Equals) typeComparer = cmp.Comparer(cty.Type.Equals)
valueComparer = cmp.Comparer(cty.Value.RawEquals) valueComparer = cmp.Comparer(cty.Value.RawEquals)
valueTrans = cmp.Transformer("hcl2shim", hcl2shim.ConfigValueFromHCL2)
) )
func TestNewContextRequiredVersion(t *testing.T) { func TestNewContextRequiredVersion(t *testing.T) {
@ -253,6 +254,7 @@ func testDiffFn(
} }
diff.Attributes[v.(string)] = attrDiff diff.Attributes[v.(string)] = attrDiff
continue
} }
// If this key is not computed, then look it up in the // If this key is not computed, then look it up in the
@ -514,7 +516,7 @@ func testProviderSchema(name string) *ProviderSchema {
"compute": { "compute": {
Type: cty.String, Type: cty.String,
Optional: true, Optional: true,
Computed: true, Computed: false,
}, },
"compute_value": { "compute_value": {
Type: cty.String, Type: cty.String,

View File

@ -1502,111 +1502,6 @@ STATE:
<no state> <no state>
` `
const testTerraformPlanModuleInputVarStr = `
DIFF:
CREATE: aws_instance.bar
foo: "" => "2"
type: "" => "aws_instance"
module.child:
CREATE: aws_instance.foo
foo: "" => "52"
type: "" => "aws_instance"
STATE:
<no state>
`
const testTerraformPlanModuleMultiVarStr = `
DIFF:
CREATE: aws_instance.parent.0
CREATE: aws_instance.parent.1
module.child:
CREATE: aws_instance.bar.0
baz: "" => "baz"
type: "" => "aws_instance"
CREATE: aws_instance.bar.1
baz: "" => "baz"
type: "" => "aws_instance"
CREATE: aws_instance.foo
foo: "" => "baz,baz"
type: "" => "aws_instance"
STATE:
<no state>
`
const testTerraformPlanModuleOrphansStr = `
DIFF:
CREATE: aws_instance.foo
num: "" => "2"
type: "" => "aws_instance"
module.child:
DESTROY: aws_instance.foo
STATE:
module.child:
aws_instance.foo:
ID = baz
`
const testTerraformPlanModuleProviderVarStr = `
DIFF:
module.child:
CREATE: aws_instance.test
type: "" => "aws_instance"
value: "" => "hello"
STATE:
<no state>
`
const testTerraformPlanModuleVarStr = `
DIFF:
CREATE: aws_instance.bar
foo: "" => "2"
type: "" => "aws_instance"
module.child:
CREATE: aws_instance.foo
num: "" => "2"
type: "" => "aws_instance"
STATE:
<no state>
`
const testTerraformPlanModuleVarComputedStr = `
DIFF:
CREATE: aws_instance.bar
foo: "" => "<computed>"
type: "" => "aws_instance"
module.child:
CREATE: aws_instance.foo
compute: "" => "foo"
compute_value: "" => "<computed>"
foo: "" => "<computed>"
type: "" => "aws_instance"
STATE:
<no state>
`
const testTerraformPlanModuleVarIntStr = ` const testTerraformPlanModuleVarIntStr = `
DIFF: DIFF: