2014-06-03 17:08:00 -05:00
|
|
|
package terraform
|
|
|
|
|
|
|
|
import (
|
2014-07-07 14:53:01 -05:00
|
|
|
"bytes"
|
|
|
|
"crypto/sha1"
|
|
|
|
"encoding/gob"
|
|
|
|
"encoding/hex"
|
2014-06-03 17:08:00 -05:00
|
|
|
"path/filepath"
|
2014-06-30 13:14:03 -05:00
|
|
|
"sync"
|
2014-06-03 17:08:00 -05:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/config"
|
|
|
|
)
|
|
|
|
|
|
|
|
// This is the directory where our test fixtures are.
|
|
|
|
const fixtureDir = "./test-fixtures"
|
|
|
|
|
2014-07-07 14:53:01 -05:00
|
|
|
func checksumStruct(t *testing.T, i interface{}) string {
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
enc := gob.NewEncoder(buf)
|
|
|
|
if err := enc.Encode(i); err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
sum := sha1.Sum(buf.Bytes())
|
|
|
|
return hex.EncodeToString(sum[:])
|
|
|
|
}
|
|
|
|
|
2014-06-05 04:32:10 -05:00
|
|
|
func testConfig(t *testing.T, name string) *config.Config {
|
|
|
|
c, err := config.Load(filepath.Join(fixtureDir, name, "main.tf"))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
2014-06-25 14:58:27 -05:00
|
|
|
func testProviderFuncFixed(rp ResourceProvider) ResourceProviderFactory {
|
|
|
|
return func() (ResourceProvider, error) {
|
|
|
|
return rp, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-30 13:14:03 -05:00
|
|
|
// HookRecordApplyOrder is a test hook that records the order of applies
|
|
|
|
// by recording the PreApply event.
|
|
|
|
type HookRecordApplyOrder struct {
|
|
|
|
NilHook
|
|
|
|
|
|
|
|
Active bool
|
|
|
|
|
|
|
|
IDs []string
|
|
|
|
States []*ResourceState
|
|
|
|
Diffs []*ResourceDiff
|
|
|
|
|
|
|
|
l sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *HookRecordApplyOrder) PreApply(
|
|
|
|
id string,
|
|
|
|
s *ResourceState,
|
|
|
|
d *ResourceDiff) (HookAction, error) {
|
|
|
|
if h.Active {
|
|
|
|
h.l.Lock()
|
|
|
|
defer h.l.Unlock()
|
|
|
|
|
|
|
|
h.IDs = append(h.IDs, id)
|
|
|
|
h.Diffs = append(h.Diffs, d)
|
|
|
|
h.States = append(h.States, s)
|
|
|
|
}
|
|
|
|
|
|
|
|
return HookActionContinue, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Below are all the constant strings that are the expected output for
|
|
|
|
// various tests.
|
|
|
|
|
2014-06-18 18:38:08 -05:00
|
|
|
const testTerraformApplyStr = `
|
|
|
|
aws_instance.bar:
|
|
|
|
ID = foo
|
|
|
|
foo = bar
|
2014-07-01 12:28:42 -05:00
|
|
|
type = aws_instance
|
2014-06-18 18:38:08 -05:00
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
|
|
|
num = 2
|
2014-07-01 12:28:42 -05:00
|
|
|
type = aws_instance
|
2014-06-18 18:38:08 -05:00
|
|
|
`
|
|
|
|
|
2014-07-02 18:16:38 -05:00
|
|
|
const testTerraformApplyCancelStr = `
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
|
|
|
num = 2
|
|
|
|
`
|
|
|
|
|
2014-06-23 14:19:41 -05:00
|
|
|
const testTerraformApplyComputeStr = `
|
|
|
|
aws_instance.bar:
|
|
|
|
ID = foo
|
2014-06-30 21:29:07 -05:00
|
|
|
foo = computed_dynamical
|
2014-07-01 12:28:42 -05:00
|
|
|
type = aws_instance
|
2014-06-23 14:19:41 -05:00
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
2014-06-30 21:29:07 -05:00
|
|
|
dynamical = computed_dynamical
|
2014-07-01 12:28:42 -05:00
|
|
|
num = 2
|
|
|
|
type = aws_instance
|
2014-06-23 14:19:41 -05:00
|
|
|
`
|
|
|
|
|
2014-06-30 13:14:03 -05:00
|
|
|
const testTerraformApplyDestroyStr = `
|
2014-07-02 21:56:29 -05:00
|
|
|
<no state>
|
2014-06-30 13:14:03 -05:00
|
|
|
`
|
|
|
|
|
2014-07-02 19:26:39 -05:00
|
|
|
const testTerraformApplyErrorStr = `
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
|
|
|
num = 2
|
|
|
|
`
|
|
|
|
|
|
|
|
const testTerraformApplyErrorPartialStr = `
|
|
|
|
aws_instance.bar:
|
|
|
|
ID = bar
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
|
|
|
num = 2
|
|
|
|
`
|
|
|
|
|
2014-07-04 17:36:28 -05:00
|
|
|
const testTerraformApplyOutputStr = `
|
|
|
|
aws_instance.bar:
|
|
|
|
ID = foo
|
|
|
|
foo = bar
|
|
|
|
type = aws_instance
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
|
|
|
num = 2
|
|
|
|
type = aws_instance
|
|
|
|
|
|
|
|
Outputs:
|
|
|
|
|
|
|
|
foo_num = 2
|
|
|
|
`
|
|
|
|
|
2014-07-05 12:48:47 -05:00
|
|
|
const testTerraformApplyOutputMultiStr = `
|
|
|
|
aws_instance.bar.0:
|
|
|
|
ID = foo
|
|
|
|
foo = bar
|
|
|
|
type = aws_instance
|
|
|
|
aws_instance.bar.1:
|
|
|
|
ID = foo
|
|
|
|
foo = bar
|
|
|
|
type = aws_instance
|
|
|
|
aws_instance.bar.2:
|
|
|
|
ID = foo
|
|
|
|
foo = bar
|
|
|
|
type = aws_instance
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
|
|
|
num = 2
|
|
|
|
type = aws_instance
|
|
|
|
|
|
|
|
Outputs:
|
|
|
|
|
|
|
|
foo_num = bar,bar,bar
|
|
|
|
`
|
|
|
|
|
2014-07-06 16:09:44 -05:00
|
|
|
const testTerraformApplyOutputMultiIndexStr = `
|
|
|
|
aws_instance.bar.0:
|
|
|
|
ID = foo
|
|
|
|
foo = bar
|
|
|
|
type = aws_instance
|
|
|
|
aws_instance.bar.1:
|
|
|
|
ID = foo
|
|
|
|
foo = bar
|
|
|
|
type = aws_instance
|
|
|
|
aws_instance.bar.2:
|
|
|
|
ID = foo
|
|
|
|
foo = bar
|
|
|
|
type = aws_instance
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
|
|
|
num = 2
|
|
|
|
type = aws_instance
|
|
|
|
|
|
|
|
Outputs:
|
|
|
|
|
|
|
|
foo_num = bar
|
|
|
|
`
|
|
|
|
|
2014-06-23 15:08:25 -05:00
|
|
|
const testTerraformApplyUnknownAttrStr = `
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
|
|
|
num = 2
|
2014-07-01 12:28:42 -05:00
|
|
|
type = aws_instance
|
2014-06-23 15:08:25 -05:00
|
|
|
`
|
|
|
|
|
2014-06-23 14:28:02 -05:00
|
|
|
const testTerraformApplyVarsStr = `
|
|
|
|
aws_instance.bar:
|
|
|
|
ID = foo
|
|
|
|
foo = bar
|
2014-07-01 12:28:42 -05:00
|
|
|
type = aws_instance
|
2014-06-23 14:28:02 -05:00
|
|
|
aws_instance.foo:
|
|
|
|
ID = foo
|
|
|
|
num = 2
|
2014-07-01 12:28:42 -05:00
|
|
|
type = aws_instance
|
2014-06-23 14:28:02 -05:00
|
|
|
`
|
|
|
|
|
2014-06-20 12:44:49 -05:00
|
|
|
const testTerraformPlanStr = `
|
2014-06-25 20:22:42 -05:00
|
|
|
DIFF:
|
|
|
|
|
2014-06-10 13:37:04 -05:00
|
|
|
UPDATE: aws_instance.bar
|
2014-06-18 11:30:59 -05:00
|
|
|
foo: "" => "2"
|
|
|
|
type: "" => "aws_instance"
|
2014-06-10 13:37:04 -05:00
|
|
|
UPDATE: aws_instance.foo
|
2014-06-18 11:30:59 -05:00
|
|
|
num: "" => "2"
|
|
|
|
type: "" => "aws_instance"
|
2014-06-25 20:22:42 -05:00
|
|
|
|
|
|
|
STATE:
|
|
|
|
|
|
|
|
<no state>
|
2014-06-05 08:57:06 -05:00
|
|
|
`
|
2014-06-05 22:17:03 -05:00
|
|
|
|
2014-06-20 12:44:49 -05:00
|
|
|
const testTerraformPlanComputedStr = `
|
2014-06-25 20:22:42 -05:00
|
|
|
DIFF:
|
|
|
|
|
2014-06-10 13:37:04 -05:00
|
|
|
UPDATE: aws_instance.bar
|
2014-06-18 11:30:59 -05:00
|
|
|
foo: "" => "<computed>"
|
|
|
|
type: "" => "aws_instance"
|
2014-06-10 13:37:04 -05:00
|
|
|
UPDATE: aws_instance.foo
|
2014-07-07 16:57:41 -05:00
|
|
|
foo: "" => "<computed>"
|
|
|
|
num: "" => "2"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
|
|
|
|
STATE:
|
|
|
|
|
|
|
|
<no state>
|
|
|
|
`
|
|
|
|
|
|
|
|
const testTerraformPlanComputedIdStr = `
|
|
|
|
DIFF:
|
|
|
|
|
|
|
|
UPDATE: aws_instance.bar
|
|
|
|
foo: "" => "<computed>"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
UPDATE: aws_instance.foo
|
|
|
|
foo: "" => "<computed>"
|
2014-06-18 11:30:59 -05:00
|
|
|
num: "" => "2"
|
|
|
|
type: "" => "aws_instance"
|
2014-06-25 20:22:42 -05:00
|
|
|
|
|
|
|
STATE:
|
|
|
|
|
|
|
|
<no state>
|
|
|
|
`
|
|
|
|
|
2014-07-03 23:24:17 -05:00
|
|
|
const testTerraformPlanCountStr = `
|
|
|
|
DIFF:
|
|
|
|
|
|
|
|
UPDATE: aws_instance.bar
|
|
|
|
foo: "" => "foo,foo,foo,foo,foo"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
UPDATE: aws_instance.foo.0
|
|
|
|
foo: "" => "foo"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
UPDATE: aws_instance.foo.1
|
|
|
|
foo: "" => "foo"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
UPDATE: aws_instance.foo.2
|
|
|
|
foo: "" => "foo"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
UPDATE: aws_instance.foo.3
|
|
|
|
foo: "" => "foo"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
UPDATE: aws_instance.foo.4
|
|
|
|
foo: "" => "foo"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
|
|
|
|
STATE:
|
|
|
|
|
|
|
|
<no state>
|
|
|
|
`
|
|
|
|
|
2014-07-03 23:42:18 -05:00
|
|
|
const testTerraformPlanCountDecreaseStr = `
|
|
|
|
DIFF:
|
|
|
|
|
|
|
|
UPDATE: aws_instance.bar
|
|
|
|
foo: "" => "bar"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
DESTROY: aws_instance.foo.1
|
|
|
|
DESTROY: aws_instance.foo.2
|
|
|
|
|
|
|
|
STATE:
|
|
|
|
|
|
|
|
aws_instance.foo.0:
|
|
|
|
ID = bar
|
|
|
|
foo = foo
|
|
|
|
type = aws_instance
|
|
|
|
aws_instance.foo.1:
|
|
|
|
ID = bar
|
|
|
|
aws_instance.foo.2:
|
|
|
|
ID = bar
|
|
|
|
`
|
|
|
|
|
2014-07-03 23:47:07 -05:00
|
|
|
const testTerraformPlanCountIncreaseStr = `
|
|
|
|
DIFF:
|
|
|
|
|
|
|
|
UPDATE: aws_instance.bar
|
|
|
|
foo: "" => "bar"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
UPDATE: aws_instance.foo.1
|
|
|
|
foo: "" => "foo"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
UPDATE: aws_instance.foo.2
|
|
|
|
foo: "" => "foo"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
|
|
|
|
STATE:
|
|
|
|
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = bar
|
|
|
|
foo = foo
|
|
|
|
type = aws_instance
|
|
|
|
`
|
|
|
|
|
2014-06-29 18:28:50 -05:00
|
|
|
const testTerraformPlanDestroyStr = `
|
|
|
|
DIFF:
|
|
|
|
|
|
|
|
DESTROY: aws_instance.one
|
|
|
|
DESTROY: aws_instance.two
|
|
|
|
|
|
|
|
STATE:
|
|
|
|
|
|
|
|
aws_instance.one:
|
|
|
|
ID = bar
|
|
|
|
aws_instance.two:
|
|
|
|
ID = baz
|
|
|
|
`
|
|
|
|
|
2014-06-25 23:58:33 -05:00
|
|
|
const testTerraformPlanOrphanStr = `
|
|
|
|
DIFF:
|
|
|
|
|
|
|
|
DESTROY: aws_instance.baz
|
|
|
|
UPDATE: aws_instance.foo
|
|
|
|
num: "" => "2"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
|
|
|
|
STATE:
|
|
|
|
|
|
|
|
aws_instance.baz:
|
|
|
|
ID = bar
|
|
|
|
`
|
|
|
|
|
2014-06-25 20:22:42 -05:00
|
|
|
const testTerraformPlanStateStr = `
|
|
|
|
DIFF:
|
|
|
|
|
|
|
|
UPDATE: aws_instance.bar
|
|
|
|
foo: "" => "2"
|
|
|
|
type: "" => "aws_instance"
|
|
|
|
UPDATE: aws_instance.foo
|
|
|
|
num: "" => "2"
|
|
|
|
type: "" => ""
|
|
|
|
|
|
|
|
STATE:
|
|
|
|
|
|
|
|
aws_instance.foo:
|
|
|
|
ID = bar
|
2014-06-05 22:17:03 -05:00
|
|
|
`
|