package diff import ( "testing" "github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/terraform" ) func TestResourceBuilder_attrSetComputed(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "foo": AttrTypeCreate, }, ComputedAttrs: []string{ "foo", }, } state := &terraform.ResourceState{} c := testConfig(t, map[string]interface{}{ "foo": "bar", }, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("diff shold not be nil") } actual := testResourceDiffStr(diff) expected := testRBAttrSetComputedDiff if actual != expected { t.Fatalf("bad: %s", actual) } } func TestResourceBuilder_attrSetComputedComplex(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "foo": AttrTypeCreate, }, ComputedAttrs: []string{ "foo", }, } state := &terraform.ResourceState{ ID: "foo", Attributes: map[string]string{ "foo.#": "0", }, } c := testConfig(t, map[string]interface{}{}, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff != nil { t.Fatalf("diff shold be nil: %s", diff) } } func TestResourceBuilder_replaceComputed(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "foo": AttrTypeCreate, }, ComputedAttrs: []string{ "foo", }, } state := &terraform.ResourceState{ ID: "foo", Attributes: map[string]string{ "foo": "bar", }, } c := testConfig(t, nil, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff != nil { t.Fatalf("should be nil: %#v", diff) } } func TestResourceBuilder_complex(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "listener": AttrTypeUpdate, }, } state := &terraform.ResourceState{ ID: "foo", Attributes: map[string]string{ "ignore": "1", "listener.#": "1", "listener.0.port": "80", }, } c := testConfig(t, map[string]interface{}{ "listener": []interface{}{ map[interface{}]interface{}{ "port": 3000, }, }, }, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("should not be nil") } actual := testResourceDiffStr(diff) expected := testRBComplexDiff if actual != expected { t.Fatalf("bad: %s", actual) } } func TestResourceBuilder_complexReplace(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "listener": AttrTypeUpdate, }, } state := &terraform.ResourceState{ ID: "foo", Attributes: map[string]string{ "ignore": "1", "listener.#": "1", "listener.0.port": "80", }, } c := testConfig(t, map[string]interface{}{ "listener": []interface{}{ map[interface{}]interface{}{ "value": "50", }, }, }, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("should not be nil") } actual := testResourceDiffStr(diff) expected := testRBComplexReplaceDiff if actual != expected { t.Fatalf("bad: %s", actual) } } func TestResourceBuilder_computedAttrsUpdate(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "foo": AttrTypeUpdate, }, ComputedAttrsUpdate: []string{ "bar", }, } state := &terraform.ResourceState{ Attributes: map[string]string{"foo": "foo"}, } c := testConfig(t, map[string]interface{}{ "foo": "bar", }, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("diff shold not be nil") } actual := testResourceDiffStr(diff) expected := testRBComputedAttrUpdate if actual != expected { t.Fatalf("bad: %s", actual) } } func TestResourceBuilder_new(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "foo": AttrTypeUpdate, }, ComputedAttrs: []string{"private_ip"}, } state := &terraform.ResourceState{} c := testConfig(t, map[string]interface{}{ "foo": "bar", }, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("should not be nil") } actual := testResourceDiffStr(diff) expected := testRBNewDiff if actual != expected { t.Fatalf("bad: %s", actual) } } func TestResourceBuilder_preProcess(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "foo": AttrTypeCreate, }, PreProcess: map[string]PreProcessFunc{ "foo": func(v string) string { return "bar" + v }, }, } state := &terraform.ResourceState{} c := testConfig(t, map[string]interface{}{ "foo": "foo", }, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("diff shold not be nil") } actual := testResourceDiffStr(diff) expected := testRBPreProcessDiff if actual != expected { t.Fatalf("bad: %s", actual) } actual = diff.Attributes["foo"].NewExtra.(string) expected = "foo" if actual != expected { t.Fatalf("bad: %#v", actual) } } func TestResourceBuilder_preProcessUnknown(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "foo": AttrTypeCreate, }, PreProcess: map[string]PreProcessFunc{ "foo": func(string) string { return "bar" }, }, } state := &terraform.ResourceState{} c := testConfig(t, map[string]interface{}{ "foo": "${var.unknown}", }, map[string]string{ "var.unknown": config.UnknownVariableValue, }) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("diff shold not be nil") } actual := testResourceDiffStr(diff) expected := testRBPreProcessUnknownDiff if actual != expected { t.Fatalf("bad: %s", actual) } } func TestResourceBuilder_requiresNew(t *testing.T) { rb := &ResourceBuilder{ ComputedAttrs: []string{"private_ip"}, Attrs: map[string]AttrType{ "ami": AttrTypeCreate, }, } state := &terraform.ResourceState{ ID: "1", Attributes: map[string]string{ "ami": "foo", "private_ip": "127.0.0.1", }, } c := testConfig(t, map[string]interface{}{ "ami": "bar", }, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("should not be nil") } actual := testResourceDiffStr(diff) expected := testRBRequiresNewDiff if actual != expected { t.Fatalf("bad: %s", actual) } } func TestResourceBuilder_same(t *testing.T) { rb := &ResourceBuilder{ ComputedAttrs: []string{"private_ip"}, } state := &terraform.ResourceState{ ID: "1", Attributes: map[string]string{ "foo": "bar", }, } c := testConfig(t, map[string]interface{}{ "foo": "bar", }, nil) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff != nil { t.Fatal("should not diff: %s", diff) } } func TestResourceBuilder_unknown(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "foo": AttrTypeUpdate, }, } state := &terraform.ResourceState{} c := testConfig(t, map[string]interface{}{ "foo": "${var.unknown}", }, map[string]string{ "var.foo": "bar", "var.unknown": config.UnknownVariableValue, }) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("should not be nil") } actual := testResourceDiffStr(diff) expected := testRBUnknownDiff if actual != expected { t.Fatalf("bad: %s", actual) } } func TestResourceBuilder_vars(t *testing.T) { rb := &ResourceBuilder{ Attrs: map[string]AttrType{ "foo": AttrTypeUpdate, }, } state := &terraform.ResourceState{} c := testConfig(t, map[string]interface{}{ "foo": "${var.foo}", }, map[string]string{ "var.foo": "bar", }) diff, err := rb.Diff(state, c) if err != nil { t.Fatalf("err: %s", err) } if diff == nil { t.Fatal("should not be nil") } actual := testResourceDiffStr(diff) expected := testRBVarsDiff if actual != expected { t.Fatalf("bad: %s", actual) } } const testRBAttrSetComputedDiff = `CREATE IN foo: "" => "bar" (forces new resource) ` const testRBComplexDiff = `UPDATE IN listener.0.port: "80" => "3000" ` const testRBComplexReplaceDiff = `UPDATE IN listener.0.port: "80" => "" IN listener.0.value: "" => "50" ` const testRBComputedAttrUpdate = `UPDATE OUT bar: "" => "" IN foo: "foo" => "bar" ` const testRBNewDiff = `UPDATE IN foo: "" => "bar" OUT private_ip: "" => "" ` const testRBPreProcessDiff = `CREATE IN foo: "" => "barfoo" (forces new resource) ` const testRBPreProcessUnknownDiff = `CREATE IN foo: "" => "${var.unknown}" (forces new resource) ` const testRBRequiresNewDiff = `CREATE IN ami: "foo" => "bar" (forces new resource) OUT private_ip: "127.0.0.1" => "" ` const testRBUnknownDiff = `UPDATE IN foo: "" => "${var.unknown}" ` const testRBVarsDiff = `UPDATE IN foo: "" => "bar" `