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