github.com/hugorut/terraform@v1.1.3/src/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/hugorut/terraform/src/backend" 13 "github.com/hugorut/terraform/src/states/statefile" 14 "github.com/hugorut/terraform/src/states/statemgr" 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 := statefile.Read(f) 39 f.Close() 40 if err != nil { 41 t.Fatalf("err: %s", err) 42 } 43 44 actual := state.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.Workspaces() 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.StateMgr(expectedA); err != nil { 109 t.Fatal(err) 110 } 111 112 states, err = b.Workspaces() 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.StateMgr(expectedB); err != nil { 124 t.Fatal(err) 125 } 126 127 states, err = b.Workspaces() 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.DeleteWorkspace(expectedA); err != nil { 138 t.Fatal(err) 139 } 140 141 states, err = b.Workspaces() 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.DeleteWorkspace(expectedB); err != nil { 152 t.Fatal(err) 153 } 154 155 states, err = b.Workspaces() 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.DeleteWorkspace(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) StateMgr(name string) (statemgr.Full, error) { 186 if b.stateErr { 187 return nil, errTestDelegateState 188 } 189 s := statemgr.NewFilesystem("terraform.tfstate") 190 return s, nil 191 } 192 193 func (b *testDelegateBackend) Workspaces() ([]string, error) { 194 if b.statesErr { 195 return nil, errTestDelegateStates 196 } 197 return []string{"default"}, nil 198 } 199 200 func (b *testDelegateBackend) DeleteWorkspace(name string) error { 201 if b.deleteErr { 202 return errTestDelegateDeleteState 203 } 204 return nil 205 } 206 207 // verify that the MultiState methods are dispatched to the correct Backend. 208 func TestLocal_multiStateBackend(t *testing.T) { 209 // assign a separate backend where we can read the state 210 b := NewWithBackend(&testDelegateBackend{ 211 stateErr: true, 212 statesErr: true, 213 deleteErr: true, 214 }) 215 216 if _, err := b.StateMgr("test"); err != errTestDelegateState { 217 t.Fatal("expected errTestDelegateState, got:", err) 218 } 219 220 if _, err := b.Workspaces(); err != errTestDelegateStates { 221 t.Fatal("expected errTestDelegateStates, got:", err) 222 } 223 224 if err := b.DeleteWorkspace("test"); err != errTestDelegateDeleteState { 225 t.Fatal("expected errTestDelegateDeleteState, got:", err) 226 } 227 } 228 229 // change into a tmp dir and return a deferable func to change back and cleanup 230 func testTmpDir(t *testing.T) func() { 231 tmp, err := ioutil.TempDir("", "tf") 232 if err != nil { 233 t.Fatal(err) 234 } 235 236 old, err := os.Getwd() 237 if err != nil { 238 t.Fatal(err) 239 } 240 241 if err := os.Chdir(tmp); err != nil { 242 t.Fatal(err) 243 } 244 245 return func() { 246 // ignore errors and try to clean up 247 os.Chdir(old) 248 os.RemoveAll(tmp) 249 } 250 }