helper/resource: ImportState test can verify states
This commit is contained in:
parent
27452f0043
commit
6a675b4a15
|
@ -149,6 +149,11 @@ type TestStep struct {
|
||||||
// used to verify that the resulting value of ImportState has the
|
// used to verify that the resulting value of ImportState has the
|
||||||
// proper resources, IDs, and attributes.
|
// proper resources, IDs, and attributes.
|
||||||
ImportStateCheck ImportStateCheckFunc
|
ImportStateCheck ImportStateCheckFunc
|
||||||
|
|
||||||
|
// ImportStateVerify, if true, will also check that the state values
|
||||||
|
// that are finally put into the state after import match for all the
|
||||||
|
// IDs returned by the Import.
|
||||||
|
ImportStateVerify bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test performs an acceptance test on a resource.
|
// Test performs an acceptance test on a resource.
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package resource
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -36,11 +39,11 @@ func testStepImportState(
|
||||||
return state, err
|
return state, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ImportOpts needs a flag to read a config module so it
|
|
||||||
// can load our provider config without env vars.
|
|
||||||
|
|
||||||
// Do the import!
|
// Do the import!
|
||||||
newState, err := ctx.Import(&terraform.ImportOpts{
|
newState, err := ctx.Import(&terraform.ImportOpts{
|
||||||
|
// Set the module so that any provider config is loaded
|
||||||
|
Module: mod,
|
||||||
|
|
||||||
Targets: []*terraform.ImportTarget{
|
Targets: []*terraform.ImportTarget{
|
||||||
&terraform.ImportTarget{
|
&terraform.ImportTarget{
|
||||||
Addr: step.ResourceName,
|
Addr: step.ResourceName,
|
||||||
|
@ -66,6 +69,47 @@ func testStepImportState(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify that all the states match
|
||||||
|
if step.ImportStateVerify {
|
||||||
|
new := newState.RootModule().Resources
|
||||||
|
old := state.RootModule().Resources
|
||||||
|
for _, r := range new {
|
||||||
|
// Find the existing resource
|
||||||
|
var oldR *terraform.ResourceState
|
||||||
|
for _, r2 := range old {
|
||||||
|
if r2.Primary != nil && r2.Primary.ID == r.Primary.ID {
|
||||||
|
oldR = r2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if oldR == nil {
|
||||||
|
return state, fmt.Errorf(
|
||||||
|
"Failed state verification, resource with ID %s not found",
|
||||||
|
r.Primary.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare their attributes
|
||||||
|
actual := r.Primary.Attributes
|
||||||
|
expected := oldR.Primary.Attributes
|
||||||
|
if !reflect.DeepEqual(actual, expected) {
|
||||||
|
// Determine only the different attributes
|
||||||
|
for k, v := range expected {
|
||||||
|
if av, ok := actual[k]; ok && v == av {
|
||||||
|
delete(expected, k)
|
||||||
|
delete(actual, k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spewConf := spew.NewDefaultConfig()
|
||||||
|
spewConf.SortKeys = true
|
||||||
|
return state, fmt.Errorf(
|
||||||
|
"Attributes not equivalent. Difference is shown below. Top is actual, bottom is expected."+
|
||||||
|
"\n\n%s\n\n%s",
|
||||||
|
spewConf.Sdump(actual), spewConf.Sdump(expected))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Return the old state (non-imported) so we don't change anything.
|
// Return the old state (non-imported) so we don't change anything.
|
||||||
return state, nil
|
return state, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -177,3 +177,134 @@ func TestTest_importStateDetectId(t *testing.T) {
|
||||||
t.Fatal("didn't call check")
|
t.Fatal("didn't call check")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTest_importStateVerify(t *testing.T) {
|
||||||
|
mp := testProvider()
|
||||||
|
mp.DiffReturn = nil
|
||||||
|
mp.ApplyFn = func(
|
||||||
|
info *terraform.InstanceInfo,
|
||||||
|
state *terraform.InstanceState,
|
||||||
|
diff *terraform.InstanceDiff) (*terraform.InstanceState, error) {
|
||||||
|
if !diff.Destroy {
|
||||||
|
return &terraform.InstanceState{
|
||||||
|
ID: "foo",
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.RefreshFn = func(
|
||||||
|
i *terraform.InstanceInfo,
|
||||||
|
s *terraform.InstanceState) (*terraform.InstanceState, error) {
|
||||||
|
if len(s.Attributes) == 0 {
|
||||||
|
s.Attributes = map[string]string{
|
||||||
|
"id": s.ID,
|
||||||
|
"foo": "bar",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.ImportStateFn = func(
|
||||||
|
info *terraform.InstanceInfo, id string) ([]*terraform.InstanceState, error) {
|
||||||
|
if id != "foo" {
|
||||||
|
return nil, fmt.Errorf("bad import ID: %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []*terraform.InstanceState{
|
||||||
|
&terraform.InstanceState{
|
||||||
|
ID: "foo",
|
||||||
|
Ephemeral: terraform.EphemeralState{Type: "test_instance"},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mt := new(mockT)
|
||||||
|
Test(mt, TestCase{
|
||||||
|
Providers: map[string]terraform.ResourceProvider{
|
||||||
|
"test": mp,
|
||||||
|
},
|
||||||
|
|
||||||
|
Steps: []TestStep{
|
||||||
|
TestStep{
|
||||||
|
Config: testConfigStr,
|
||||||
|
},
|
||||||
|
TestStep{
|
||||||
|
ResourceName: "test_instance.foo",
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if mt.failed() {
|
||||||
|
t.Fatalf("test failed: %s", mt.failMessage())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTest_importStateVerifyFail(t *testing.T) {
|
||||||
|
mp := testProvider()
|
||||||
|
mp.DiffReturn = nil
|
||||||
|
mp.ApplyFn = func(
|
||||||
|
info *terraform.InstanceInfo,
|
||||||
|
state *terraform.InstanceState,
|
||||||
|
diff *terraform.InstanceDiff) (*terraform.InstanceState, error) {
|
||||||
|
if !diff.Destroy {
|
||||||
|
return &terraform.InstanceState{
|
||||||
|
ID: "foo",
|
||||||
|
Attributes: map[string]string{
|
||||||
|
"foo": "bar",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.RefreshFn = func(
|
||||||
|
i *terraform.InstanceInfo,
|
||||||
|
s *terraform.InstanceState) (*terraform.InstanceState, error) {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.ImportStateFn = func(
|
||||||
|
info *terraform.InstanceInfo, id string) ([]*terraform.InstanceState, error) {
|
||||||
|
if id != "foo" {
|
||||||
|
return nil, fmt.Errorf("bad import ID: %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []*terraform.InstanceState{
|
||||||
|
&terraform.InstanceState{
|
||||||
|
ID: "foo",
|
||||||
|
Ephemeral: terraform.EphemeralState{Type: "test_instance"},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
mt := new(mockT)
|
||||||
|
Test(mt, TestCase{
|
||||||
|
Providers: map[string]terraform.ResourceProvider{
|
||||||
|
"test": mp,
|
||||||
|
},
|
||||||
|
|
||||||
|
Steps: []TestStep{
|
||||||
|
TestStep{
|
||||||
|
Config: testConfigStr,
|
||||||
|
},
|
||||||
|
TestStep{
|
||||||
|
ResourceName: "test_instance.foo",
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if !mt.failed() {
|
||||||
|
t.Fatalf("test should fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue