From 8625e8c2acac55d1d3b0643dc746b8a63dcfa364 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 2 Jul 2014 17:26:39 -0700 Subject: [PATCH] terraform: tests for Apply in areas of errors --- terraform/terraform.go | 6 + terraform/terraform_test.go | 139 ++++++++++++++++++++ terraform/test-fixtures/apply-error/main.tf | 7 + 3 files changed, 152 insertions(+) create mode 100644 terraform/test-fixtures/apply-error/main.tf diff --git a/terraform/terraform.go b/terraform/terraform.go index 8822a0843..e2c88fe6c 100644 --- a/terraform/terraform.go +++ b/terraform/terraform.go @@ -145,7 +145,13 @@ func (t *Terraform) Refresh(c *config.Config, s *State) (*State, error) { func (t *Terraform) apply( g *depgraph.Graph, p *Plan) (*State, error) { + // Create our result. Make sure we preserve the prior states s := new(State) + s.init() + for k, v := range p.State.Resources { + s.Resources[k] = v + } + err := g.Walk(t.applyWalkFn(s, p)) return s, err } diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index c1075cf73..9b3d98dec 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -196,6 +196,131 @@ func TestTerraformApply_destroy(t *testing.T) { } } +func TestTerraformApply_error(t *testing.T) { + errored := false + + rpAWS := new(MockResourceProvider) + rpAWS.ResourcesReturn = []ResourceType{ + ResourceType{Name: "aws_instance"}, + } + rpAWS.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + return &ResourceDiff{ + Attributes: map[string]*ResourceAttrDiff{ + "num": &ResourceAttrDiff{ + New: "bar", + }, + }, + }, nil + } + rpAWS.ApplyFn = func(*ResourceState, *ResourceDiff) (*ResourceState, error) { + if errored { + return nil, fmt.Errorf("error") + } + errored = true + + return &ResourceState{ + ID: "foo", + Attributes: map[string]string{ + "num": "2", + }, + }, nil + } + + c := testConfig(t, "apply-error") + tf := testTerraform2(t, &Config{ + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(rpAWS), + }, + }) + + p, err := tf.Plan(&PlanOpts{Config: c}) + if err != nil { + t.Fatalf("err: %s", err) + } + + state, err := tf.Apply(p) + if err == nil { + t.Fatal("should have error") + } + + if len(state.Resources) != 1 { + t.Fatalf("bad: %#v", state.Resources) + } + + actual := strings.TrimSpace(state.String()) + expected := strings.TrimSpace(testTerraformApplyErrorStr) + if actual != expected { + t.Fatalf("bad: \n%s", actual) + } +} + +func TestTerraformApply_errorPartial(t *testing.T) { + errored := false + + rpAWS := new(MockResourceProvider) + rpAWS.ResourcesReturn = []ResourceType{ + ResourceType{Name: "aws_instance"}, + } + rpAWS.DiffFn = func(*ResourceState, *ResourceConfig) (*ResourceDiff, error) { + return &ResourceDiff{ + Attributes: map[string]*ResourceAttrDiff{ + "num": &ResourceAttrDiff{ + New: "bar", + }, + }, + }, nil + } + rpAWS.ApplyFn = func(*ResourceState, *ResourceDiff) (*ResourceState, error) { + if errored { + return nil, fmt.Errorf("error") + } + errored = true + + return &ResourceState{ + ID: "foo", + Attributes: map[string]string{ + "num": "2", + }, + }, nil + } + + c := testConfig(t, "apply-error") + tf := testTerraform2(t, &Config{ + Providers: map[string]ResourceProviderFactory{ + "aws": testProviderFuncFixed(rpAWS), + }, + }) + + s := &State{ + Resources: map[string]*ResourceState{ + "aws_instance.bar": &ResourceState{ + ID: "bar", + Type: "aws_instance", + }, + }, + } + + p, err := tf.Plan(&PlanOpts{Config: c, State: s}) + if err != nil { + t.Fatalf("err: %s", err) + } + + state, err := tf.Apply(p) + if err == nil { + t.Fatal("should have error") + } + + if len(state.Resources) != 2 { + t.Fatalf("bad: %#v", state.Resources) + } + + actual := strings.TrimSpace(state.String()) + expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) + if actual != expected { + t.Fatalf("bad: \n%s", actual) + } +} + func TestTerraformApply_hook(t *testing.T) { c := testConfig(t, "apply-good") h := new(MockHook) @@ -789,6 +914,20 @@ aws_instance.foo: ID = ` +const testTerraformApplyErrorStr = ` +aws_instance.foo: + ID = foo + num = 2 +` + +const testTerraformApplyErrorPartialStr = ` +aws_instance.bar: + ID = bar +aws_instance.foo: + ID = foo + num = 2 +` + const testTerraformApplyUnknownAttrStr = ` aws_instance.foo: ID = foo diff --git a/terraform/test-fixtures/apply-error/main.tf b/terraform/test-fixtures/apply-error/main.tf new file mode 100644 index 000000000..94ed55478 --- /dev/null +++ b/terraform/test-fixtures/apply-error/main.tf @@ -0,0 +1,7 @@ +resource "aws_instance" "foo" { + num = "2" +} + +resource "aws_instance" "bar" { + foo = "${aws_instance.foo.num}" +}