github.com/jzbruno/terraform@v0.10.3-0.20180104230435-18975d727047/backend/local/backend_test.go (about)

     1  package local
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"reflect"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/hashicorp/terraform/backend"
    13  	"github.com/hashicorp/terraform/state"
    14  	"github.com/hashicorp/terraform/terraform"
    15  )
    16  
    17  func TestLocal_impl(t *testing.T) {
    18  	var _ backend.Enhanced = new(Local)
    19  	var _ backend.Local = new(Local)
    20  	var _ backend.CLI = new(Local)
    21  }
    22  
    23  func TestLocal_backend(t *testing.T) {
    24  	defer testTmpDir(t)()
    25  	b := &Local{}
    26  	backend.TestBackend(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 := terraform.ReadState(f)
    38  	f.Close()
    39  	if err != nil {
    40  		t.Fatalf("err: %s", err)
    41  	}
    42  
    43  	actual := strings.TrimSpace(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 := &Local{}
    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  	defer testTmpDir(t)()
    93  	dflt := backend.DefaultStateName
    94  	expectedStates := []string{dflt}
    95  
    96  	b := &Local{}
    97  	states, err := b.States()
    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.State(expectedA); err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	states, err = b.States()
   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.State(expectedB); err != nil {
   123  		t.Fatal(err)
   124  	}
   125  
   126  	states, err = b.States()
   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.DeleteState(expectedA); err != nil {
   137  		t.Fatal(err)
   138  	}
   139  
   140  	states, err = b.States()
   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.DeleteState(expectedB); err != nil {
   151  		t.Fatal(err)
   152  	}
   153  
   154  	states, err = b.States()
   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.DeleteState(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) State(name string) (state.State, error) {
   185  	if b.stateErr {
   186  		return nil, errTestDelegateState
   187  	}
   188  	s := &state.LocalState{
   189  		Path:    "terraform.tfstate",
   190  		PathOut: "terraform.tfstate",
   191  	}
   192  	return s, nil
   193  }
   194  
   195  func (b *testDelegateBackend) States() ([]string, error) {
   196  	if b.statesErr {
   197  		return nil, errTestDelegateStates
   198  	}
   199  	return []string{"default"}, nil
   200  }
   201  
   202  func (b *testDelegateBackend) DeleteState(name string) error {
   203  	if b.deleteErr {
   204  		return errTestDelegateDeleteState
   205  	}
   206  	return nil
   207  }
   208  
   209  // verify that the MultiState methods are dispatched to the correct Backend.
   210  func TestLocal_multiStateBackend(t *testing.T) {
   211  	// assign a separate backend where we can read the state
   212  	b := &Local{
   213  		Backend: &testDelegateBackend{
   214  			stateErr:  true,
   215  			statesErr: true,
   216  			deleteErr: true,
   217  		},
   218  	}
   219  
   220  	if _, err := b.State("test"); err != errTestDelegateState {
   221  		t.Fatal("expected errTestDelegateState, got:", err)
   222  	}
   223  
   224  	if _, err := b.States(); err != errTestDelegateStates {
   225  		t.Fatal("expected errTestDelegateStates, got:", err)
   226  	}
   227  
   228  	if err := b.DeleteState("test"); err != errTestDelegateDeleteState {
   229  		t.Fatal("expected errTestDelegateDeleteState, got:", err)
   230  	}
   231  }
   232  
   233  // change into a tmp dir and return a deferable func to change back and cleanup
   234  func testTmpDir(t *testing.T) func() {
   235  	tmp, err := ioutil.TempDir("", "tf")
   236  	if err != nil {
   237  		t.Fatal(err)
   238  	}
   239  
   240  	old, err := os.Getwd()
   241  	if err != nil {
   242  		t.Fatal(err)
   243  	}
   244  
   245  	if err := os.Chdir(tmp); err != nil {
   246  		t.Fatal(err)
   247  	}
   248  
   249  	return func() {
   250  		// ignore errors and try to clean up
   251  		os.Chdir(old)
   252  		os.RemoveAll(tmp)
   253  	}
   254  }