github.com/tompao/terraform@v0.6.10-0.20180215233341-e41b29d0961b/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 }