mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
update local.Local to match the latest Backend
Update the methods, remove the handling of "current", and make tests pass.
This commit is contained in:
parent
96194fbc0d
commit
65527f35a4
@ -123,6 +123,9 @@ type Operation struct {
|
|||||||
// If LockState is true, the Operation must Lock any
|
// If LockState is true, the Operation must Lock any
|
||||||
// state.Lockers for its duration, and Unlock when complete.
|
// state.Lockers for its duration, and Unlock when complete.
|
||||||
LockState bool
|
LockState bool
|
||||||
|
|
||||||
|
// Environment is the named state that should be loaded from the Backend.
|
||||||
|
Environment string
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunningOperation is the result of starting an operation.
|
// RunningOperation is the result of starting an operation.
|
||||||
|
@ -53,8 +53,10 @@ type Local struct {
|
|||||||
StateOutPath string
|
StateOutPath string
|
||||||
StateBackupPath string
|
StateBackupPath string
|
||||||
|
|
||||||
// we only want to create a single instance of the local state
|
// We only want to create a single instance of a local state, so store them
|
||||||
state state.State
|
// here as they're loaded.
|
||||||
|
states map[string]state.State
|
||||||
|
|
||||||
// Terraform context. Many of these will be overridden or merged by
|
// Terraform context. Many of these will be overridden or merged by
|
||||||
// Operation. See Operation for more details.
|
// Operation. See Operation for more details.
|
||||||
ContextOpts *terraform.ContextOpts
|
ContextOpts *terraform.ContextOpts
|
||||||
@ -78,10 +80,6 @@ type Local struct {
|
|||||||
schema *schema.Backend
|
schema *schema.Backend
|
||||||
opLock sync.Mutex
|
opLock sync.Mutex
|
||||||
once sync.Once
|
once sync.Once
|
||||||
|
|
||||||
// workingDir is where the State* paths should be relative to.
|
|
||||||
// This is currently only used for tests.
|
|
||||||
workingDir string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Local) Input(
|
func (b *Local) Input(
|
||||||
@ -118,54 +116,35 @@ func (b *Local) Configure(c *terraform.ResourceConfig) error {
|
|||||||
return f(c)
|
return f(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Local) States() ([]string, string, error) {
|
func (b *Local) States() ([]string, error) {
|
||||||
// If we have a backend handling state, defer to that.
|
// If we have a backend handling state, defer to that.
|
||||||
if b.Backend != nil {
|
if b.Backend != nil {
|
||||||
if b, ok := b.Backend.(backend.MultiState); ok {
|
return b.Backend.States()
|
||||||
return b.States()
|
|
||||||
} else {
|
|
||||||
return nil, "", ErrEnvNotSupported
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// the listing always start with "default"
|
// the listing always start with "default"
|
||||||
envs := []string{backend.DefaultStateName}
|
envs := []string{backend.DefaultStateName}
|
||||||
|
|
||||||
current, err := b.currentStateName()
|
entries, err := ioutil.ReadDir(DefaultEnvDir)
|
||||||
if err != nil {
|
|
||||||
return nil, "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
entries, err := ioutil.ReadDir(filepath.Join(b.workingDir, DefaultEnvDir))
|
|
||||||
// no error if there's no envs configured
|
// no error if there's no envs configured
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return envs, backend.DefaultStateName, nil
|
return envs, nil
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
currentExists := false
|
|
||||||
var listed []string
|
var listed []string
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if entry.IsDir() {
|
if entry.IsDir() {
|
||||||
name := filepath.Base(entry.Name())
|
listed = append(listed, filepath.Base(entry.Name()))
|
||||||
if name == current {
|
|
||||||
currentExists = true
|
|
||||||
}
|
}
|
||||||
listed = append(listed, name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// current was out of sync for some reason, so return defualt
|
|
||||||
if !currentExists {
|
|
||||||
current = backend.DefaultStateName
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(listed)
|
sort.Strings(listed)
|
||||||
envs = append(envs, listed...)
|
envs = append(envs, listed...)
|
||||||
|
|
||||||
return envs, current, nil
|
return envs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteState removes a named state.
|
// DeleteState removes a named state.
|
||||||
@ -173,11 +152,7 @@ func (b *Local) States() ([]string, string, error) {
|
|||||||
func (b *Local) DeleteState(name string) error {
|
func (b *Local) DeleteState(name string) error {
|
||||||
// If we have a backend handling state, defer to that.
|
// If we have a backend handling state, defer to that.
|
||||||
if b.Backend != nil {
|
if b.Backend != nil {
|
||||||
if b, ok := b.Backend.(backend.MultiState); ok {
|
return b.Backend.DeleteState(name)
|
||||||
return b.DeleteState(name)
|
|
||||||
} else {
|
|
||||||
return ErrEnvNotSupported
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == "" {
|
if name == "" {
|
||||||
@ -188,91 +163,25 @@ func (b *Local) DeleteState(name string) error {
|
|||||||
return errors.New("cannot delete default state")
|
return errors.New("cannot delete default state")
|
||||||
}
|
}
|
||||||
|
|
||||||
_, current, err := b.States()
|
delete(b.states, name)
|
||||||
if err != nil {
|
return os.RemoveAll(filepath.Join(DefaultEnvDir, name))
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we're deleting the current state, we change back to the default
|
|
||||||
if name == current {
|
|
||||||
if err := b.ChangeState(backend.DefaultStateName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.RemoveAll(filepath.Join(b.workingDir, DefaultEnvDir, name))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change to the named state, creating it if it doesn't exist.
|
func (b *Local) State(name string) (state.State, error) {
|
||||||
func (b *Local) ChangeState(name string) error {
|
|
||||||
// If we have a backend handling state, defer to that.
|
// If we have a backend handling state, defer to that.
|
||||||
if b.Backend != nil {
|
if b.Backend != nil {
|
||||||
if b, ok := b.Backend.(backend.MultiState); ok {
|
return b.Backend.State(name)
|
||||||
return b.ChangeState(name)
|
|
||||||
} else {
|
|
||||||
return ErrEnvNotSupported
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
name = strings.TrimSpace(name)
|
if s, ok := b.states[name]; ok {
|
||||||
if name == "" {
|
return s, nil
|
||||||
return errors.New("state name cannot be empty")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
envs, current, err := b.States()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == current {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
exists := false
|
|
||||||
for _, env := range envs {
|
|
||||||
if env == name {
|
|
||||||
exists = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
if err := b.createState(name); err != nil {
|
if err := b.createState(name); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.MkdirAll(filepath.Join(b.workingDir, DefaultDataDir), 0755)
|
statePath, stateOutPath, backupPath, err := b.StatePaths(name)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ioutil.WriteFile(
|
|
||||||
filepath.Join(b.workingDir, DefaultDataDir, DefaultEnvFile),
|
|
||||||
[]byte(name),
|
|
||||||
0644,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the current state so it's reloaded on the next call to State
|
|
||||||
b.state = nil
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Local) State() (state.State, error) {
|
|
||||||
// If we have a backend handling state, defer to that.
|
|
||||||
if b.Backend != nil {
|
|
||||||
return b.Backend.State()
|
|
||||||
}
|
|
||||||
|
|
||||||
if b.state != nil {
|
|
||||||
return b.state, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
statePath, stateOutPath, backupPath, err := b.StatePaths()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -291,7 +200,10 @@ func (b *Local) State() (state.State, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b.state = s
|
if b.states == nil {
|
||||||
|
b.states = map[string]state.State{}
|
||||||
|
}
|
||||||
|
b.states[name] = s
|
||||||
return s, nil
|
return s, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,20 +297,24 @@ func (b *Local) schemaConfigure(ctx context.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// StatePaths returns the StatePath, StateOutPath, and StateBackupPath as
|
// StatePaths returns the StatePath, StateOutPath, and StateBackupPath as
|
||||||
// configured by the current environment. If backups are disabled,
|
// configured from the CLI.
|
||||||
// StateBackupPath will be an empty string.
|
func (b *Local) StatePaths(name string) (string, string, string, error) {
|
||||||
func (b *Local) StatePaths() (string, string, string, error) {
|
|
||||||
statePath := b.StatePath
|
statePath := b.StatePath
|
||||||
stateOutPath := b.StateOutPath
|
stateOutPath := b.StateOutPath
|
||||||
backupPath := b.StateBackupPath
|
backupPath := b.StateBackupPath
|
||||||
|
|
||||||
|
if name == "" {
|
||||||
|
name = backend.DefaultStateName
|
||||||
|
}
|
||||||
|
|
||||||
|
if name == backend.DefaultStateName {
|
||||||
if statePath == "" {
|
if statePath == "" {
|
||||||
path, err := b.statePath()
|
statePath = name
|
||||||
if err != nil {
|
|
||||||
return "", "", "", err
|
|
||||||
}
|
}
|
||||||
statePath = path
|
} else {
|
||||||
|
statePath = filepath.Join(DefaultEnvDir, name, DefaultStateFilename)
|
||||||
}
|
}
|
||||||
|
|
||||||
if stateOutPath == "" {
|
if stateOutPath == "" {
|
||||||
stateOutPath = statePath
|
stateOutPath = statePath
|
||||||
}
|
}
|
||||||
@ -413,33 +329,21 @@ func (b *Local) StatePaths() (string, string, string, error) {
|
|||||||
return statePath, stateOutPath, backupPath, nil
|
return statePath, stateOutPath, backupPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Local) statePath() (string, error) {
|
// this only ensures that the named directory exists
|
||||||
_, current, err := b.States()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
path := DefaultStateFilename
|
|
||||||
|
|
||||||
if current != backend.DefaultStateName && current != "" {
|
|
||||||
path = filepath.Join(b.workingDir, DefaultEnvDir, current, DefaultStateFilename)
|
|
||||||
}
|
|
||||||
return path, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Local) createState(name string) error {
|
func (b *Local) createState(name string) error {
|
||||||
stateNames, _, err := b.States()
|
if name == backend.DefaultStateName {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, n := range stateNames {
|
|
||||||
if name == n {
|
|
||||||
// state exists, nothing to do
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stateDir := filepath.Join(DefaultEnvDir, name)
|
||||||
|
s, err := os.Stat(stateDir)
|
||||||
|
if err == nil && s.IsDir() {
|
||||||
|
// no need to check for os.IsNotExist, since that is covered by os.MkdirAll
|
||||||
|
// which will catch the other possible errors as well.
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.MkdirAll(filepath.Join(b.workingDir, DefaultEnvDir, name), 0755)
|
err = os.MkdirAll(stateDir, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -451,7 +355,7 @@ func (b *Local) createState(name string) error {
|
|||||||
// configuration files.
|
// configuration files.
|
||||||
// If there are no configured environments, currentStateName returns "default"
|
// If there are no configured environments, currentStateName returns "default"
|
||||||
func (b *Local) currentStateName() (string, error) {
|
func (b *Local) currentStateName() (string, error) {
|
||||||
contents, err := ioutil.ReadFile(filepath.Join(b.workingDir, DefaultDataDir, DefaultEnvFile))
|
contents, err := ioutil.ReadFile(filepath.Join(DefaultDataDir, DefaultEnvFile))
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return backend.DefaultStateName, nil
|
return backend.DefaultStateName, nil
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ func (b *Local) Context(op *backend.Operation) (*terraform.Context, state.State,
|
|||||||
|
|
||||||
func (b *Local) context(op *backend.Operation) (*terraform.Context, state.State, error) {
|
func (b *Local) context(op *backend.Operation) (*terraform.Context, state.State, error) {
|
||||||
// Get the state.
|
// Get the state.
|
||||||
s, err := b.State()
|
s, err := b.State(op.Environment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err)
|
return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err)
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
package local
|
package local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/backend"
|
"github.com/hashicorp/terraform/backend"
|
||||||
|
"github.com/hashicorp/terraform/state"
|
||||||
"github.com/hashicorp/terraform/terraform"
|
"github.com/hashicorp/terraform/terraform"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,7 +17,6 @@ func TestLocal_impl(t *testing.T) {
|
|||||||
var _ backend.Enhanced = new(Local)
|
var _ backend.Enhanced = new(Local)
|
||||||
var _ backend.Local = new(Local)
|
var _ backend.Local = new(Local)
|
||||||
var _ backend.CLI = new(Local)
|
var _ backend.CLI = new(Local)
|
||||||
var _ backend.MultiState = new(Local)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkState(t *testing.T, path, expected string) {
|
func checkState(t *testing.T, path, expected string) {
|
||||||
@ -46,31 +45,24 @@ func TestLocal_addAndRemoveStates(t *testing.T) {
|
|||||||
expectedStates := []string{dflt}
|
expectedStates := []string{dflt}
|
||||||
|
|
||||||
b := &Local{}
|
b := &Local{}
|
||||||
states, current, err := b.States()
|
states, err := b.States()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if current != dflt {
|
|
||||||
t.Fatalf("expected %q, got %q", dflt, current)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(states, expectedStates) {
|
if !reflect.DeepEqual(states, expectedStates) {
|
||||||
t.Fatalf("expected []string{%q}, got %q", dflt, states)
|
t.Fatalf("expected []string{%q}, got %q", dflt, states)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedA := "test_A"
|
expectedA := "test_A"
|
||||||
if err := b.ChangeState(expectedA); err != nil {
|
if _, err := b.State(expectedA); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
states, current, err = b.States()
|
states, err = b.States()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if current != expectedA {
|
|
||||||
t.Fatalf("expected %q, got %q", expectedA, current)
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedStates = append(expectedStates, expectedA)
|
expectedStates = append(expectedStates, expectedA)
|
||||||
if !reflect.DeepEqual(states, expectedStates) {
|
if !reflect.DeepEqual(states, expectedStates) {
|
||||||
@ -78,17 +70,14 @@ func TestLocal_addAndRemoveStates(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expectedB := "test_B"
|
expectedB := "test_B"
|
||||||
if err := b.ChangeState(expectedB); err != nil {
|
if _, err := b.State(expectedB); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
states, current, err = b.States()
|
states, err = b.States()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if current != expectedB {
|
|
||||||
t.Fatalf("expected %q, got %q", expectedB, current)
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedStates = append(expectedStates, expectedB)
|
expectedStates = append(expectedStates, expectedB)
|
||||||
if !reflect.DeepEqual(states, expectedStates) {
|
if !reflect.DeepEqual(states, expectedStates) {
|
||||||
@ -99,13 +88,10 @@ func TestLocal_addAndRemoveStates(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
states, current, err = b.States()
|
states, err = b.States()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if current != expectedB {
|
|
||||||
t.Fatalf("expected %q, got %q", dflt, current)
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedStates = []string{dflt, expectedB}
|
expectedStates = []string{dflt, expectedB}
|
||||||
if !reflect.DeepEqual(states, expectedStates) {
|
if !reflect.DeepEqual(states, expectedStates) {
|
||||||
@ -116,13 +102,10 @@ func TestLocal_addAndRemoveStates(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
states, current, err = b.States()
|
states, err = b.States()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if current != dflt {
|
|
||||||
t.Fatalf("expected %q, got %q", dflt, current)
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedStates = []string{dflt}
|
expectedStates = []string{dflt}
|
||||||
if !reflect.DeepEqual(states, expectedStates) {
|
if !reflect.DeepEqual(states, expectedStates) {
|
||||||
@ -134,97 +117,45 @@ func TestLocal_addAndRemoveStates(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify the behavior with a backend that doesn't support multiple states
|
// a local backend which return sentinel errors for NamedState methods to
|
||||||
func TestLocal_noMultiStateBackend(t *testing.T) {
|
// verify it's being called.
|
||||||
type noMultiState struct {
|
type testDelegateBackend struct {
|
||||||
backend.Backend
|
*Local
|
||||||
}
|
}
|
||||||
|
|
||||||
b := &Local{
|
var errTestDelegateState = errors.New("State called")
|
||||||
Backend: &noMultiState{},
|
var errTestDelegateStates = errors.New("States called")
|
||||||
}
|
var errTestDelegateDeleteState = errors.New("Delete called")
|
||||||
|
|
||||||
_, _, err := b.States()
|
func (b *testDelegateBackend) State(name string) (state.State, error) {
|
||||||
if err != ErrEnvNotSupported {
|
return nil, errTestDelegateState
|
||||||
t.Fatal("backend does not support environments.", err)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
err = b.ChangeState("test")
|
func (b *testDelegateBackend) States() ([]string, error) {
|
||||||
if err != ErrEnvNotSupported {
|
return nil, errTestDelegateStates
|
||||||
t.Fatal("backend does not support environments.", err)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
err = b.ChangeState("test")
|
func (b *testDelegateBackend) DeleteState(name string) error {
|
||||||
if err != ErrEnvNotSupported {
|
return errTestDelegateDeleteState
|
||||||
t.Fatal("backend does not support environments.", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify that the MultiState methods are dispatched to the correct Backend.
|
// verify that the MultiState methods are dispatched to the correct Backend.
|
||||||
func TestLocal_multiStateBackend(t *testing.T) {
|
func TestLocal_multiStateBackend(t *testing.T) {
|
||||||
defer testTmpDir(t)()
|
// assign a separate backend where we can read the state
|
||||||
|
|
||||||
dflt := backend.DefaultStateName
|
|
||||||
expectedStates := []string{dflt}
|
|
||||||
|
|
||||||
// make a second tmp dir for the sub-Backend.
|
|
||||||
// we verify the corret backend was called by checking the paths.
|
|
||||||
tmp, err := ioutil.TempDir("", "tf")
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
defer os.RemoveAll(tmp)
|
|
||||||
|
|
||||||
fmt.Println("second tmp:", tmp)
|
|
||||||
|
|
||||||
b := &Local{
|
b := &Local{
|
||||||
Backend: &Local{
|
Backend: &testDelegateBackend{},
|
||||||
workingDir: tmp,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
testA := "test_A"
|
if _, err := b.State("test"); err != errTestDelegateState {
|
||||||
if err := b.ChangeState(testA); err != nil {
|
t.Fatal("expected errTestDelegateState, got:", err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
states, current, err := b.States()
|
if _, err := b.States(); err != errTestDelegateStates {
|
||||||
if err != nil {
|
t.Fatal("expected errTestDelegateStates, got:", err)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if current != testA {
|
|
||||||
t.Fatalf("expected %q, got %q", testA, current)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedStates = append(expectedStates, testA)
|
if err := b.DeleteState("test"); err != errTestDelegateDeleteState {
|
||||||
if !reflect.DeepEqual(states, expectedStates) {
|
t.Fatal("expected errTestDelegateDeleteState, got:", err)
|
||||||
t.Fatalf("expected %q, got %q", expectedStates, states)
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify that no environment paths were created for the top-level Backend
|
|
||||||
if _, err := os.Stat(DefaultDataDir); !os.IsNotExist(err) {
|
|
||||||
t.Fatal("remote state operations should not have written local files")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := os.Stat(filepath.Join(DefaultEnvDir, testA)); !os.IsNotExist(err) {
|
|
||||||
t.Fatal("remote state operations should not have written local files")
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the new state
|
|
||||||
if err := b.DeleteState(testA); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
states, current, err = b.States()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if current != dflt {
|
|
||||||
t.Fatalf("expected %q, got %q", dflt, current)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(states, expectedStates[:1]) {
|
|
||||||
t.Fatalf("expected %q, got %q", expectedStates, states)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user