diff --git a/command/format/plan_test.go b/command/format/plan_test.go deleted file mode 100644 index 0a2dc1e36..000000000 --- a/command/format/plan_test.go +++ /dev/null @@ -1,619 +0,0 @@ -package format - -import ( - "reflect" - "strings" - "testing" - - "github.com/davecgh/go-spew/spew" - "github.com/hashicorp/terraform/terraform" - "github.com/mitchellh/colorstring" -) - -var disabledColorize = &colorstring.Colorize{ - Colors: colorstring.DefaultColors, - Disable: true, -} - -func TestNewPlan(t *testing.T) { - tests := map[string]struct { - Input *terraform.Plan - Want *Plan - }{ - "nil input": { - Input: nil, - Want: &Plan{ - Resources: nil, - }, - }, - "nil diff": { - Input: &terraform.Plan{}, - Want: &Plan{ - Resources: nil, - }, - }, - "empty diff": { - Input: &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - { - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{}, - }, - }, - }, - }, - Want: &Plan{ - Resources: nil, - }, - }, - "create managed resource": { - Input: &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - { - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "test_resource.foo": { - Attributes: map[string]*terraform.ResourceAttrDiff{ - "id": { - NewComputed: true, - RequiresNew: true, - }, - }, - }, - }, - }, - }, - }, - }, - Want: &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("test_resource.foo"), - Action: terraform.DiffCreate, - Attributes: []*AttributeDiff{ - { - Path: "id", - Action: terraform.DiffCreate, - NewComputed: true, - ForcesNew: true, - }, - }, - }, - }, - }, - }, - "create managed resource in child module": { - Input: &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - { - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "test_resource.foo": { - Attributes: map[string]*terraform.ResourceAttrDiff{ - "id": { - NewComputed: true, - RequiresNew: true, - }, - }, - }, - }, - }, - { - Path: []string{"root", "foo"}, - Resources: map[string]*terraform.InstanceDiff{ - "test_resource.foo": { - Attributes: map[string]*terraform.ResourceAttrDiff{ - "id": { - NewComputed: true, - RequiresNew: true, - }, - }, - }, - }, - }, - }, - }, - }, - Want: &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("test_resource.foo"), - Action: terraform.DiffCreate, - Attributes: []*AttributeDiff{ - { - Path: "id", - Action: terraform.DiffCreate, - NewComputed: true, - ForcesNew: true, - }, - }, - }, - { - Addr: mustParseResourceAddress("module.foo.test_resource.foo"), - Action: terraform.DiffCreate, - Attributes: []*AttributeDiff{ - { - Path: "id", - Action: terraform.DiffCreate, - NewComputed: true, - ForcesNew: true, - }, - }, - }, - }, - }, - }, - "create data resource": { - Input: &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - { - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "data.test_data_source.foo": { - Attributes: map[string]*terraform.ResourceAttrDiff{ - "id": { - NewComputed: true, - RequiresNew: true, - }, - }, - }, - }, - }, - }, - }, - }, - Want: &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("data.test_data_source.foo"), - Action: terraform.DiffRefresh, - Attributes: []*AttributeDiff{ - { - Path: "id", - Action: terraform.DiffUpdate, - NewComputed: true, - ForcesNew: true, - }, - }, - }, - }, - }, - }, - "destroy managed resource": { - Input: &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - { - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "test_resource.foo": { - Destroy: true, - }, - }, - }, - }, - }, - }, - Want: &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("test_resource.foo"), - Action: terraform.DiffDestroy, - }, - }, - }, - }, - "destroy data resource": { - Input: &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - { - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "data.test_data_source.foo": { - Destroy: true, - }, - }, - }, - }, - }, - }, - Want: &Plan{ - // Data source destroys are not shown - Resources: nil, - }, - }, - "destroy many instances of a resource": { - Input: &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - { - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "test_resource.foo.0": { - Destroy: true, - }, - "test_resource.foo.1": { - Destroy: true, - }, - "test_resource.foo.10": { - Destroy: true, - }, - "test_resource.foo.2": { - Destroy: true, - }, - "test_resource.foo.3": { - Destroy: true, - }, - "test_resource.foo.4": { - Destroy: true, - }, - "test_resource.foo.5": { - Destroy: true, - }, - "test_resource.foo.6": { - Destroy: true, - }, - "test_resource.foo.7": { - Destroy: true, - }, - "test_resource.foo.8": { - Destroy: true, - }, - "test_resource.foo.9": { - Destroy: true, - }, - }, - }, - }, - }, - }, - Want: &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("test_resource.foo[0]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[1]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[2]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[3]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[4]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[5]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[6]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[7]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[8]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[9]"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.foo[10]"), - Action: terraform.DiffDestroy, - }, - }, - }, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - got := NewPlan(test.Input) - if !reflect.DeepEqual(got, test.Want) { - t.Errorf( - "wrong result\ninput: %sgot: %swant:%s", - spew.Sdump(test.Input), - spew.Sdump(got), - spew.Sdump(test.Want), - ) - } - }) - } -} - -func TestPlanStats(t *testing.T) { - tests := map[string]struct { - Input *Plan - Want PlanStats - }{ - "empty": { - &Plan{}, - PlanStats{}, - }, - "destroy": { - &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("test_resource.foo"), - Action: terraform.DiffDestroy, - }, - { - Addr: mustParseResourceAddress("test_resource.bar"), - Action: terraform.DiffDestroy, - }, - }, - }, - PlanStats{ - ToDestroy: 2, - }, - }, - "create": { - &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("test_resource.foo"), - Action: terraform.DiffCreate, - }, - { - Addr: mustParseResourceAddress("test_resource.bar"), - Action: terraform.DiffCreate, - }, - }, - }, - PlanStats{ - ToAdd: 2, - }, - }, - "update": { - &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("test_resource.foo"), - Action: terraform.DiffUpdate, - }, - { - Addr: mustParseResourceAddress("test_resource.bar"), - Action: terraform.DiffUpdate, - }, - }, - }, - PlanStats{ - ToChange: 2, - }, - }, - "data source refresh": { - &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("data.test.foo"), - Action: terraform.DiffRefresh, - }, - }, - }, - PlanStats{ - // data resource refreshes are not counted in our stats - }, - }, - "replace": { - &Plan{ - Resources: []*InstanceDiff{ - { - Addr: mustParseResourceAddress("test_resource.foo"), - Action: terraform.DiffDestroyCreate, - }, - { - Addr: mustParseResourceAddress("test_resource.bar"), - Action: terraform.DiffDestroyCreate, - }, - }, - }, - PlanStats{ - ToDestroy: 2, - ToAdd: 2, - }, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - got := test.Input.Stats() - if !reflect.DeepEqual(got, test.Want) { - t.Errorf( - "wrong result\ninput: %sgot: %swant:%s", - spew.Sdump(test.Input), - spew.Sdump(got), - spew.Sdump(test.Want), - ) - } - }) - } -} - -// Test that deposed instances are marked as such -func TestPlan_destroyDeposed(t *testing.T) { - plan := &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - &terraform.ModuleDiff{ - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "aws_instance.foo": &terraform.InstanceDiff{ - DestroyDeposed: true, - }, - }, - }, - }, - }, - } - dispPlan := NewPlan(plan) - actual := dispPlan.Format(disabledColorize) - - expected := strings.TrimSpace(` -- aws_instance.foo (deposed) - `) - if actual != expected { - t.Fatalf("expected:\n\n%s\n\ngot:\n\n%s", expected, actual) - } -} - -// Test that computed fields with an interpolation string get displayed -func TestPlan_displayInterpolations(t *testing.T) { - plan := &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - &terraform.ModuleDiff{ - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "aws_instance.foo": &terraform.InstanceDiff{ - Attributes: map[string]*terraform.ResourceAttrDiff{ - "computed_field": &terraform.ResourceAttrDiff{ - New: "${aws_instance.other.id}", - NewComputed: true, - }, - }, - }, - }, - }, - }, - }, - } - dispPlan := NewPlan(plan) - out := dispPlan.Format(disabledColorize) - lines := strings.Split(out, "\n") - if len(lines) != 2 { - t.Fatal("expected 2 lines of output, got:\n", out) - } - - actual := strings.TrimSpace(lines[1]) - expected := `computed_field: "" => "${aws_instance.other.id}"` - - if actual != expected { - t.Fatalf("expected:\n\n%s\n\ngot:\n\n%s", expected, actual) - } -} - -// Ensure that (forces new resource) text is included -// https://github.com/hashicorp/terraform/issues/16035 -func TestPlan_forcesNewResource(t *testing.T) { - plan := &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - &terraform.ModuleDiff{ - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "test_resource.foo": &terraform.InstanceDiff{ - Destroy: true, - Attributes: map[string]*terraform.ResourceAttrDiff{ - "A": &terraform.ResourceAttrDiff{ - New: "B", - RequiresNew: true, - }, - }, - }, - }, - }, - }, - }, - } - dispPlan := NewPlan(plan) - actual := dispPlan.Format(disabledColorize) - - expected := strings.TrimSpace(` --/+ test_resource.foo (new resource required) - A: "" => "B" (forces new resource) - `) - if actual != expected { - t.Fatalf("expected:\n\n%s\n\ngot:\n\n%s", expected, actual) - } -} - -// Test that a root level data source gets a special plan output on create -func TestPlan_rootDataSource(t *testing.T) { - plan := &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - &terraform.ModuleDiff{ - Path: []string{"root"}, - Resources: map[string]*terraform.InstanceDiff{ - "data.type.name": &terraform.InstanceDiff{ - Attributes: map[string]*terraform.ResourceAttrDiff{ - "A": &terraform.ResourceAttrDiff{ - New: "B", - RequiresNew: true, - }, - }, - }, - }, - }, - }, - }, - } - dispPlan := NewPlan(plan) - actual := dispPlan.Format(disabledColorize) - - expected := strings.TrimSpace(` - <= data.type.name - A: "B" - `) - if actual != expected { - t.Fatalf("expected:\n\n%s\n\ngot:\n\n%s", expected, actual) - } -} - -// Test that data sources nested in modules get the same plan output -func TestPlan_nestedDataSource(t *testing.T) { - plan := &terraform.Plan{ - Diff: &terraform.Diff{ - Modules: []*terraform.ModuleDiff{ - &terraform.ModuleDiff{ - Path: []string{"root", "nested"}, - Resources: map[string]*terraform.InstanceDiff{ - "data.type.name": &terraform.InstanceDiff{ - Attributes: map[string]*terraform.ResourceAttrDiff{ - "A": &terraform.ResourceAttrDiff{ - New: "B", - RequiresNew: true, - }, - }, - }, - }, - }, - }, - }, - } - dispPlan := NewPlan(plan) - actual := dispPlan.Format(disabledColorize) - - expected := strings.TrimSpace(` - <= module.nested.data.type.name - A: "B" - `) - if actual != expected { - t.Fatalf("expected:\n\n%s\n\ngot:\n\n%s", expected, actual) - } -} - -func mustParseResourceAddress(s string) *terraform.ResourceAddress { - addr, err := terraform.ParseResourceAddress(s) - if err != nil { - panic(err) - } - return addr -}