Merge pull request #18125 from hashicorp/f-testing-taint
helper/resource: Add ability to pre-taint resources
This commit is contained in:
commit
67182d06d7
|
@ -266,6 +266,15 @@ type TestStep struct {
|
|||
// below.
|
||||
PreConfig func()
|
||||
|
||||
// Taint is a list of resource addresses to taint prior to the execution of
|
||||
// the step. Be sure to only include this at a step where the referenced
|
||||
// address will be present in state, as it will fail the test if the resource
|
||||
// is missing.
|
||||
//
|
||||
// This option is ignored on ImportState tests, and currently only works for
|
||||
// resources in the root module path.
|
||||
Taint []string
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Test modes. One of the following groups of settings must be
|
||||
// set to determine what the test step will do. Ideally we would've
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package resource
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
@ -21,6 +22,14 @@ func testStep(
|
|||
opts terraform.ContextOpts,
|
||||
state *terraform.State,
|
||||
step TestStep) (*terraform.State, error) {
|
||||
// Pre-taint any resources that have been defined in Taint, as long as this
|
||||
// is not a destroy step.
|
||||
if !step.Destroy {
|
||||
if err := testStepTaint(state, step); err != nil {
|
||||
return state, err
|
||||
}
|
||||
}
|
||||
|
||||
mod, err := testModule(opts, step)
|
||||
if err != nil {
|
||||
return state, err
|
||||
|
@ -154,3 +163,19 @@ func testStep(
|
|||
// Made it here? Good job test step!
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func testStepTaint(state *terraform.State, step TestStep) error {
|
||||
for _, p := range step.Taint {
|
||||
m := state.RootModule()
|
||||
if m == nil {
|
||||
return errors.New("no state")
|
||||
}
|
||||
rs, ok := m.Resources[p]
|
||||
if !ok {
|
||||
return fmt.Errorf("resource %q not found in state", p)
|
||||
}
|
||||
log.Printf("[WARN] Test: Explicitly tainting resource %q", p)
|
||||
rs.Taint()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -911,6 +911,85 @@ func mockSweeperFunc(s string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func TestTest_Taint(t *testing.T) {
|
||||
mp := testProvider()
|
||||
mp.DiffFn = func(
|
||||
_ *terraform.InstanceInfo,
|
||||
state *terraform.InstanceState,
|
||||
_ *terraform.ResourceConfig,
|
||||
) (*terraform.InstanceDiff, error) {
|
||||
return &terraform.InstanceDiff{
|
||||
DestroyTainted: state.Tainted,
|
||||
}, nil
|
||||
}
|
||||
|
||||
mp.ApplyFn = func(
|
||||
info *terraform.InstanceInfo,
|
||||
state *terraform.InstanceState,
|
||||
diff *terraform.InstanceDiff,
|
||||
) (*terraform.InstanceState, error) {
|
||||
var id string
|
||||
switch {
|
||||
case diff.Destroy && !diff.DestroyTainted:
|
||||
return nil, nil
|
||||
case diff.DestroyTainted:
|
||||
id = "tainted"
|
||||
default:
|
||||
id = "not_tainted"
|
||||
}
|
||||
|
||||
return &terraform.InstanceState{
|
||||
ID: id,
|
||||
}, nil
|
||||
}
|
||||
|
||||
mp.RefreshFn = func(
|
||||
_ *terraform.InstanceInfo,
|
||||
state *terraform.InstanceState,
|
||||
) (*terraform.InstanceState, error) {
|
||||
return state, nil
|
||||
}
|
||||
|
||||
mt := new(mockT)
|
||||
Test(mt, TestCase{
|
||||
Providers: map[string]terraform.ResourceProvider{
|
||||
"test": mp,
|
||||
},
|
||||
Steps: []TestStep{
|
||||
TestStep{
|
||||
Config: testConfigStr,
|
||||
Check: func(s *terraform.State) error {
|
||||
rs := s.RootModule().Resources["test_instance.foo"]
|
||||
if rs.Primary.ID != "not_tainted" {
|
||||
return fmt.Errorf("expected not_tainted, got %s", rs.Primary.ID)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
TestStep{
|
||||
Taint: []string{"test_instance.foo"},
|
||||
Config: testConfigStr,
|
||||
Check: func(s *terraform.State) error {
|
||||
rs := s.RootModule().Resources["test_instance.foo"]
|
||||
if rs.Primary.ID != "tainted" {
|
||||
return fmt.Errorf("expected tainted, got %s", rs.Primary.ID)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
TestStep{
|
||||
Taint: []string{"test_instance.fooo"},
|
||||
Config: testConfigStr,
|
||||
ExpectError: regexp.MustCompile("resource \"test_instance.fooo\" not found in state"),
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if mt.failed() {
|
||||
t.Fatalf("test failure: %s", mt.failMessage())
|
||||
}
|
||||
}
|
||||
|
||||
const testConfigStr = `
|
||||
resource "test_instance" "foo" {}
|
||||
`
|
||||
|
|
Loading…
Reference in New Issue