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