package command import ( "os" "path/filepath" "strings" "testing" "github.com/mitchellh/cli" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/helper/copy" "github.com/hashicorp/terraform/states" "github.com/hashicorp/terraform/terraform" ) func TestStateRm(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","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "bar", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), &states.ResourceInstanceObjectSrc{ AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) p := testProvider() ui := new(cli.MockUi) c := &StateRmCommand{ StateMeta{ Meta: Meta{ testingOverrides: metaOverridesForProvider(p), Ui: ui, }, }, } 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()) } // Test it is correct testStateOutput(t, statePath, testStateRmOutput) // Test we have backups backups := testStateBackups(t, filepath.Dir(statePath)) if len(backups) != 1 { t.Fatalf("bad: %#v", backups) } testStateOutput(t, backups[0], testStateRmOutputOriginal) } func TestStateRmNoArgs(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","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "bar", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), &states.ResourceInstanceObjectSrc{ AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) p := testProvider() ui := new(cli.MockUi) c := &StateRmCommand{ StateMeta{ Meta: Meta{ testingOverrides: metaOverridesForProvider(p), Ui: ui, }, }, } args := []string{ "-state", statePath, } if code := c.Run(args); code != 1 { t.Errorf("wrong exit status %d; want %d", code, 1) } if msg := ui.ErrorWriter.String(); !strings.Contains(msg, "At least one resource address") { t.Errorf("not the error we were looking for:\n%s", msg) } } func TestStateRmNonExist(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","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "bar", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), &states.ResourceInstanceObjectSrc{ AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) p := testProvider() ui := new(cli.MockUi) c := &StateRmCommand{ StateMeta{ Meta: Meta{ testingOverrides: metaOverridesForProvider(p), Ui: ui, }, }, } args := []string{ "-state", statePath, "test_instance.baz", // doesn't exist in the state constructed above } if code := c.Run(args); code != 1 { t.Errorf("wrong exit status %d; want %d", code, 1) } if msg := ui.ErrorWriter.String(); !strings.Contains(msg, "No such resource instance in state") { t.Errorf("not the error we were looking for:\n%s", msg) } } func TestStateRm_backupExplicit(t *testing.T) { td := tempDir(t) defer os.RemoveAll(td) backupPath := filepath.Join(td, "backup") 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","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), ) s.SetResourceInstanceCurrent( addrs.Resource{ Mode: addrs.ManagedResourceMode, Type: "test_instance", Name: "bar", }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), &states.ResourceInstanceObjectSrc{ AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`), Status: states.ObjectReady, }, addrs.ProviderConfig{Type: "test"}.Absolute(addrs.RootModuleInstance), ) }) statePath := testStateFile(t, state) p := testProvider() ui := new(cli.MockUi) c := &StateRmCommand{ StateMeta{ Meta: Meta{ testingOverrides: metaOverridesForProvider(p), Ui: ui, }, }, } args := []string{ "-backup", backupPath, "-state", statePath, "test_instance.foo", } if code := c.Run(args); code != 0 { t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) } // Test it is correct testStateOutput(t, statePath, testStateRmOutput) // Test backup testStateOutput(t, backupPath, testStateRmOutputOriginal) } func TestStateRm_noState(t *testing.T) { tmp, cwd := testCwd(t) defer testFixCwd(t, tmp, cwd) p := testProvider() ui := new(cli.MockUi) c := &StateRmCommand{ StateMeta{ Meta: Meta{ testingOverrides: metaOverridesForProvider(p), Ui: ui, }, }, } args := []string{} if code := c.Run(args); code != 1 { t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) } } func TestStateRm_needsInit(t *testing.T) { td := tempDir(t) copy.CopyDir(testFixturePath("backend-change"), td) defer os.RemoveAll(td) defer testChdir(t, td)() p := testProvider() ui := new(cli.MockUi) c := &StateRmCommand{ StateMeta{ Meta: Meta{ testingOverrides: metaOverridesForProvider(p), Ui: ui, }, }, } args := []string{"foo"} if code := c.Run(args); code == 0 { t.Fatal("expected error\noutput:", ui.OutputWriter) } if !strings.Contains(ui.ErrorWriter.String(), "Initialization") { t.Fatal("expected initialization error, got:\n", ui.ErrorWriter) } } func TestStateRm_backendState(t *testing.T) { td := tempDir(t) copy.CopyDir(testFixturePath("backend-unchanged"), td) defer os.RemoveAll(td) defer testChdir(t, td)() state := &terraform.State{ Modules: []*terraform.ModuleState{ &terraform.ModuleState{ Path: []string{"root"}, Resources: map[string]*terraform.ResourceState{ "test_instance.foo": &terraform.ResourceState{ Type: "test_instance", Primary: &terraform.InstanceState{ ID: "bar", Attributes: map[string]string{ "foo": "value", "bar": "value", }, }, }, "test_instance.bar": &terraform.ResourceState{ Type: "test_instance", Primary: &terraform.InstanceState{ ID: "foo", Attributes: map[string]string{ "foo": "value", "bar": "value", }, }, }, }, }, }, } // the local backend state file is "foo" statePath := "local-state.tfstate" backupPath := "local-state.backup" f, err := os.Create(statePath) if err != nil { t.Fatal(err) } defer f.Close() if err := terraform.WriteState(state, f); err != nil { t.Fatal(err) } p := testProvider() ui := new(cli.MockUi) c := &StateRmCommand{ StateMeta{ Meta: Meta{ testingOverrides: metaOverridesForProvider(p), Ui: ui, }, }, } args := []string{ "-backup", backupPath, "test_instance.foo", } if code := c.Run(args); code != 0 { t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) } // Test it is correct testStateOutput(t, statePath, testStateRmOutput) // Test backup testStateOutput(t, backupPath, testStateRmOutputOriginal) } const testStateRmOutputOriginal = ` test_instance.bar: ID = foo provider = provider.test bar = value foo = value test_instance.foo: ID = bar provider = provider.test bar = value foo = value ` const testStateRmOutput = ` test_instance.bar: ID = foo provider = provider.test bar = value foo = value `