mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-29 10:21:01 -06:00
b0eafeb212
fixes #1947 Root cause was a bad edge being made by the CBD transform going from the flattened destroy node to the unflattened create node, which was no longer in the graph. The destroy node therefore had a dependency that could never be satisfied, which locked up the walk.
6793 lines
146 KiB
Go
6793 lines
146 KiB
Go
package terraform
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestContext2Plan(t *testing.T) {
|
|
m := testModule(t, "plan-good")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if len(plan.Diff.RootModule().Resources) < 2 {
|
|
t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_emptyDiff(t *testing.T) {
|
|
m := testModule(t, "plan-empty")
|
|
p := testProvider("aws")
|
|
p.DiffFn = func(
|
|
info *InstanceInfo,
|
|
s *InstanceState,
|
|
c *ResourceConfig) (*InstanceDiff, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanEmptyStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_minimal(t *testing.T) {
|
|
m := testModule(t, "plan-empty")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanEmptyStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_modules(t *testing.T) {
|
|
m := testModule(t, "plan-modules")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModulesStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
// GH-1475
|
|
func TestContext2Plan_moduleCycle(t *testing.T) {
|
|
m := testModule(t, "plan-module-cycle")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleCycleStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleDeadlock(t *testing.T) {
|
|
m := testModule(t, "plan-module-deadlock")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
timeout := make(chan bool, 1)
|
|
done := make(chan bool, 1)
|
|
go func() {
|
|
time.Sleep(3 * time.Second)
|
|
timeout <- true
|
|
}()
|
|
go func() {
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
done <- true
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(`
|
|
DIFF:
|
|
|
|
module.child:
|
|
CREATE: aws_instance.foo.0
|
|
CREATE: aws_instance.foo.1
|
|
CREATE: aws_instance.foo.2
|
|
|
|
STATE:
|
|
|
|
<no state>
|
|
`)
|
|
if actual != expected {
|
|
t.Fatalf("expected:\n%sgot:\n%s", expected, actual)
|
|
}
|
|
}()
|
|
|
|
select {
|
|
case <-timeout:
|
|
t.Fatalf("timed out! probably deadlock")
|
|
case <-done:
|
|
// ok
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleInput(t *testing.T) {
|
|
m := testModule(t, "plan-module-input")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleInputStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleInputComputed(t *testing.T) {
|
|
m := testModule(t, "plan-module-input-computed")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleInputComputedStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleInputFromVar(t *testing.T) {
|
|
m := testModule(t, "plan-module-input-var")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "52",
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleInputVarStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleMultiVar(t *testing.T) {
|
|
m := testModule(t, "plan-module-multi-var")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleMultiVarStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleOrphans(t *testing.T) {
|
|
m := testModule(t, "plan-modules-remove")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: []string{"root", "child"},
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "baz",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleOrphansStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleProviderInherit(t *testing.T) {
|
|
var l sync.Mutex
|
|
var calls []string
|
|
|
|
m := testModule(t, "plan-module-provider-inherit")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": func() (ResourceProvider, error) {
|
|
l.Lock()
|
|
defer l.Unlock()
|
|
|
|
p := testProvider("aws")
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
if v, ok := c.Get("from"); !ok || v.(string) != "root" {
|
|
return fmt.Errorf("bad")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
p.DiffFn = func(
|
|
info *InstanceInfo,
|
|
state *InstanceState,
|
|
c *ResourceConfig) (*InstanceDiff, error) {
|
|
v, _ := c.Get("from")
|
|
calls = append(calls, v.(string))
|
|
return testDiffFn(info, state, c)
|
|
}
|
|
return p, nil
|
|
},
|
|
},
|
|
})
|
|
|
|
_, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := calls
|
|
sort.Strings(actual)
|
|
expected := []string{"child", "root"}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleProviderDefaults(t *testing.T) {
|
|
var l sync.Mutex
|
|
var calls []string
|
|
toCount := 0
|
|
|
|
m := testModule(t, "plan-module-provider-defaults")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": func() (ResourceProvider, error) {
|
|
l.Lock()
|
|
defer l.Unlock()
|
|
|
|
p := testProvider("aws")
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
if v, ok := c.Get("from"); !ok || v.(string) != "root" {
|
|
return fmt.Errorf("bad")
|
|
}
|
|
if v, ok := c.Get("to"); ok && v.(string) == "child" {
|
|
toCount++
|
|
}
|
|
|
|
return nil
|
|
}
|
|
p.DiffFn = func(
|
|
info *InstanceInfo,
|
|
state *InstanceState,
|
|
c *ResourceConfig) (*InstanceDiff, error) {
|
|
v, _ := c.Get("from")
|
|
calls = append(calls, v.(string))
|
|
return testDiffFn(info, state, c)
|
|
}
|
|
return p, nil
|
|
},
|
|
},
|
|
})
|
|
|
|
_, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if toCount != 1 {
|
|
t.Fatalf(
|
|
"provider in child didn't set proper config\n\n"+
|
|
"toCount: %d", toCount)
|
|
}
|
|
|
|
actual := calls
|
|
sort.Strings(actual)
|
|
expected := []string{"child", "root"}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleProviderDefaultsVar(t *testing.T) {
|
|
var l sync.Mutex
|
|
var calls []string
|
|
|
|
m := testModule(t, "plan-module-provider-defaults-var")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": func() (ResourceProvider, error) {
|
|
l.Lock()
|
|
defer l.Unlock()
|
|
|
|
p := testProvider("aws")
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
var buf bytes.Buffer
|
|
if v, ok := c.Get("from"); ok {
|
|
buf.WriteString(v.(string) + "\n")
|
|
}
|
|
if v, ok := c.Get("to"); ok {
|
|
buf.WriteString(v.(string) + "\n")
|
|
}
|
|
|
|
calls = append(calls, buf.String())
|
|
return nil
|
|
}
|
|
p.DiffFn = testDiffFn
|
|
return p, nil
|
|
},
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "root",
|
|
},
|
|
})
|
|
|
|
_, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
expected := []string{
|
|
"root\n",
|
|
"root\nchild\n",
|
|
}
|
|
if !reflect.DeepEqual(calls, expected) {
|
|
t.Fatalf("BAD: %#v", calls)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleVar(t *testing.T) {
|
|
m := testModule(t, "plan-module-var")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleVarStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleVarComputed(t *testing.T) {
|
|
m := testModule(t, "plan-module-var-computed")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleVarComputedStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_nil(t *testing.T) {
|
|
m := testModule(t, "plan-nil")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
if len(plan.Diff.RootModule().Resources) != 0 {
|
|
t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_preventDestroy_bad(t *testing.T) {
|
|
m := testModule(t, "plan-prevent-destroy-bad")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "i-abc123",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
|
|
expectedErr := "aws_instance.foo: plan would destroy"
|
|
if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
|
|
t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
|
|
expectedErr, err, plan)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_preventDestroy_good(t *testing.T) {
|
|
m := testModule(t, "plan-prevent-destroy-good")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "i-abc123",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
if !plan.Diff.Empty() {
|
|
t.Fatalf("Expected empty plan, got %s", plan.String())
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_preventDestroy_destroyPlan(t *testing.T) {
|
|
m := testModule(t, "plan-prevent-destroy-good")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "i-abc123",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Destroy: true,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
|
|
expectedErr := "aws_instance.foo: plan would destroy"
|
|
if !strings.Contains(fmt.Sprintf("%s", err), expectedErr) {
|
|
t.Fatalf("expected err would contain %q\nerr: %s\nplan: %s",
|
|
expectedErr, err, plan)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_providerAliasMissing(t *testing.T) {
|
|
m := testModule(t, "apply-provider-alias-missing")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Provider: "aws.foo",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"require_new": "abc",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err == nil {
|
|
t.Fatal("should err")
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_computed(t *testing.T) {
|
|
m := testModule(t, "plan-computed")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanComputedStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_computedList(t *testing.T) {
|
|
m := testModule(t, "plan-computed-list")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanComputedListStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_count(t *testing.T) {
|
|
m := testModule(t, "plan-count")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if len(plan.Diff.RootModule().Resources) < 6 {
|
|
t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_countComputed(t *testing.T) {
|
|
m := testModule(t, "plan-count-computed")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
_, err := ctx.Plan()
|
|
if err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_countIndex(t *testing.T) {
|
|
m := testModule(t, "plan-count-index")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountIndexStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_countIndexZero(t *testing.T) {
|
|
m := testModule(t, "plan-count-index-zero")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountIndexZeroStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_countVar(t *testing.T) {
|
|
m := testModule(t, "plan-count-var")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"count": "3",
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountVarStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_countZero(t *testing.T) {
|
|
m := testModule(t, "plan-count-zero")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountZeroStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_countOneIndex(t *testing.T) {
|
|
m := testModule(t, "plan-count-one-index")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountOneIndexStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_countDecreaseToOne(t *testing.T) {
|
|
m := testModule(t, "plan-count-dec")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo.0": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.foo.1": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
"aws_instance.foo.2": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountDecreaseStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_countIncreaseFromNotSet(t *testing.T) {
|
|
m := testModule(t, "plan-count-inc")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountIncreaseStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_countIncreaseFromOne(t *testing.T) {
|
|
m := testModule(t, "plan-count-inc")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo.0": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
// https://github.com/PeoplePerHour/terraform/pull/11
|
|
//
|
|
// This tests a case where both a "resource" and "resource.0" are in
|
|
// the state file, which apparently is a reasonable backwards compatibility
|
|
// concern found in the above 3rd party repo.
|
|
func TestContext2Plan_countIncreaseFromOneCorrupted(t *testing.T) {
|
|
m := testModule(t, "plan-count-inc")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.foo.0": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanCountIncreaseFromOneCorruptedStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_destroy(t *testing.T) {
|
|
m := testModule(t, "plan-destroy")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.one": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
"aws_instance.two": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "baz",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
Destroy: true,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if len(plan.Diff.RootModule().Resources) != 2 {
|
|
t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanDestroyStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleDestroy(t *testing.T) {
|
|
m := testModule(t, "plan-module-destroy")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
&ModuleState{
|
|
Path: []string{"root", "child"},
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
Destroy: true,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
// GH-1835
|
|
func TestContext2Plan_moduleDestroyCycle(t *testing.T) {
|
|
m := testModule(t, "plan-module-destroy-gh-1835")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: []string{"root", "a_module"},
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.a": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "a",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
&ModuleState{
|
|
Path: []string{"root", "b_module"},
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.b": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "b",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
Destroy: true,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_moduleDestroyMultivar(t *testing.T) {
|
|
m := testModule(t, "plan-module-destroy-multivar")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{},
|
|
},
|
|
&ModuleState{
|
|
Path: []string{"root", "child"},
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo.0": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar0",
|
|
},
|
|
},
|
|
"aws_instance.foo.1": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
Destroy: true,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_pathVar(t *testing.T) {
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
m := testModule(t, "plan-path-var")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanPathVarStr)
|
|
|
|
// Warning: this ordering REALLY matters for this test. The
|
|
// order is: cwd, module, root.
|
|
expected = fmt.Sprintf(
|
|
expected,
|
|
cwd,
|
|
m.Config().Dir,
|
|
m.Config().Dir)
|
|
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_diffVar(t *testing.T) {
|
|
m := testModule(t, "plan-diffvar")
|
|
p := testProvider("aws")
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"num": "2",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
p.DiffFn = func(
|
|
info *InstanceInfo,
|
|
s *InstanceState,
|
|
c *ResourceConfig) (*InstanceDiff, error) {
|
|
if s.ID != "bar" {
|
|
return testDiffFn(info, s, c)
|
|
}
|
|
|
|
return &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"num": &ResourceAttrDiff{
|
|
Old: "2",
|
|
New: "3",
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanDiffVarStr)
|
|
if actual != expected {
|
|
t.Fatalf("actual:\n%s\n\nexpected:\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_hook(t *testing.T) {
|
|
m := testModule(t, "plan-good")
|
|
h := new(MockHook)
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Hooks: []Hook{h},
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
_, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !h.PreDiffCalled {
|
|
t.Fatal("should be called")
|
|
}
|
|
if !h.PostDiffCalled {
|
|
t.Fatal("should be called")
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_orphan(t *testing.T) {
|
|
m := testModule(t, "plan-orphan")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.baz": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanOrphanStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_state(t *testing.T) {
|
|
m := testModule(t, "plan-good")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if len(plan.Diff.RootModule().Resources) < 2 {
|
|
t.Fatalf("bad: %#v", plan.Diff.RootModule().Resources)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanStateStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_taint(t *testing.T) {
|
|
m := testModule(t, "plan-taint")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{"num": "2"},
|
|
},
|
|
},
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "baz",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanTaintStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_multiple_taint(t *testing.T) {
|
|
m := testModule(t, "plan-taint")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{"num": "2"},
|
|
},
|
|
},
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "baz",
|
|
},
|
|
&InstanceState{
|
|
ID: "zip",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanMultipleTaintStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_targeted(t *testing.T) {
|
|
m := testModule(t, "plan-targeted")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Targets: []string{"aws_instance.foo"},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(`
|
|
DIFF:
|
|
|
|
CREATE: aws_instance.foo
|
|
num: "" => "2"
|
|
type: "" => "aws_instance"
|
|
|
|
STATE:
|
|
|
|
<no state>
|
|
`)
|
|
if actual != expected {
|
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_provider(t *testing.T) {
|
|
m := testModule(t, "plan-provider")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
|
|
var value interface{}
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
value, _ = c.Get("foo")
|
|
return nil
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "bar",
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if value != "bar" {
|
|
t.Fatalf("bad: %#v", value)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_varMultiCountOne(t *testing.T) {
|
|
m := testModule(t, "plan-var-multi-count-one")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
plan, err := ctx.Plan()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(plan.String())
|
|
expected := strings.TrimSpace(testTerraformPlanVarMultiCountOneStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Plan_varListErr(t *testing.T) {
|
|
m := testModule(t, "plan-var-list-err")
|
|
p := testProvider("aws")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
_, err := ctx.Plan()
|
|
if err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-basic")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
p.RefreshFn = nil
|
|
p.RefreshReturn = &InstanceState{
|
|
ID: "foo",
|
|
}
|
|
|
|
s, err := ctx.Refresh()
|
|
mod := s.RootModule()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
if !p.RefreshCalled {
|
|
t.Fatal("refresh should be called")
|
|
}
|
|
if p.RefreshState.ID != "foo" {
|
|
t.Fatalf("bad: %#v", p.RefreshState)
|
|
}
|
|
if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
|
|
t.Fatalf("bad: %#v %#v", mod.Resources["aws_instance.web"], p.RefreshReturn)
|
|
}
|
|
|
|
for _, r := range mod.Resources {
|
|
if r.Type == "" {
|
|
t.Fatalf("no type: %#v", r)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_targeted(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-targeted")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_vpc.metoo": resourceState("aws_vpc", "vpc-abc123"),
|
|
"aws_instance.notme": resourceState("aws_instance", "i-bcd345"),
|
|
"aws_instance.me": resourceState("aws_instance", "i-abc123"),
|
|
"aws_elb.meneither": resourceState("aws_elb", "lb-abc123"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Targets: []string{"aws_instance.me"},
|
|
})
|
|
|
|
refreshedResources := make([]string, 0, 2)
|
|
p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
|
|
refreshedResources = append(refreshedResources, i.Id)
|
|
return is, nil
|
|
}
|
|
|
|
_, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
expected := []string{"aws_vpc.metoo", "aws_instance.me"}
|
|
if !reflect.DeepEqual(refreshedResources, expected) {
|
|
t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_targetedCount(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-targeted-count")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_vpc.metoo": resourceState("aws_vpc", "vpc-abc123"),
|
|
"aws_instance.notme": resourceState("aws_instance", "i-bcd345"),
|
|
"aws_instance.me.0": resourceState("aws_instance", "i-abc123"),
|
|
"aws_instance.me.1": resourceState("aws_instance", "i-cde567"),
|
|
"aws_instance.me.2": resourceState("aws_instance", "i-cde789"),
|
|
"aws_elb.meneither": resourceState("aws_elb", "lb-abc123"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Targets: []string{"aws_instance.me"},
|
|
})
|
|
|
|
refreshedResources := make([]string, 0, 2)
|
|
p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
|
|
refreshedResources = append(refreshedResources, i.Id)
|
|
return is, nil
|
|
}
|
|
|
|
_, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// Target didn't specify index, so we should get all our instances
|
|
expected := []string{
|
|
"aws_vpc.metoo",
|
|
"aws_instance.me.0",
|
|
"aws_instance.me.1",
|
|
"aws_instance.me.2",
|
|
}
|
|
sort.Strings(expected)
|
|
sort.Strings(refreshedResources)
|
|
if !reflect.DeepEqual(refreshedResources, expected) {
|
|
t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_targetedCountIndex(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-targeted-count")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_vpc.metoo": resourceState("aws_vpc", "vpc-abc123"),
|
|
"aws_instance.notme": resourceState("aws_instance", "i-bcd345"),
|
|
"aws_instance.me.0": resourceState("aws_instance", "i-abc123"),
|
|
"aws_instance.me.1": resourceState("aws_instance", "i-cde567"),
|
|
"aws_instance.me.2": resourceState("aws_instance", "i-cde789"),
|
|
"aws_elb.meneither": resourceState("aws_elb", "lb-abc123"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Targets: []string{"aws_instance.me[0]"},
|
|
})
|
|
|
|
refreshedResources := make([]string, 0, 2)
|
|
p.RefreshFn = func(i *InstanceInfo, is *InstanceState) (*InstanceState, error) {
|
|
refreshedResources = append(refreshedResources, i.Id)
|
|
return is, nil
|
|
}
|
|
|
|
_, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
expected := []string{"aws_vpc.metoo", "aws_instance.me.0"}
|
|
if !reflect.DeepEqual(refreshedResources, expected) {
|
|
t.Fatalf("expected: %#v, got: %#v", expected, refreshedResources)
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_delete(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-basic")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
p.RefreshFn = nil
|
|
p.RefreshReturn = nil
|
|
|
|
s, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := s.RootModule()
|
|
if len(mod.Resources) > 0 {
|
|
t.Fatal("resources should be empty")
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_ignoreUncreated(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-basic")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: nil,
|
|
})
|
|
|
|
p.RefreshFn = nil
|
|
p.RefreshReturn = &InstanceState{
|
|
ID: "foo",
|
|
}
|
|
|
|
_, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
if p.RefreshCalled {
|
|
t.Fatal("refresh should not be called")
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_hook(t *testing.T) {
|
|
h := new(MockHook)
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-basic")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Hooks: []Hook{h},
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Refresh(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
if !h.PreRefreshCalled {
|
|
t.Fatal("should be called")
|
|
}
|
|
if !h.PostRefreshCalled {
|
|
t.Fatal("should be called")
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_modules(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-modules")
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
&ModuleState{
|
|
Path: []string{"root", "child"},
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "baz",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
|
|
if s.ID != "baz" {
|
|
return s, nil
|
|
}
|
|
|
|
s.ID = "new"
|
|
return s, nil
|
|
}
|
|
|
|
s, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(s.String())
|
|
expected := strings.TrimSpace(testContextRefreshModuleStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_moduleInputComputedOutput(t *testing.T) {
|
|
m := testModule(t, "refresh-module-input-computed-output")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Refresh(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_moduleVarModule(t *testing.T) {
|
|
m := testModule(t, "refresh-module-var-module")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Refresh(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
}
|
|
|
|
// GH-70
|
|
func TestContext2Refresh_noState(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-no-state")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.RefreshFn = nil
|
|
p.RefreshReturn = &InstanceState{
|
|
ID: "foo",
|
|
}
|
|
|
|
if _, err := ctx.Refresh(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_output(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-output")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "foo",
|
|
Attributes: map[string]string{
|
|
"foo": "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
Outputs: map[string]string{
|
|
"foo": "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
|
|
return s, nil
|
|
}
|
|
|
|
s, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(s.String())
|
|
expected := strings.TrimSpace(testContextRefreshOutputStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_outputPartial(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-output-partial")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
p.RefreshFn = nil
|
|
p.RefreshReturn = nil
|
|
|
|
s, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(s.String())
|
|
expected := strings.TrimSpace(testContextRefreshOutputPartialStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_state(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-basic")
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
p.RefreshFn = nil
|
|
p.RefreshReturn = &InstanceState{
|
|
ID: "foo",
|
|
}
|
|
|
|
s, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
originalMod := state.RootModule()
|
|
mod := s.RootModule()
|
|
if !p.RefreshCalled {
|
|
t.Fatal("refresh should be called")
|
|
}
|
|
if !reflect.DeepEqual(p.RefreshState, originalMod.Resources["aws_instance.web"].Primary) {
|
|
t.Fatalf(
|
|
"bad:\n\n%#v\n\n%#v",
|
|
p.RefreshState,
|
|
originalMod.Resources["aws_instance.web"].Primary)
|
|
}
|
|
if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
|
|
t.Fatalf("bad: %#v", mod.Resources)
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_tainted(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-basic")
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
p.RefreshFn = nil
|
|
p.RefreshReturn = &InstanceState{
|
|
ID: "foo",
|
|
}
|
|
|
|
s, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
if !p.RefreshCalled {
|
|
t.Fatal("refresh should be called")
|
|
}
|
|
|
|
actual := strings.TrimSpace(s.String())
|
|
expected := strings.TrimSpace(testContextRefreshTaintedStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n\n%s\n\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
// Doing a Refresh (or any operation really, but Refresh usually
|
|
// happens first) with a config with an unknown provider should result in
|
|
// an error. The key bug this found was that this wasn't happening if
|
|
// Providers was _empty_.
|
|
func TestContext2Refresh_unknownProvider(t *testing.T) {
|
|
m := testModule(t, "refresh-unknown-provider")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{},
|
|
})
|
|
|
|
if _, err := ctx.Refresh(); err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
}
|
|
|
|
func TestContext2Refresh_vars(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "refresh-vars")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "foo",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
p.RefreshFn = nil
|
|
p.RefreshReturn = &InstanceState{
|
|
ID: "foo",
|
|
}
|
|
|
|
s, err := ctx.Refresh()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
mod := s.RootModule()
|
|
if !p.RefreshCalled {
|
|
t.Fatal("refresh should be called")
|
|
}
|
|
if p.RefreshState.ID != "foo" {
|
|
t.Fatalf("bad: %#v", p.RefreshState)
|
|
}
|
|
if !reflect.DeepEqual(mod.Resources["aws_instance.web"].Primary, p.RefreshReturn) {
|
|
t.Fatalf("bad: %#v", mod.Resources["aws_instance.web"])
|
|
}
|
|
|
|
for _, r := range mod.Resources {
|
|
if r.Type == "" {
|
|
t.Fatalf("no type: %#v", r)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-good")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_badVar(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-bad-var")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_countNegative(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-count-negative")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_countVariable(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "apply-count-variable")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_countVariableNoDefault(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-count-variable")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) != 1 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
/*
|
|
TODO: What should we do here?
|
|
func TestContext2Validate_cycle(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-cycle")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("expected no warns, got: %#v", w)
|
|
}
|
|
if len(e) != 1 {
|
|
t.Fatalf("expected 1 err, got: %s", e)
|
|
}
|
|
}
|
|
*/
|
|
|
|
func TestContext2Validate_moduleBadOutput(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-bad-module-output")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_moduleGood(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-good-module")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_moduleBadResource(t *testing.T) {
|
|
m := testModule(t, "validate-module-bad-rc")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_moduleDepsShouldNotCycle(t *testing.T) {
|
|
m := testModule(t, "validate-module-deps-cycle")
|
|
p := testProvider("aws")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := ctx.Validate()
|
|
|
|
if len(w) > 0 {
|
|
t.Fatalf("expected no warnings, got: %s", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("expected no errors, got: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_moduleProviderInherit(t *testing.T) {
|
|
m := testModule(t, "validate-module-pc-inherit")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
|
|
return nil, c.CheckSet([]string{"set"})
|
|
}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_moduleProviderVar(t *testing.T) {
|
|
m := testModule(t, "validate-module-pc-vars")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"provider_var": "bar",
|
|
},
|
|
})
|
|
|
|
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
|
|
return nil, c.CheckSet([]string{"foo"})
|
|
}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_moduleProviderInheritUnused(t *testing.T) {
|
|
m := testModule(t, "validate-module-pc-inherit-unused")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
|
|
return nil, c.CheckSet([]string{"foo"})
|
|
}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_orphans(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-good")
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
p.ValidateResourceFn = func(
|
|
t string, c *ResourceConfig) ([]string, []error) {
|
|
return nil, c.CheckSet([]string{"foo"})
|
|
}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_providerConfig_bad(t *testing.T) {
|
|
m := testModule(t, "validate-bad-pc")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.ValidateReturnErrors = []error{fmt.Errorf("bad")}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
if !strings.Contains(fmt.Sprintf("%s", e), "bad") {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_providerConfig_badEmpty(t *testing.T) {
|
|
m := testModule(t, "validate-bad-pc-empty")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.ValidateReturnErrors = []error{fmt.Errorf("bad")}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_providerConfig_good(t *testing.T) {
|
|
m := testModule(t, "validate-bad-pc")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_provisionerConfig_bad(t *testing.T) {
|
|
m := testModule(t, "validate-bad-prov-conf")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
})
|
|
|
|
pr.ValidateReturnErrors = []error{fmt.Errorf("bad")}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_provisionerConfig_good(t *testing.T) {
|
|
m := testModule(t, "validate-bad-prov-conf")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
pr.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
|
|
if c == nil {
|
|
t.Fatalf("missing resource config for provisioner")
|
|
}
|
|
return nil, c.CheckSet([]string{"command"})
|
|
}
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_requiredVar(t *testing.T) {
|
|
m := testModule(t, "validate-required-var")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_resourceConfig_bad(t *testing.T) {
|
|
m := testModule(t, "validate-bad-rc")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.ValidateResourceReturnErrors = []error{fmt.Errorf("bad")}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_resourceConfig_good(t *testing.T) {
|
|
m := testModule(t, "validate-bad-rc")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_resourceNameSymbol(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-resource-name-symbol")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) == 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_selfRef(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-self-ref")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_selfRefMulti(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-self-ref-multi")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_selfRefMultiAll(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-self-ref-multi-all")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) == 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_tainted(t *testing.T) {
|
|
p := testProvider("aws")
|
|
m := testModule(t, "validate-good")
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
p.ValidateResourceFn = func(
|
|
t string, c *ResourceConfig) ([]string, []error) {
|
|
return nil, c.CheckSet([]string{"foo"})
|
|
}
|
|
|
|
w, e := c.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %#v", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_targetedDestroy(t *testing.T) {
|
|
m := testModule(t, "validate-targeted")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": resourceState("aws_instance", "i-bcd345"),
|
|
"aws_instance.bar": resourceState("aws_instance", "i-abc123"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Targets: []string{"aws_instance.foo"},
|
|
Destroy: true,
|
|
})
|
|
|
|
w, e := ctx.Validate()
|
|
if len(w) > 0 {
|
|
warnStr := ""
|
|
for _, v := range w {
|
|
warnStr = warnStr + " " + v
|
|
}
|
|
t.Fatalf("bad: %s", warnStr)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_varRef(t *testing.T) {
|
|
m := testModule(t, "validate-variable-ref")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
computed := false
|
|
p.ValidateResourceFn = func(t string, c *ResourceConfig) ([]string, []error) {
|
|
computed = c.IsComputed("foo")
|
|
return nil, nil
|
|
}
|
|
|
|
c.Validate()
|
|
if !computed {
|
|
t.Fatal("should be computed")
|
|
}
|
|
}
|
|
|
|
func TestContext2Validate_varRefFilled(t *testing.T) {
|
|
m := testModule(t, "validate-variable-ref")
|
|
p := testProvider("aws")
|
|
c := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "bar",
|
|
},
|
|
})
|
|
|
|
var value interface{}
|
|
p.ValidateResourceFn = func(t string, c *ResourceConfig) ([]string, []error) {
|
|
value, _ = c.Get("foo")
|
|
return nil, nil
|
|
}
|
|
|
|
c.Validate()
|
|
if value != "bar" {
|
|
t.Fatalf("bad: %#v", value)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input(t *testing.T) {
|
|
input := new(MockUIInput)
|
|
m := testModule(t, "input-vars")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "us-west-2",
|
|
"amis.us-east-1": "override",
|
|
},
|
|
UIInput: input,
|
|
})
|
|
|
|
input.InputReturnMap = map[string]string{
|
|
"var.foo": "us-east-1",
|
|
}
|
|
|
|
if err := ctx.Input(InputModeStd); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformInputVarsStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_badVarDefault(t *testing.T) {
|
|
m := testModule(t, "input-bad-var-default")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
c.Config["foo"] = "bar"
|
|
return c, nil
|
|
}
|
|
|
|
if err := ctx.Input(InputModeStd); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_provider(t *testing.T) {
|
|
m := testModule(t, "input-provider")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
var actual interface{}
|
|
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
c.Config["foo"] = "bar"
|
|
return c, nil
|
|
}
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
actual = c.Config["foo"]
|
|
return nil
|
|
}
|
|
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
|
|
return nil, c.CheckSet([]string{"foo"})
|
|
}
|
|
|
|
if err := ctx.Input(InputModeStd); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Apply(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(actual, "bar") {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_providerMulti(t *testing.T) {
|
|
m := testModule(t, "input-provider-multi")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
var actual []interface{}
|
|
var lock sync.Mutex
|
|
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
c.Config["foo"] = "bar"
|
|
return c, nil
|
|
}
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
lock.Lock()
|
|
defer lock.Unlock()
|
|
actual = append(actual, c.Config["foo"])
|
|
return nil
|
|
}
|
|
p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
|
|
return nil, c.CheckSet([]string{"foo"})
|
|
}
|
|
|
|
if err := ctx.Input(InputModeStd); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Apply(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
expected := []interface{}{"bar", "bar"}
|
|
if !reflect.DeepEqual(actual, expected) {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_providerOnce(t *testing.T) {
|
|
m := testModule(t, "input-provider-once")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
count := 0
|
|
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
count++
|
|
return nil, nil
|
|
}
|
|
|
|
if err := ctx.Input(InputModeStd); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if count != 1 {
|
|
t.Fatalf("should only be called once: %d", count)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_providerId(t *testing.T) {
|
|
input := new(MockUIInput)
|
|
m := testModule(t, "input-provider")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
UIInput: input,
|
|
})
|
|
|
|
var actual interface{}
|
|
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
v, err := i.Input(&InputOpts{Id: "foo"})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
c.Config["foo"] = v
|
|
return c, nil
|
|
}
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
actual = c.Config["foo"]
|
|
return nil
|
|
}
|
|
|
|
input.InputReturnMap = map[string]string{
|
|
"provider.aws.foo": "bar",
|
|
}
|
|
|
|
if err := ctx.Input(InputModeStd); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Apply(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(actual, "bar") {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_providerOnly(t *testing.T) {
|
|
input := new(MockUIInput)
|
|
m := testModule(t, "input-provider-vars")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "us-west-2",
|
|
},
|
|
UIInput: input,
|
|
})
|
|
|
|
input.InputReturnMap = map[string]string{
|
|
"var.foo": "us-east-1",
|
|
}
|
|
|
|
var actual interface{}
|
|
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
c.Config["foo"] = "bar"
|
|
return c, nil
|
|
}
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
actual = c.Config["foo"]
|
|
return nil
|
|
}
|
|
|
|
if err := ctx.Input(InputModeProvider); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(actual, "bar") {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
actualStr := strings.TrimSpace(state.String())
|
|
expectedStr := strings.TrimSpace(testTerraformInputProviderOnlyStr)
|
|
if actualStr != expectedStr {
|
|
t.Fatalf("bad: \n%s", actualStr)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_providerVars(t *testing.T) {
|
|
input := new(MockUIInput)
|
|
m := testModule(t, "input-provider-with-vars")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "bar",
|
|
},
|
|
UIInput: input,
|
|
})
|
|
|
|
input.InputReturnMap = map[string]string{
|
|
"var.foo": "bar",
|
|
}
|
|
|
|
var actual interface{}
|
|
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
c.Config["bar"] = "baz"
|
|
return c, nil
|
|
}
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
actual, _ = c.Get("foo")
|
|
return nil
|
|
}
|
|
|
|
if err := ctx.Input(InputModeStd); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Apply(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(actual, "bar") {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_providerVarsModuleInherit(t *testing.T) {
|
|
input := new(MockUIInput)
|
|
m := testModule(t, "input-provider-with-vars-and-module")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
UIInput: input,
|
|
})
|
|
|
|
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
if errs := c.CheckSet([]string{"access_key"}); len(errs) > 0 {
|
|
return c, errs[0]
|
|
}
|
|
return c, nil
|
|
}
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
return nil
|
|
}
|
|
|
|
if err := ctx.Input(InputModeStd); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_varOnly(t *testing.T) {
|
|
input := new(MockUIInput)
|
|
m := testModule(t, "input-provider-vars")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "us-west-2",
|
|
},
|
|
UIInput: input,
|
|
})
|
|
|
|
input.InputReturnMap = map[string]string{
|
|
"var.foo": "us-east-1",
|
|
}
|
|
|
|
var actual interface{}
|
|
p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
|
|
c.Raw["foo"] = "bar"
|
|
return c, nil
|
|
}
|
|
p.ConfigureFn = func(c *ResourceConfig) error {
|
|
actual = c.Raw["foo"]
|
|
return nil
|
|
}
|
|
|
|
if err := ctx.Input(InputModeVar); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if reflect.DeepEqual(actual, "bar") {
|
|
t.Fatalf("bad: %#v", actual)
|
|
}
|
|
|
|
actualStr := strings.TrimSpace(state.String())
|
|
expectedStr := strings.TrimSpace(testTerraformInputVarOnlyStr)
|
|
if actualStr != expectedStr {
|
|
t.Fatalf("bad: \n%s", actualStr)
|
|
}
|
|
}
|
|
|
|
func TestContext2Input_varOnlyUnset(t *testing.T) {
|
|
input := new(MockUIInput)
|
|
m := testModule(t, "input-vars-unset")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "foovalue",
|
|
},
|
|
UIInput: input,
|
|
})
|
|
|
|
input.InputReturnMap = map[string]string{
|
|
"var.foo": "nope",
|
|
"var.bar": "baz",
|
|
}
|
|
|
|
if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actualStr := strings.TrimSpace(state.String())
|
|
expectedStr := strings.TrimSpace(testTerraformInputVarOnlyUnsetStr)
|
|
if actualStr != expectedStr {
|
|
t.Fatalf("bad: \n%s", actualStr)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply(t *testing.T) {
|
|
m := testModule(t, "apply-good")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) < 2 {
|
|
t.Fatalf("bad: %#v", mod.Resources)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_providerAlias(t *testing.T) {
|
|
m := testModule(t, "apply-provider-alias")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) < 2 {
|
|
t.Fatalf("bad: %#v", mod.Resources)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProviderAliasStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_emptyModule(t *testing.T) {
|
|
m := testModule(t, "apply-empty-module")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
actual = strings.Replace(actual, " ", "", -1)
|
|
expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_createBeforeDestroy(t *testing.T) {
|
|
m := testModule(t, "apply-good-create-before")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"require_new": "abc",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
if p, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
} else {
|
|
t.Logf(p.String())
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) != 1 {
|
|
t.Fatalf("bad: %s", state)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) {
|
|
m := testModule(t, "apply-good-create-before-update")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
if p, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
} else {
|
|
t.Logf(p.String())
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) != 1 {
|
|
t.Fatalf("bad: %s", state)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_minimal(t *testing.T) {
|
|
m := testModule(t, "apply-minimal")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyMinimalStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_badDiff(t *testing.T) {
|
|
m := testModule(t, "apply-good")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) {
|
|
return &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"newp": nil,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
if _, err := ctx.Apply(); err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_cancel(t *testing.T) {
|
|
stopped := false
|
|
|
|
m := testModule(t, "apply-cancel")
|
|
p := testProvider("aws")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) {
|
|
if !stopped {
|
|
stopped = true
|
|
go ctx.Stop()
|
|
|
|
for {
|
|
if ctx.sh.Stopped() {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
return &InstanceState{
|
|
ID: "foo",
|
|
Attributes: map[string]string{
|
|
"num": "2",
|
|
},
|
|
}, nil
|
|
}
|
|
p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) {
|
|
return &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"num": &ResourceAttrDiff{
|
|
New: "bar",
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// Start the Apply in a goroutine
|
|
stateCh := make(chan *State)
|
|
go func() {
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
stateCh <- state
|
|
}()
|
|
|
|
state := <-stateCh
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) != 1 {
|
|
t.Fatalf("bad: %s", state.String())
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyCancelStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_compute(t *testing.T) {
|
|
m := testModule(t, "apply-compute")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
ctx.variables = map[string]string{"value": "1"}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyComputeStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_countDecrease(t *testing.T) {
|
|
m := testModule(t, "apply-count-dec")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo.0": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.foo.1": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.foo.2": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyCountDecStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_countDecreaseToOne(t *testing.T) {
|
|
m := testModule(t, "apply-count-dec-one")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo.0": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.foo.1": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
"aws_instance.foo.2": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
// https://github.com/PeoplePerHour/terraform/pull/11
|
|
//
|
|
// This tests a case where both a "resource" and "resource.0" are in
|
|
// the state file, which apparently is a reasonable backwards compatibility
|
|
// concern found in the above 3rd party repo.
|
|
func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) {
|
|
m := testModule(t, "apply-count-dec-one")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.foo.0": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "baz",
|
|
Attributes: map[string]string{
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
if p, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
} else {
|
|
testStringMatch(t, p, testTerraformApplyCountDecToOneCorruptedPlanStr)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_countTainted(t *testing.T) {
|
|
m := testModule(t, "apply-count-tainted")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo.0": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "foo",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyCountTaintedStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_countVariable(t *testing.T) {
|
|
m := testModule(t, "apply-count-variable")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyCountVariableStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_module(t *testing.T) {
|
|
m := testModule(t, "apply-module")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyModuleStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_moduleDestroyOrder(t *testing.T) {
|
|
m := testModule(t, "apply-module-destroy-order")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
|
|
// Create a custom apply function to track the order they were destroyed
|
|
var order []string
|
|
var orderLock sync.Mutex
|
|
p.ApplyFn = func(
|
|
info *InstanceInfo,
|
|
is *InstanceState,
|
|
id *InstanceDiff) (*InstanceState, error) {
|
|
orderLock.Lock()
|
|
defer orderLock.Unlock()
|
|
|
|
order = append(order, is.ID)
|
|
return nil, nil
|
|
}
|
|
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.b": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "b",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
&ModuleState{
|
|
Path: []string{"root", "child"},
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.a": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "a",
|
|
},
|
|
},
|
|
},
|
|
Outputs: map[string]string{
|
|
"a_output": "a",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
Destroy: true,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
expected := []string{"b", "a"}
|
|
if !reflect.DeepEqual(order, expected) {
|
|
t.Fatalf("bad: %#v", order)
|
|
}
|
|
|
|
{
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_moduleVarResourceCount(t *testing.T) {
|
|
m := testModule(t, "apply-module-var-resource-count")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"count": "2",
|
|
},
|
|
Destroy: true,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Apply(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
ctx = testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"count": "5",
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Apply(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
}
|
|
|
|
// GH-819
|
|
func TestContext2Apply_moduleBool(t *testing.T) {
|
|
m := testModule(t, "apply-module-bool")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyModuleBoolStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_multiProvider(t *testing.T) {
|
|
m := testModule(t, "apply-multi-provider")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
|
|
pDO := testProvider("do")
|
|
pDO.ApplyFn = testApplyFn
|
|
pDO.DiffFn = testDiffFn
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
"do": testProviderFuncFixed(pDO),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) < 2 {
|
|
t.Fatalf("bad: %#v", mod.Resources)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyMultiProviderStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_nilDiff(t *testing.T) {
|
|
m := testModule(t, "apply-good")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
if _, err := ctx.Apply(); err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_outputOrphan(t *testing.T) {
|
|
m := testModule(t, "apply-output-orphan")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Outputs: map[string]string{
|
|
"foo": "bar",
|
|
"bar": "baz",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_Provisioner_compute(t *testing.T) {
|
|
m := testModule(t, "apply-provisioner-compute")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
|
|
val, ok := c.Config["foo"]
|
|
if !ok || val != "computed_dynamical" {
|
|
t.Fatalf("bad value for foo: %v %#v", val, c)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
Variables: map[string]string{
|
|
"value": "1",
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
|
|
// Verify apply was invoked
|
|
if !pr.ApplyCalled {
|
|
t.Fatalf("provisioner not invoked")
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_provisionerCreateFail(t *testing.T) {
|
|
m := testModule(t, "apply-provisioner-fail-create")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.DiffFn = testDiffFn
|
|
|
|
p.ApplyFn = func(
|
|
info *InstanceInfo,
|
|
is *InstanceState,
|
|
id *InstanceDiff) (*InstanceState, error) {
|
|
is.ID = "foo"
|
|
return is, fmt.Errorf("error")
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) {
|
|
m := testModule(t, "apply-provisioner-fail-create")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.DiffFn = testDiffFn
|
|
|
|
p.ApplyFn = func(
|
|
info *InstanceInfo,
|
|
is *InstanceState,
|
|
id *InstanceDiff) (*InstanceState, error) {
|
|
return nil, fmt.Errorf("error")
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_provisionerFail(t *testing.T) {
|
|
m := testModule(t, "apply-provisioner-fail")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
|
|
pr.ApplyFn = func(*InstanceState, *ResourceConfig) error {
|
|
return fmt.Errorf("EXPLOSION")
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
Variables: map[string]string{
|
|
"value": "1",
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) {
|
|
m := testModule(t, "apply-provisioner-fail-create-before")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
pr.ApplyFn = func(*InstanceState, *ResourceConfig) error {
|
|
return fmt.Errorf("EXPLOSION")
|
|
}
|
|
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"require_new": "abc",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_error_createBeforeDestroy(t *testing.T) {
|
|
m := testModule(t, "apply-error-create-before")
|
|
p := testProvider("aws")
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"require_new": "abc",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) {
|
|
return nil, fmt.Errorf("error")
|
|
}
|
|
p.DiffFn = testDiffFn
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should have error")
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s\n\nExpected:\n\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) {
|
|
m := testModule(t, "apply-error-create-before")
|
|
p := testProvider("aws")
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"require_new": "abc",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) {
|
|
// Fail the destroy!
|
|
if id.Destroy {
|
|
return is, fmt.Errorf("error")
|
|
}
|
|
|
|
// Create should work
|
|
is = &InstanceState{
|
|
ID: "foo",
|
|
}
|
|
return is, nil
|
|
}
|
|
p.DiffFn = testDiffFn
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should have error")
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) {
|
|
m := testModule(t, "apply-multi-depose-create-before-destroy")
|
|
p := testProvider("aws")
|
|
p.DiffFn = testDiffFn
|
|
ps := map[string]ResourceProviderFactory{"aws": testProviderFuncFixed(p)}
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{ID: "foo"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: ps,
|
|
State: state,
|
|
})
|
|
createdInstanceId := "bar"
|
|
// Create works
|
|
createFunc := func(is *InstanceState) (*InstanceState, error) {
|
|
return &InstanceState{ID: createdInstanceId}, nil
|
|
}
|
|
// Destroy starts broken
|
|
destroyFunc := func(is *InstanceState) (*InstanceState, error) {
|
|
return is, fmt.Errorf("destroy failed")
|
|
}
|
|
p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) {
|
|
if id.Destroy {
|
|
return destroyFunc(is)
|
|
} else {
|
|
return createFunc(is)
|
|
}
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// Destroy is broken, so even though CBD successfully replaces the instance,
|
|
// we'll have to save the Deposed instance to destroy later
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should have error")
|
|
}
|
|
|
|
checkStateString(t, state, `
|
|
aws_instance.web: (1 deposed)
|
|
ID = bar
|
|
Deposed ID 1 = foo
|
|
`)
|
|
|
|
createdInstanceId = "baz"
|
|
ctx = testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: ps,
|
|
State: state,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// We're replacing the primary instance once again. Destroy is _still_
|
|
// broken, so the Deposed list gets longer
|
|
state, err = ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should have error")
|
|
}
|
|
|
|
checkStateString(t, state, `
|
|
aws_instance.web: (2 deposed)
|
|
ID = baz
|
|
Deposed ID 1 = foo
|
|
Deposed ID 2 = bar
|
|
`)
|
|
|
|
// Destroy partially fixed!
|
|
destroyFunc = func(is *InstanceState) (*InstanceState, error) {
|
|
if is.ID == "foo" || is.ID == "baz" {
|
|
return nil, nil
|
|
} else {
|
|
return is, fmt.Errorf("destroy partially failed")
|
|
}
|
|
}
|
|
|
|
createdInstanceId = "qux"
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
state, err = ctx.Apply()
|
|
// Expect error because 1/2 of Deposed destroys failed
|
|
if err == nil {
|
|
t.Fatal("should have error")
|
|
}
|
|
|
|
// foo and baz are now gone, bar sticks around
|
|
checkStateString(t, state, `
|
|
aws_instance.web: (1 deposed)
|
|
ID = qux
|
|
Deposed ID 1 = bar
|
|
`)
|
|
|
|
// Destroy working fully!
|
|
destroyFunc = func(is *InstanceState) (*InstanceState, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
createdInstanceId = "quux"
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
state, err = ctx.Apply()
|
|
if err != nil {
|
|
t.Fatal("should not have error:", err)
|
|
}
|
|
|
|
// And finally the state is clean
|
|
checkStateString(t, state, `
|
|
aws_instance.web:
|
|
ID = quux
|
|
`)
|
|
}
|
|
|
|
func TestContext2Apply_provisionerResourceRef(t *testing.T) {
|
|
m := testModule(t, "apply-provisioner-resource-ref")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
|
|
val, ok := c.Config["foo"]
|
|
if !ok || val != "2" {
|
|
t.Fatalf("bad value for foo: %v %#v", val, c)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
|
|
// Verify apply was invoked
|
|
if !pr.ApplyCalled {
|
|
t.Fatalf("provisioner not invoked")
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_provisionerSelfRef(t *testing.T) {
|
|
m := testModule(t, "apply-provisioner-self-ref")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
|
|
val, ok := c.Config["command"]
|
|
if !ok || val != "bar" {
|
|
t.Fatalf("bad value for command: %v %#v", val, c)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
|
|
// Verify apply was invoked
|
|
if !pr.ApplyCalled {
|
|
t.Fatalf("provisioner not invoked")
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) {
|
|
var lock sync.Mutex
|
|
commands := make([]string, 0, 5)
|
|
|
|
m := testModule(t, "apply-provisioner-multi-self-ref")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
|
|
lock.Lock()
|
|
defer lock.Unlock()
|
|
|
|
val, ok := c.Config["command"]
|
|
if !ok {
|
|
t.Fatalf("bad value for command: %v %#v", val, c)
|
|
}
|
|
|
|
commands = append(commands, val.(string))
|
|
return nil
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
|
|
// Verify apply was invoked
|
|
if !pr.ApplyCalled {
|
|
t.Fatalf("provisioner not invoked")
|
|
}
|
|
|
|
// Verify our result
|
|
sort.Strings(commands)
|
|
expectedCommands := []string{"number 0", "number 1", "number 2"}
|
|
if !reflect.DeepEqual(commands, expectedCommands) {
|
|
t.Fatalf("bad: %#v", commands)
|
|
}
|
|
}
|
|
|
|
// Provisioner should NOT run on a diff, only create
|
|
func TestContext2Apply_Provisioner_Diff(t *testing.T) {
|
|
m := testModule(t, "apply-provisioner-diff")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
|
|
return nil
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
|
|
// Verify apply was invoked
|
|
if !pr.ApplyCalled {
|
|
t.Fatalf("provisioner not invoked")
|
|
}
|
|
pr.ApplyCalled = false
|
|
|
|
// Change the state to force a diff
|
|
mod := state.RootModule()
|
|
mod.Resources["aws_instance.bar"].Primary.Attributes["foo"] = "baz"
|
|
|
|
// Re-create context with state
|
|
ctx = testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state2, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual = strings.TrimSpace(state2.String())
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
|
|
// Verify apply was NOT invoked
|
|
if pr.ApplyCalled {
|
|
t.Fatalf("provisioner invoked")
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_outputDiffVars(t *testing.T) {
|
|
m := testModule(t, "apply-good")
|
|
p := testProvider("aws")
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.baz": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
|
|
for k, ad := range d.Attributes {
|
|
if ad.NewComputed {
|
|
return nil, fmt.Errorf("%s: computed", k)
|
|
}
|
|
}
|
|
|
|
result := s.MergeDiff(d)
|
|
result.ID = "foo"
|
|
return result, nil
|
|
}
|
|
p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) {
|
|
return &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"foo": &ResourceAttrDiff{
|
|
NewComputed: true,
|
|
Type: DiffAttrOutput,
|
|
},
|
|
"bar": &ResourceAttrDiff{
|
|
New: "baz",
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
if _, err := ctx.Apply(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_Provisioner_ConnInfo(t *testing.T) {
|
|
m := testModule(t, "apply-provisioner-conninfo")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
|
|
p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
|
|
if s.Ephemeral.ConnInfo == nil {
|
|
t.Fatalf("ConnInfo not initialized")
|
|
}
|
|
|
|
result, _ := testApplyFn(info, s, d)
|
|
result.Ephemeral.ConnInfo = map[string]string{
|
|
"type": "ssh",
|
|
"host": "127.0.0.1",
|
|
"port": "22",
|
|
}
|
|
return result, nil
|
|
}
|
|
p.DiffFn = testDiffFn
|
|
|
|
pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
|
|
conn := rs.Ephemeral.ConnInfo
|
|
if conn["type"] != "telnet" {
|
|
t.Fatalf("Bad: %#v", conn)
|
|
}
|
|
if conn["host"] != "127.0.0.1" {
|
|
t.Fatalf("Bad: %#v", conn)
|
|
}
|
|
if conn["port"] != "2222" {
|
|
t.Fatalf("Bad: %#v", conn)
|
|
}
|
|
if conn["user"] != "superuser" {
|
|
t.Fatalf("Bad: %#v", conn)
|
|
}
|
|
if conn["pass"] != "test" {
|
|
t.Fatalf("Bad: %#v", conn)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
Variables: map[string]string{
|
|
"value": "1",
|
|
"pass": "test",
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyProvisionerStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
|
|
// Verify apply was invoked
|
|
if !pr.ApplyCalled {
|
|
t.Fatalf("provisioner not invoked")
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_destroy(t *testing.T) {
|
|
m := testModule(t, "apply-destroy")
|
|
h := new(HookRecordApplyOrder)
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Hooks: []Hook{h},
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
// First plan and apply a create operation
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// Next, plan and apply a destroy operation
|
|
h.Active = true
|
|
ctx = testContext2(t, &ContextOpts{
|
|
Destroy: true,
|
|
State: state,
|
|
Module: m,
|
|
Hooks: []Hook{h},
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err = ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// Test that things were destroyed
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyDestroyStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
|
|
// Test that things were destroyed _in the right order_
|
|
expected2 := []string{"aws_instance.bar", "aws_instance.foo"}
|
|
actual2 := h.IDs
|
|
if !reflect.DeepEqual(actual2, expected2) {
|
|
t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_destroyOutputs(t *testing.T) {
|
|
m := testModule(t, "apply-destroy-outputs")
|
|
h := new(HookRecordApplyOrder)
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Hooks: []Hook{h},
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
// First plan and apply a create operation
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// Next, plan and apply a destroy operation
|
|
h.Active = true
|
|
ctx = testContext2(t, &ContextOpts{
|
|
Destroy: true,
|
|
State: state,
|
|
Module: m,
|
|
Hooks: []Hook{h},
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err = ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) > 0 {
|
|
t.Fatalf("bad: %#v", mod)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_destroyOrphan(t *testing.T) {
|
|
m := testModule(t, "apply-error")
|
|
p := testProvider("aws")
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.baz": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
|
|
if d.Destroy {
|
|
return nil, nil
|
|
}
|
|
|
|
result := s.MergeDiff(d)
|
|
result.ID = "foo"
|
|
return result, nil
|
|
}
|
|
p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) {
|
|
return &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"num": &ResourceAttrDiff{
|
|
New: "bar",
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if _, ok := mod.Resources["aws_instance.baz"]; ok {
|
|
t.Fatalf("bad: %#v", mod.Resources)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) {
|
|
m := testModule(t, "apply-destroy-provisioner")
|
|
p := testProvider("aws")
|
|
pr := testProvisioner()
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
|
|
called := false
|
|
pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error {
|
|
called = true
|
|
return nil
|
|
}
|
|
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"id": "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Provisioners: map[string]ResourceProvisionerFactory{
|
|
"shell": testProvisionerFuncFixed(pr),
|
|
},
|
|
State: s,
|
|
Destroy: true,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if called {
|
|
t.Fatal("provisioner should not be called")
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace("<no state>")
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_error(t *testing.T) {
|
|
errored := false
|
|
|
|
m := testModule(t, "apply-error")
|
|
p := testProvider("aws")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) {
|
|
if errored {
|
|
state := &InstanceState{
|
|
ID: "bar",
|
|
}
|
|
return state, fmt.Errorf("error")
|
|
}
|
|
errored = true
|
|
|
|
return &InstanceState{
|
|
ID: "foo",
|
|
Attributes: map[string]string{
|
|
"num": "2",
|
|
},
|
|
}, nil
|
|
}
|
|
p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) {
|
|
return &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"num": &ResourceAttrDiff{
|
|
New: "bar",
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should have error")
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyErrorStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_errorPartial(t *testing.T) {
|
|
errored := false
|
|
|
|
m := testModule(t, "apply-error")
|
|
p := testProvider("aws")
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
|
|
if errored {
|
|
return s, fmt.Errorf("error")
|
|
}
|
|
errored = true
|
|
|
|
return &InstanceState{
|
|
ID: "foo",
|
|
Attributes: map[string]string{
|
|
"num": "2",
|
|
},
|
|
}, nil
|
|
}
|
|
p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) {
|
|
return &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"num": &ResourceAttrDiff{
|
|
New: "bar",
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should have error")
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) != 2 {
|
|
t.Fatalf("bad: %#v", mod.Resources)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyErrorPartialStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_hook(t *testing.T) {
|
|
m := testModule(t, "apply-good")
|
|
h := new(MockHook)
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Hooks: []Hook{h},
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if _, err := ctx.Apply(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if !h.PreApplyCalled {
|
|
t.Fatal("should be called")
|
|
}
|
|
if !h.PostApplyCalled {
|
|
t.Fatal("should be called")
|
|
}
|
|
if !h.PostStateUpdateCalled {
|
|
t.Fatalf("should call post state update")
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_idAttr(t *testing.T) {
|
|
m := testModule(t, "apply-idattr")
|
|
p := testProvider("aws")
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
|
|
result := s.MergeDiff(d)
|
|
result.ID = "foo"
|
|
result.Attributes = map[string]string{
|
|
"id": "bar",
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) {
|
|
return &InstanceDiff{
|
|
Attributes: map[string]*ResourceAttrDiff{
|
|
"num": &ResourceAttrDiff{
|
|
New: "bar",
|
|
},
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
rs, ok := mod.Resources["aws_instance.foo"]
|
|
if !ok {
|
|
t.Fatal("not in state")
|
|
}
|
|
if rs.Primary.ID != "foo" {
|
|
t.Fatalf("bad: %#v", rs.Primary.ID)
|
|
}
|
|
if rs.Primary.Attributes["id"] != "foo" {
|
|
t.Fatalf("bad: %#v", rs.Primary.Attributes)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_output(t *testing.T) {
|
|
m := testModule(t, "apply-output")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyOutputStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_outputInvalid(t *testing.T) {
|
|
m := testModule(t, "apply-output-invalid")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
_, err := ctx.Plan()
|
|
if err == nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
if !strings.Contains(err.Error(), "is not a string") {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_outputList(t *testing.T) {
|
|
m := testModule(t, "apply-output-list")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyOutputListStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_outputMulti(t *testing.T) {
|
|
m := testModule(t, "apply-output-multi")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyOutputMultiStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_outputMultiIndex(t *testing.T) {
|
|
m := testModule(t, "apply-output-multi-index")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_taint(t *testing.T) {
|
|
m := testModule(t, "apply-taint")
|
|
p := testProvider("aws")
|
|
|
|
// destroyCount tests against regression of
|
|
// https://github.com/hashicorp/terraform/issues/1056
|
|
var destroyCount = int32(0)
|
|
var once sync.Once
|
|
simulateProviderDelay := func() {
|
|
time.Sleep(10 * time.Millisecond)
|
|
}
|
|
|
|
p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
|
|
once.Do(simulateProviderDelay)
|
|
if d.Destroy {
|
|
atomic.AddInt32(&destroyCount, 1)
|
|
}
|
|
return testApplyFn(info, s, d)
|
|
}
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "baz",
|
|
Attributes: map[string]string{
|
|
"num": "2",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyTaintStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
|
|
if destroyCount != 1 {
|
|
t.Fatalf("Expected 1 destroy, got %d", destroyCount)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_taintDep(t *testing.T) {
|
|
m := testModule(t, "apply-taint-dep")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "baz",
|
|
Attributes: map[string]string{
|
|
"num": "2",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "baz",
|
|
"num": "2",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
if p, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
} else {
|
|
t.Logf("plan: %s", p)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyTaintDepStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_taintDepRequiresNew(t *testing.T) {
|
|
m := testModule(t, "apply-taint-dep-requires-new")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
s := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": &ResourceState{
|
|
Type: "aws_instance",
|
|
Tainted: []*InstanceState{
|
|
&InstanceState{
|
|
ID: "baz",
|
|
Attributes: map[string]string{
|
|
"num": "2",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.bar": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"foo": "baz",
|
|
"num": "2",
|
|
"type": "aws_instance",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: s,
|
|
})
|
|
|
|
if p, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
} else {
|
|
t.Logf("plan: %s", p)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad:\n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_targeted(t *testing.T) {
|
|
m := testModule(t, "apply-targeted")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Targets: []string{"aws_instance.foo"},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) != 1 {
|
|
t.Fatalf("expected 1 resource, got: %#v", mod.Resources)
|
|
}
|
|
|
|
checkStateString(t, state, `
|
|
aws_instance.foo:
|
|
ID = foo
|
|
num = 2
|
|
type = aws_instance
|
|
`)
|
|
}
|
|
|
|
func TestContext2Apply_targetedCount(t *testing.T) {
|
|
m := testModule(t, "apply-targeted-count")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Targets: []string{"aws_instance.foo"},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
checkStateString(t, state, `
|
|
aws_instance.foo.0:
|
|
ID = foo
|
|
aws_instance.foo.1:
|
|
ID = foo
|
|
aws_instance.foo.2:
|
|
ID = foo
|
|
`)
|
|
}
|
|
|
|
func TestContext2Apply_targetedCountIndex(t *testing.T) {
|
|
m := testModule(t, "apply-targeted-count")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Targets: []string{"aws_instance.foo[1]"},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
checkStateString(t, state, `
|
|
aws_instance.foo.1:
|
|
ID = foo
|
|
`)
|
|
}
|
|
|
|
func TestContext2Apply_targetedDestroy(t *testing.T) {
|
|
m := testModule(t, "apply-targeted")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo": resourceState("aws_instance", "i-bcd345"),
|
|
"aws_instance.bar": resourceState("aws_instance", "i-abc123"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Targets: []string{"aws_instance.foo"},
|
|
Destroy: true,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) != 1 {
|
|
t.Fatalf("expected 1 resource, got: %#v", mod.Resources)
|
|
}
|
|
|
|
checkStateString(t, state, `
|
|
aws_instance.bar:
|
|
ID = i-abc123
|
|
`)
|
|
}
|
|
|
|
func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) {
|
|
m := testModule(t, "apply-targeted-count")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.foo.0": resourceState("aws_instance", "i-bcd345"),
|
|
"aws_instance.foo.1": resourceState("aws_instance", "i-bcd345"),
|
|
"aws_instance.foo.2": resourceState("aws_instance", "i-bcd345"),
|
|
"aws_instance.bar.0": resourceState("aws_instance", "i-abc123"),
|
|
"aws_instance.bar.1": resourceState("aws_instance", "i-abc123"),
|
|
"aws_instance.bar.2": resourceState("aws_instance", "i-abc123"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
Targets: []string{
|
|
"aws_instance.foo[2]",
|
|
"aws_instance.bar[1]",
|
|
},
|
|
Destroy: true,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
checkStateString(t, state, `
|
|
aws_instance.bar.0:
|
|
ID = i-abc123
|
|
aws_instance.bar.2:
|
|
ID = i-abc123
|
|
aws_instance.foo.0:
|
|
ID = i-bcd345
|
|
aws_instance.foo.1:
|
|
ID = i-bcd345
|
|
`)
|
|
}
|
|
|
|
func TestContext2Apply_targetedModule(t *testing.T) {
|
|
m := testModule(t, "apply-targeted-module")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Targets: []string{"module.child"},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.ModuleByPath([]string{"root", "child"})
|
|
if mod == nil {
|
|
t.Fatalf("no child module found in the state!\n\n%#v", state)
|
|
}
|
|
if len(mod.Resources) != 2 {
|
|
t.Fatalf("expected 2 resources, got: %#v", mod.Resources)
|
|
}
|
|
|
|
checkStateString(t, state, `
|
|
<no state>
|
|
module.child:
|
|
aws_instance.bar:
|
|
ID = foo
|
|
num = 2
|
|
type = aws_instance
|
|
aws_instance.foo:
|
|
ID = foo
|
|
num = 2
|
|
type = aws_instance
|
|
`)
|
|
}
|
|
|
|
func TestContext2Apply_targetedModuleResource(t *testing.T) {
|
|
m := testModule(t, "apply-targeted-module-resource")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Targets: []string{"module.child.aws_instance.foo"},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.ModuleByPath([]string{"root", "child"})
|
|
if len(mod.Resources) != 1 {
|
|
t.Fatalf("expected 1 resource, got: %#v", mod.Resources)
|
|
}
|
|
|
|
checkStateString(t, state, `
|
|
<no state>
|
|
module.child:
|
|
aws_instance.foo:
|
|
ID = foo
|
|
num = 2
|
|
type = aws_instance
|
|
`)
|
|
}
|
|
|
|
func TestContext2Apply_unknownAttribute(t *testing.T) {
|
|
m := testModule(t, "apply-unknown")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err == nil {
|
|
t.Fatal("should error")
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_vars(t *testing.T) {
|
|
m := testModule(t, "apply-vars")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
Variables: map[string]string{
|
|
"foo": "us-west-2",
|
|
"amis.us-east-1": "override",
|
|
},
|
|
})
|
|
|
|
w, e := ctx.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyVarsStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_varsEnv(t *testing.T) {
|
|
m := testModule(t, "apply-vars-env")
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
})
|
|
|
|
// Set the env var
|
|
old := tempEnv(t, "TF_VAR_ami", "baz")
|
|
defer os.Setenv("TF_VAR_ami", old)
|
|
|
|
w, e := ctx.Validate()
|
|
if len(w) > 0 {
|
|
t.Fatalf("bad: %#v", w)
|
|
}
|
|
if len(e) > 0 {
|
|
t.Fatalf("bad: %s", e)
|
|
}
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyVarsEnvStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s", actual)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_createBefore_depends(t *testing.T) {
|
|
m := testModule(t, "apply-depends-create-before")
|
|
h := new(HookRecordApplyOrder)
|
|
p := testProvider("aws")
|
|
p.ApplyFn = testApplyFn
|
|
p.DiffFn = testDiffFn
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"require_new": "ami-old",
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.lb": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "baz",
|
|
Attributes: map[string]string{
|
|
"instance": "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Hooks: []Hook{h},
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
h.Active = true
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
mod := state.RootModule()
|
|
if len(mod.Resources) < 2 {
|
|
t.Fatalf("bad: %#v", mod.Resources)
|
|
}
|
|
|
|
actual := strings.TrimSpace(state.String())
|
|
expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr)
|
|
if actual != expected {
|
|
t.Fatalf("bad: \n%s\n%s", actual, expected)
|
|
}
|
|
|
|
// Test that things were managed _in the right order_
|
|
order := h.States
|
|
diffs := h.Diffs
|
|
if order[0].ID != "" || diffs[0].Destroy {
|
|
t.Fatalf("should create new instance first: %#v", order)
|
|
}
|
|
|
|
if order[1].ID != "baz" {
|
|
t.Fatalf("update must happen after create: %#v", order)
|
|
}
|
|
|
|
if order[2].ID != "bar" || !diffs[2].Destroy {
|
|
t.Fatalf("destroy must happen after update: %#v", order)
|
|
}
|
|
}
|
|
|
|
func TestContext2Apply_singleDestroy(t *testing.T) {
|
|
m := testModule(t, "apply-depends-create-before")
|
|
h := new(HookRecordApplyOrder)
|
|
p := testProvider("aws")
|
|
|
|
invokeCount := 0
|
|
p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) {
|
|
invokeCount++
|
|
switch invokeCount {
|
|
case 1:
|
|
if d.Destroy {
|
|
t.Fatalf("should not destroy")
|
|
}
|
|
if s.ID != "" {
|
|
t.Fatalf("should not have ID")
|
|
}
|
|
case 2:
|
|
if d.Destroy {
|
|
t.Fatalf("should not destroy")
|
|
}
|
|
if s.ID != "baz" {
|
|
t.Fatalf("should have id")
|
|
}
|
|
case 3:
|
|
if !d.Destroy {
|
|
t.Fatalf("should destroy")
|
|
}
|
|
if s.ID == "" {
|
|
t.Fatalf("should have ID")
|
|
}
|
|
default:
|
|
t.Fatalf("bad invoke count %d", invokeCount)
|
|
}
|
|
return testApplyFn(info, s, d)
|
|
}
|
|
p.DiffFn = testDiffFn
|
|
state := &State{
|
|
Modules: []*ModuleState{
|
|
&ModuleState{
|
|
Path: rootModulePath,
|
|
Resources: map[string]*ResourceState{
|
|
"aws_instance.web": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "bar",
|
|
Attributes: map[string]string{
|
|
"require_new": "ami-old",
|
|
},
|
|
},
|
|
},
|
|
"aws_instance.lb": &ResourceState{
|
|
Type: "aws_instance",
|
|
Primary: &InstanceState{
|
|
ID: "baz",
|
|
Attributes: map[string]string{
|
|
"instance": "bar",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
ctx := testContext2(t, &ContextOpts{
|
|
Module: m,
|
|
Hooks: []Hook{h},
|
|
Providers: map[string]ResourceProviderFactory{
|
|
"aws": testProviderFuncFixed(p),
|
|
},
|
|
State: state,
|
|
})
|
|
|
|
if _, err := ctx.Plan(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
h.Active = true
|
|
state, err := ctx.Apply()
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
if invokeCount != 3 {
|
|
t.Fatalf("bad: %d", invokeCount)
|
|
}
|
|
}
|
|
|
|
func testContext2(t *testing.T, opts *ContextOpts) *Context {
|
|
return NewContext(opts)
|
|
}
|
|
|
|
func testApplyFn(
|
|
info *InstanceInfo,
|
|
s *InstanceState,
|
|
d *InstanceDiff) (*InstanceState, error) {
|
|
if d.Destroy {
|
|
return nil, nil
|
|
}
|
|
|
|
id := "foo"
|
|
if idAttr, ok := d.Attributes["id"]; ok && !idAttr.NewComputed {
|
|
id = idAttr.New
|
|
}
|
|
|
|
result := &InstanceState{
|
|
ID: id,
|
|
Attributes: make(map[string]string),
|
|
}
|
|
|
|
// Copy all the prior attributes
|
|
for k, v := range s.Attributes {
|
|
result.Attributes[k] = v
|
|
}
|
|
|
|
if d != nil {
|
|
result = result.MergeDiff(d)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func testDiffFn(
|
|
info *InstanceInfo,
|
|
s *InstanceState,
|
|
c *ResourceConfig) (*InstanceDiff, error) {
|
|
var diff InstanceDiff
|
|
diff.Attributes = make(map[string]*ResourceAttrDiff)
|
|
|
|
for k, v := range c.Raw {
|
|
if _, ok := v.(string); !ok {
|
|
continue
|
|
}
|
|
|
|
if k == "nil" {
|
|
return nil, nil
|
|
}
|
|
|
|
// This key is used for other purposes
|
|
if k == "compute_value" {
|
|
continue
|
|
}
|
|
|
|
if k == "compute" {
|
|
attrDiff := &ResourceAttrDiff{
|
|
Old: "",
|
|
New: "",
|
|
NewComputed: true,
|
|
}
|
|
|
|
if cv, ok := c.Config["compute_value"]; ok {
|
|
if cv.(string) == "1" {
|
|
attrDiff.NewComputed = false
|
|
attrDiff.New = fmt.Sprintf("computed_%s", v.(string))
|
|
}
|
|
}
|
|
|
|
diff.Attributes[v.(string)] = attrDiff
|
|
continue
|
|
}
|
|
|
|
// If this key is not computed, then look it up in the
|
|
// cleaned config.
|
|
found := false
|
|
for _, ck := range c.ComputedKeys {
|
|
if ck == k {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
v = c.Config[k]
|
|
}
|
|
|
|
attrDiff := &ResourceAttrDiff{
|
|
Old: "",
|
|
New: v.(string),
|
|
}
|
|
|
|
if k == "require_new" {
|
|
attrDiff.RequiresNew = true
|
|
}
|
|
diff.Attributes[k] = attrDiff
|
|
}
|
|
|
|
for _, k := range c.ComputedKeys {
|
|
diff.Attributes[k] = &ResourceAttrDiff{
|
|
Old: "",
|
|
NewComputed: true,
|
|
}
|
|
}
|
|
|
|
for k, v := range diff.Attributes {
|
|
if v.NewComputed {
|
|
continue
|
|
}
|
|
|
|
old, ok := s.Attributes[k]
|
|
if !ok {
|
|
continue
|
|
}
|
|
if old == v.New {
|
|
delete(diff.Attributes, k)
|
|
}
|
|
}
|
|
|
|
if !diff.Empty() {
|
|
diff.Attributes["type"] = &ResourceAttrDiff{
|
|
Old: "",
|
|
New: info.Type,
|
|
}
|
|
}
|
|
|
|
return &diff, nil
|
|
}
|
|
|
|
func testProvider(prefix string) *MockResourceProvider {
|
|
p := new(MockResourceProvider)
|
|
p.RefreshFn = func(info *InstanceInfo, s *InstanceState) (*InstanceState, error) {
|
|
return s, nil
|
|
}
|
|
p.ResourcesReturn = []ResourceType{
|
|
ResourceType{
|
|
Name: fmt.Sprintf("%s_instance", prefix),
|
|
},
|
|
}
|
|
|
|
return p
|
|
}
|
|
|
|
func testProvisioner() *MockResourceProvisioner {
|
|
p := new(MockResourceProvisioner)
|
|
return p
|
|
}
|
|
|
|
func checkStateString(t *testing.T, state *State, expected string) {
|
|
actual := strings.TrimSpace(state.String())
|
|
expected = strings.TrimSpace(expected)
|
|
|
|
if actual != expected {
|
|
t.Fatalf("state does not match! actual:\n%s\n\nexpected:\n%s", actual, expected)
|
|
}
|
|
}
|
|
|
|
func resourceState(resourceType, resourceID string) *ResourceState {
|
|
return &ResourceState{
|
|
Type: resourceType,
|
|
Primary: &InstanceState{
|
|
ID: resourceID,
|
|
},
|
|
}
|
|
}
|
|
|
|
const testContextGraph = `
|
|
root: root
|
|
aws_instance.bar
|
|
aws_instance.bar -> provider.aws
|
|
aws_instance.foo
|
|
aws_instance.foo -> provider.aws
|
|
provider.aws
|
|
root
|
|
root -> aws_instance.bar
|
|
root -> aws_instance.foo
|
|
`
|
|
|
|
const testContextRefreshModuleStr = `
|
|
aws_instance.web: (1 tainted)
|
|
ID = <not created>
|
|
Tainted ID 1 = bar
|
|
|
|
module.child:
|
|
aws_instance.web:
|
|
ID = new
|
|
`
|
|
|
|
const testContextRefreshOutputStr = `
|
|
aws_instance.web:
|
|
ID = foo
|
|
foo = bar
|
|
|
|
Outputs:
|
|
|
|
foo = bar
|
|
`
|
|
|
|
const testContextRefreshOutputPartialStr = `
|
|
<no state>
|
|
`
|
|
|
|
const testContextRefreshTaintedStr = `
|
|
aws_instance.web: (1 tainted)
|
|
ID = <not created>
|
|
Tainted ID 1 = foo
|
|
`
|