github.com/kevinklinger/open_terraform@v1.3.6/noninternal/backend/local/backend_test.go (about)

     1  package local
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"path/filepath"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/kevinklinger/open_terraform/noninternal/backend"
    12  	"github.com/kevinklinger/open_terraform/noninternal/states/statefile"
    13  	"github.com/kevinklinger/open_terraform/noninternal/states/statemgr"
    14  )
    15  
    16  func TestLocal_impl(t *testing.T) {
    17  	var _ backend.Enhanced = New()
    18  	var _ backend.Local = New()
    19  	var _ backend.CLI = New()
    20  }
    21  
    22  func TestLocal_backend(t *testing.T) {
    23  	testTmpDir(t)
    24  	b := New()
    25  	backend.TestBackendStates(t, b)
    26  	backend.TestBackendStateLocks(t, b, b)
    27  }
    28  
    29  func checkState(t *testing.T, path, expected string) {
    30  	t.Helper()
    31  	// Read the state
    32  	f, err := os.Open(path)
    33  	if err != nil {
    34  		t.Fatalf("err: %s", err)
    35  	}
    36  
    37  	state, err := statefile.Read(f)
    38  	f.Close()
    39  	if err != nil {
    40  		t.Fatalf("err: %s", err)
    41  	}
    42  
    43  	actual := state.State.String()
    44  	expected = strings.TrimSpace(expected)
    45  	if actual != expected {
    46  		t.Fatalf("state does not match! actual:\n%s\n\nexpected:\n%s", actual, expected)
    47  	}
    48  }
    49  
    50  func TestLocal_StatePaths(t *testing.T) {
    51  	b := New()
    52  
    53  	// Test the defaults
    54  	path, out, back := b.StatePaths("")
    55  
    56  	if path != DefaultStateFilename {
    57  		t.Fatalf("expected %q, got %q", DefaultStateFilename, path)
    58  	}
    59  
    60  	if out != DefaultStateFilename {
    61  		t.Fatalf("expected %q, got %q", DefaultStateFilename, out)
    62  	}
    63  
    64  	dfltBackup := DefaultStateFilename + DefaultBackupExtension
    65  	if back != dfltBackup {
    66  		t.Fatalf("expected %q, got %q", dfltBackup, back)
    67  	}
    68  
    69  	// check with env
    70  	testEnv := "test_env"
    71  	path, out, back = b.StatePaths(testEnv)
    72  
    73  	expectedPath := filepath.Join(DefaultWorkspaceDir, testEnv, DefaultStateFilename)
    74  	expectedOut := expectedPath
    75  	expectedBackup := expectedPath + DefaultBackupExtension
    76  
    77  	if path != expectedPath {
    78  		t.Fatalf("expected %q, got %q", expectedPath, path)
    79  	}
    80  
    81  	if out != expectedOut {
    82  		t.Fatalf("expected %q, got %q", expectedOut, out)
    83  	}
    84  
    85  	if back != expectedBackup {
    86  		t.Fatalf("expected %q, got %q", expectedBackup, back)
    87  	}
    88  
    89  }
    90  
    91  func TestLocal_addAndRemoveStates(t *testing.T) {
    92  	testTmpDir(t)
    93  	dflt := backend.DefaultStateName
    94  	expectedStates := []string{dflt}
    95  
    96  	b := New()
    97  	states, err := b.Workspaces()
    98  	if err != nil {
    99  		t.Fatal(err)
   100  	}
   101  
   102  	if !reflect.DeepEqual(states, expectedStates) {
   103  		t.Fatalf("expected []string{%q}, got %q", dflt, states)
   104  	}
   105  
   106  	expectedA := "test_A"
   107  	if _, err := b.StateMgr(expectedA); err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	states, err = b.Workspaces()
   112  	if err != nil {
   113  		t.Fatal(err)
   114  	}
   115  
   116  	expectedStates = append(expectedStates, expectedA)
   117  	if !reflect.DeepEqual(states, expectedStates) {
   118  		t.Fatalf("expected %q, got %q", expectedStates, states)
   119  	}
   120  
   121  	expectedB := "test_B"
   122  	if _, err := b.StateMgr(expectedB); err != nil {
   123  		t.Fatal(err)
   124  	}
   125  
   126  	states, err = b.Workspaces()
   127  	if err != nil {
   128  		t.Fatal(err)
   129  	}
   130  
   131  	expectedStates = append(expectedStates, expectedB)
   132  	if !reflect.DeepEqual(states, expectedStates) {
   133  		t.Fatalf("expected %q, got %q", expectedStates, states)
   134  	}
   135  
   136  	if err := b.DeleteWorkspace(expectedA); err != nil {
   137  		t.Fatal(err)
   138  	}
   139  
   140  	states, err = b.Workspaces()
   141  	if err != nil {
   142  		t.Fatal(err)
   143  	}
   144  
   145  	expectedStates = []string{dflt, expectedB}
   146  	if !reflect.DeepEqual(states, expectedStates) {
   147  		t.Fatalf("expected %q, got %q", expectedStates, states)
   148  	}
   149  
   150  	if err := b.DeleteWorkspace(expectedB); err != nil {
   151  		t.Fatal(err)
   152  	}
   153  
   154  	states, err = b.Workspaces()
   155  	if err != nil {
   156  		t.Fatal(err)
   157  	}
   158  
   159  	expectedStates = []string{dflt}
   160  	if !reflect.DeepEqual(states, expectedStates) {
   161  		t.Fatalf("expected %q, got %q", expectedStates, states)
   162  	}
   163  
   164  	if err := b.DeleteWorkspace(dflt); err == nil {
   165  		t.Fatal("expected error deleting default state")
   166  	}
   167  }
   168  
   169  // a local backend which returns sentinel errors for NamedState methods to
   170  // verify it's being called.
   171  type testDelegateBackend struct {
   172  	*Local
   173  
   174  	// return a sentinel error on these calls
   175  	stateErr  bool
   176  	statesErr bool
   177  	deleteErr bool
   178  }
   179  
   180  var errTestDelegateState = errors.New("state called")
   181  var errTestDelegateStates = errors.New("states called")
   182  var errTestDelegateDeleteState = errors.New("delete called")
   183  
   184  func (b *testDelegateBackend) StateMgr(name string) (statemgr.Full, error) {
   185  	if b.stateErr {
   186  		return nil, errTestDelegateState
   187  	}
   188  	s := statemgr.NewFilesystem("terraform.tfstate")
   189  	return s, nil
   190  }
   191  
   192  func (b *testDelegateBackend) Workspaces() ([]string, error) {
   193  	if b.statesErr {
   194  		return nil, errTestDelegateStates
   195  	}
   196  	return []string{"default"}, nil
   197  }
   198  
   199  func (b *testDelegateBackend) DeleteWorkspace(name string) error {
   200  	if b.deleteErr {
   201  		return errTestDelegateDeleteState
   202  	}
   203  	return nil
   204  }
   205  
   206  // verify that the MultiState methods are dispatched to the correct Backend.
   207  func TestLocal_multiStateBackend(t *testing.T) {
   208  	// assign a separate backend where we can read the state
   209  	b := NewWithBackend(&testDelegateBackend{
   210  		stateErr:  true,
   211  		statesErr: true,
   212  		deleteErr: true,
   213  	})
   214  
   215  	if _, err := b.StateMgr("test"); err != errTestDelegateState {
   216  		t.Fatal("expected errTestDelegateState, got:", err)
   217  	}
   218  
   219  	if _, err := b.Workspaces(); err != errTestDelegateStates {
   220  		t.Fatal("expected errTestDelegateStates, got:", err)
   221  	}
   222  
   223  	if err := b.DeleteWorkspace("test"); err != errTestDelegateDeleteState {
   224  		t.Fatal("expected errTestDelegateDeleteState, got:", err)
   225  	}
   226  }
   227  
   228  // testTmpDir changes into a tmp dir and change back automatically when the test
   229  // and all its subtests complete.
   230  func testTmpDir(t *testing.T) {
   231  	tmp := t.TempDir()
   232  
   233  	old, err := os.Getwd()
   234  	if err != nil {
   235  		t.Fatal(err)
   236  	}
   237  
   238  	if err := os.Chdir(tmp); err != nil {
   239  		t.Fatal(err)
   240  	}
   241  
   242  	t.Cleanup(func() {
   243  		// ignore errors and try to clean up
   244  		os.Chdir(old)
   245  	})
   246  }