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