mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-25 01:00:16 -05:00
Move command/ to internal/command/
This is part of a general effort to move all of Terraform's non-library package surface under internal in order to reinforce that these are for internal use within Terraform only. If you were previously importing packages under this prefix into an external codebase, you could pin to an earlier release tag as an interim solution until you've make a plan to achieve the same functionality some other way.
This commit is contained in:
570
internal/command/taint_test.go
Normal file
570
internal/command/taint_test.go
Normal file
@@ -0,0 +1,570 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/mitchellh/cli"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/addrs"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
)
|
||||
|
||||
func TestTaint(t *testing.T) {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
"test_instance.foo",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
testStateOutput(t, statePath, testTaintStr)
|
||||
}
|
||||
|
||||
func TestTaint_lockedState(t *testing.T) {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
statePath := testStateFile(t, state)
|
||||
|
||||
unlock, err := testLockState(testDataDir, statePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer unlock()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
"test_instance.foo",
|
||||
}
|
||||
if code := c.Run(args); code == 0 {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
|
||||
output := ui.ErrorWriter.String()
|
||||
if !strings.Contains(output, "lock") {
|
||||
t.Fatal("command output does not look like a lock error:", output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaint_backup(t *testing.T) {
|
||||
// Get a temp cwd
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
// Write the temp state
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"test_instance.foo",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
testStateOutput(t, DefaultStateFilename+".backup", testTaintDefaultStr)
|
||||
testStateOutput(t, DefaultStateFilename, testTaintStr)
|
||||
}
|
||||
|
||||
func TestTaint_backupDisable(t *testing.T) {
|
||||
// Get a temp cwd
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
// Write the temp state
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-backup", "-",
|
||||
"test_instance.foo",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
if _, err := os.Stat(DefaultStateFilename + ".backup"); err == nil {
|
||||
t.Fatal("backup path should not exist")
|
||||
}
|
||||
|
||||
testStateOutput(t, DefaultStateFilename, testTaintStr)
|
||||
}
|
||||
|
||||
func TestTaint_badState(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state", "i-should-not-exist-ever",
|
||||
"foo",
|
||||
}
|
||||
if code := c.Run(args); code != 1 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaint_defaultState(t *testing.T) {
|
||||
// Get a temp cwd
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
// Write the temp state
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"test_instance.foo",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
testStateOutput(t, DefaultStateFilename, testTaintStr)
|
||||
}
|
||||
|
||||
func TestTaint_defaultWorkspaceState(t *testing.T) {
|
||||
// Get a temp cwd
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
testWorkspace := "development"
|
||||
path := testStateFileWorkspaceDefault(t, testWorkspace, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
meta := Meta{Ui: ui, View: view}
|
||||
meta.SetWorkspace(testWorkspace)
|
||||
c := &TaintCommand{
|
||||
Meta: meta,
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"test_instance.foo",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
testStateOutput(t, path, testTaintStr)
|
||||
}
|
||||
|
||||
func TestTaint_missing(t *testing.T) {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
"test_instance.bar",
|
||||
}
|
||||
if code := c.Run(args); code == 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.OutputWriter.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaint_missingAllow(t *testing.T) {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-allow-missing",
|
||||
"-state", statePath,
|
||||
"test_instance.bar",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
// Check for the warning
|
||||
actual := strings.TrimSpace(ui.ErrorWriter.String())
|
||||
expected := strings.TrimSpace(`
|
||||
Warning: No such resource instance
|
||||
|
||||
Resource instance test_instance.bar was not found, but this is not an error
|
||||
because -allow-missing was set.
|
||||
|
||||
`)
|
||||
if diff := cmp.Diff(expected, actual); diff != "" {
|
||||
t.Fatalf("wrong output\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTaint_stateOut(t *testing.T) {
|
||||
// Get a temp cwd
|
||||
tmp, cwd := testCwd(t)
|
||||
defer testFixCwd(t, tmp, cwd)
|
||||
|
||||
// Write the temp state
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state-out", "foo",
|
||||
"test_instance.foo",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
testStateOutput(t, DefaultStateFilename, testTaintDefaultStr)
|
||||
testStateOutput(t, "foo", testTaintStr)
|
||||
}
|
||||
|
||||
func TestTaint_module(t *testing.T) {
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "blah",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"blah"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{
|
||||
"-state", statePath,
|
||||
"module.child.test_instance.blah",
|
||||
}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
|
||||
}
|
||||
|
||||
testStateOutput(t, statePath, testTaintModuleStr)
|
||||
}
|
||||
|
||||
func TestTaint_checkRequiredVersion(t *testing.T) {
|
||||
// Create a temporary working directory that is empty
|
||||
td := tempDir(t)
|
||||
testCopyDir(t, testFixturePath("taint-check-required-version"), td)
|
||||
defer os.RemoveAll(td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
// Write the temp state
|
||||
state := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetResourceInstanceCurrent(
|
||||
addrs.Resource{
|
||||
Mode: addrs.ManagedResourceMode,
|
||||
Type: "test_instance",
|
||||
Name: "foo",
|
||||
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
|
||||
&states.ResourceInstanceObjectSrc{
|
||||
AttrsJSON: []byte(`{"id":"bar"}`),
|
||||
Status: states.ObjectReady,
|
||||
},
|
||||
addrs.AbsProviderConfig{
|
||||
Provider: addrs.NewDefaultProvider("test"),
|
||||
Module: addrs.RootModule,
|
||||
},
|
||||
)
|
||||
})
|
||||
path := testStateFile(t, state)
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
args := []string{"test_instance.foo"}
|
||||
if code := c.Run(args); code != 1 {
|
||||
t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
|
||||
}
|
||||
|
||||
// State is unchanged
|
||||
testStateOutput(t, path, testTaintDefaultStr)
|
||||
|
||||
// Required version diags are correct
|
||||
errStr := ui.ErrorWriter.String()
|
||||
if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
|
||||
t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
|
||||
}
|
||||
if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
|
||||
t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
|
||||
}
|
||||
}
|
||||
|
||||
const testTaintStr = `
|
||||
test_instance.foo: (tainted)
|
||||
ID = bar
|
||||
provider = provider["registry.terraform.io/hashicorp/test"]
|
||||
`
|
||||
|
||||
const testTaintDefaultStr = `
|
||||
test_instance.foo:
|
||||
ID = bar
|
||||
provider = provider["registry.terraform.io/hashicorp/test"]
|
||||
`
|
||||
|
||||
const testTaintModuleStr = `
|
||||
test_instance.foo:
|
||||
ID = bar
|
||||
provider = provider["registry.terraform.io/hashicorp/test"]
|
||||
|
||||
module.child:
|
||||
test_instance.blah: (tainted)
|
||||
ID = blah
|
||||
provider = provider["registry.terraform.io/hashicorp/test"]
|
||||
`
|
||||
Reference in New Issue
Block a user