github.com/ticketmaster/terraform@v0.10.0-beta2.0.20170711045249-a12daf5aba4f/command/workspace_command_test.go (about) 1 package command 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path/filepath" 7 "strings" 8 "testing" 9 10 "github.com/hashicorp/terraform/backend" 11 "github.com/hashicorp/terraform/backend/local" 12 "github.com/hashicorp/terraform/state" 13 "github.com/hashicorp/terraform/terraform" 14 "github.com/mitchellh/cli" 15 ) 16 17 func TestWorkspace_createAndChange(t *testing.T) { 18 // Create a temporary working directory that is empty 19 td := tempDir(t) 20 os.MkdirAll(td, 0755) 21 defer os.RemoveAll(td) 22 defer testChdir(t, td)() 23 24 newCmd := &WorkspaceNewCommand{} 25 26 current := newCmd.Workspace() 27 if current != backend.DefaultStateName { 28 t.Fatal("current workspace should be 'default'") 29 } 30 31 args := []string{"test"} 32 ui := new(cli.MockUi) 33 newCmd.Meta = Meta{Ui: ui} 34 if code := newCmd.Run(args); code != 0 { 35 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 36 } 37 38 current = newCmd.Workspace() 39 if current != "test" { 40 t.Fatalf("current workspace should be 'test', got %q", current) 41 } 42 43 selCmd := &WorkspaceSelectCommand{} 44 args = []string{backend.DefaultStateName} 45 ui = new(cli.MockUi) 46 selCmd.Meta = Meta{Ui: ui} 47 if code := selCmd.Run(args); code != 0 { 48 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 49 } 50 51 current = newCmd.Workspace() 52 if current != backend.DefaultStateName { 53 t.Fatal("current workspace should be 'default'") 54 } 55 56 } 57 58 // Create some workspaces and test the list output. 59 // This also ensures we switch to the correct env after each call 60 func TestWorkspace_createAndList(t *testing.T) { 61 // Create a temporary working directory that is empty 62 td := tempDir(t) 63 os.MkdirAll(td, 0755) 64 defer os.RemoveAll(td) 65 defer testChdir(t, td)() 66 67 // make sure a vars file doesn't interfere 68 err := ioutil.WriteFile( 69 DefaultVarsFilename, 70 []byte(`foo = "bar"`), 71 0644, 72 ) 73 if err != nil { 74 t.Fatal(err) 75 } 76 77 envs := []string{"test_a", "test_b", "test_c"} 78 79 // create multiple workspaces 80 for _, env := range envs { 81 ui := new(cli.MockUi) 82 newCmd := &WorkspaceNewCommand{ 83 Meta: Meta{Ui: ui}, 84 } 85 if code := newCmd.Run([]string{env}); code != 0 { 86 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 87 } 88 } 89 90 listCmd := &WorkspaceListCommand{} 91 ui := new(cli.MockUi) 92 listCmd.Meta = Meta{Ui: ui} 93 94 if code := listCmd.Run(nil); code != 0 { 95 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 96 } 97 98 actual := strings.TrimSpace(ui.OutputWriter.String()) 99 expected := "default\n test_a\n test_b\n* test_c" 100 101 if actual != expected { 102 t.Fatalf("\nexpected: %q\nactual: %q", expected, actual) 103 } 104 } 105 106 // Create some workspaces and test the show output. 107 func TestWorkspace_createAndShow(t *testing.T) { 108 // Create a temporary working directory that is empty 109 td := tempDir(t) 110 os.MkdirAll(td, 0755) 111 defer os.RemoveAll(td) 112 defer testChdir(t, td)() 113 114 // make sure a vars file doesn't interfere 115 err := ioutil.WriteFile( 116 DefaultVarsFilename, 117 []byte(`foo = "bar"`), 118 0644, 119 ) 120 if err != nil { 121 t.Fatal(err) 122 } 123 124 // make sure current workspace show outputs "default" 125 showCmd := &WorkspaceShowCommand{} 126 ui := new(cli.MockUi) 127 showCmd.Meta = Meta{Ui: ui} 128 129 if code := showCmd.Run(nil); code != 0 { 130 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 131 } 132 133 actual := strings.TrimSpace(ui.OutputWriter.String()) 134 expected := "default" 135 136 if actual != expected { 137 t.Fatalf("\nexpected: %q\nactual: %q", expected, actual) 138 } 139 140 newCmd := &WorkspaceNewCommand{} 141 142 env := []string{"test_a"} 143 144 // create test_a workspace 145 ui = new(cli.MockUi) 146 newCmd.Meta = Meta{Ui: ui} 147 if code := newCmd.Run(env); code != 0 { 148 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 149 } 150 151 selCmd := &WorkspaceSelectCommand{} 152 ui = new(cli.MockUi) 153 selCmd.Meta = Meta{Ui: ui} 154 if code := selCmd.Run(env); code != 0 { 155 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 156 } 157 158 showCmd = &WorkspaceShowCommand{} 159 ui = new(cli.MockUi) 160 showCmd.Meta = Meta{Ui: ui} 161 162 if code := showCmd.Run(nil); code != 0 { 163 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 164 } 165 166 actual = strings.TrimSpace(ui.OutputWriter.String()) 167 expected = "test_a" 168 169 if actual != expected { 170 t.Fatalf("\nexpected: %q\nactual: %q", expected, actual) 171 } 172 } 173 174 // Don't allow names that aren't URL safe 175 func TestWorkspace_createInvalid(t *testing.T) { 176 // Create a temporary working directory that is empty 177 td := tempDir(t) 178 os.MkdirAll(td, 0755) 179 defer os.RemoveAll(td) 180 defer testChdir(t, td)() 181 182 envs := []string{"test_a*", "test_b/foo", "../../../test_c", "好_d"} 183 184 // create multiple workspaces 185 for _, env := range envs { 186 ui := new(cli.MockUi) 187 newCmd := &WorkspaceNewCommand{ 188 Meta: Meta{Ui: ui}, 189 } 190 if code := newCmd.Run([]string{env}); code == 0 { 191 t.Fatalf("expected failure: \n%s", ui.OutputWriter) 192 } 193 } 194 195 // list workspaces to make sure none were created 196 listCmd := &WorkspaceListCommand{} 197 ui := new(cli.MockUi) 198 listCmd.Meta = Meta{Ui: ui} 199 200 if code := listCmd.Run(nil); code != 0 { 201 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 202 } 203 204 actual := strings.TrimSpace(ui.OutputWriter.String()) 205 expected := "* default" 206 207 if actual != expected { 208 t.Fatalf("\nexpected: %q\nactual: %q", expected, actual) 209 } 210 } 211 212 func TestWorkspace_createWithState(t *testing.T) { 213 td := tempDir(t) 214 os.MkdirAll(td, 0755) 215 defer os.RemoveAll(td) 216 defer testChdir(t, td)() 217 218 // create a non-empty state 219 originalState := &terraform.State{ 220 Modules: []*terraform.ModuleState{ 221 &terraform.ModuleState{ 222 Path: []string{"root"}, 223 Resources: map[string]*terraform.ResourceState{ 224 "test_instance.foo": &terraform.ResourceState{ 225 Type: "test_instance", 226 Primary: &terraform.InstanceState{ 227 ID: "bar", 228 }, 229 }, 230 }, 231 }, 232 }, 233 } 234 235 err := (&state.LocalState{Path: "test.tfstate"}).WriteState(originalState) 236 if err != nil { 237 t.Fatal(err) 238 } 239 240 args := []string{"-state", "test.tfstate", "test"} 241 ui := new(cli.MockUi) 242 newCmd := &WorkspaceNewCommand{ 243 Meta: Meta{Ui: ui}, 244 } 245 if code := newCmd.Run(args); code != 0 { 246 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter) 247 } 248 249 newPath := filepath.Join(local.DefaultWorkspaceDir, "test", DefaultStateFilename) 250 envState := state.LocalState{Path: newPath} 251 err = envState.RefreshState() 252 if err != nil { 253 t.Fatal(err) 254 } 255 256 newState := envState.State() 257 originalState.Version = newState.Version // the round-trip through the state manager implicitly populates version 258 if !originalState.Equal(newState) { 259 t.Fatalf("states not equal\norig: %s\nnew: %s", originalState, newState) 260 } 261 } 262 263 func TestWorkspace_delete(t *testing.T) { 264 td := tempDir(t) 265 os.MkdirAll(td, 0755) 266 defer os.RemoveAll(td) 267 defer testChdir(t, td)() 268 269 // create the workspace directories 270 if err := os.MkdirAll(filepath.Join(local.DefaultWorkspaceDir, "test"), 0755); err != nil { 271 t.Fatal(err) 272 } 273 274 // create the workspace file 275 if err := os.MkdirAll(DefaultDataDir, 0755); err != nil { 276 t.Fatal(err) 277 } 278 if err := ioutil.WriteFile(filepath.Join(DefaultDataDir, local.DefaultWorkspaceFile), []byte("test"), 0644); err != nil { 279 t.Fatal(err) 280 } 281 282 ui := new(cli.MockUi) 283 delCmd := &WorkspaceDeleteCommand{ 284 Meta: Meta{Ui: ui}, 285 } 286 287 current := delCmd.Workspace() 288 if current != "test" { 289 t.Fatal("wrong workspace:", current) 290 } 291 292 // we can't delete our current workspace 293 args := []string{"test"} 294 if code := delCmd.Run(args); code == 0 { 295 t.Fatal("expected error deleting current workspace") 296 } 297 298 // change back to default 299 if err := delCmd.SetWorkspace(backend.DefaultStateName); err != nil { 300 t.Fatal(err) 301 } 302 303 // try the delete again 304 ui = new(cli.MockUi) 305 delCmd.Meta.Ui = ui 306 if code := delCmd.Run(args); code != 0 { 307 t.Fatalf("error deleting workspace: %s", ui.ErrorWriter) 308 } 309 310 current = delCmd.Workspace() 311 if current != backend.DefaultStateName { 312 t.Fatalf("wrong workspace: %q", current) 313 } 314 } 315 func TestWorkspace_deleteWithState(t *testing.T) { 316 td := tempDir(t) 317 os.MkdirAll(td, 0755) 318 defer os.RemoveAll(td) 319 defer testChdir(t, td)() 320 321 // create the workspace directories 322 if err := os.MkdirAll(filepath.Join(local.DefaultWorkspaceDir, "test"), 0755); err != nil { 323 t.Fatal(err) 324 } 325 326 // create a non-empty state 327 originalState := &terraform.State{ 328 Modules: []*terraform.ModuleState{ 329 &terraform.ModuleState{ 330 Path: []string{"root"}, 331 Resources: map[string]*terraform.ResourceState{ 332 "test_instance.foo": &terraform.ResourceState{ 333 Type: "test_instance", 334 Primary: &terraform.InstanceState{ 335 ID: "bar", 336 }, 337 }, 338 }, 339 }, 340 }, 341 } 342 343 envStatePath := filepath.Join(local.DefaultWorkspaceDir, "test", DefaultStateFilename) 344 err := (&state.LocalState{Path: envStatePath}).WriteState(originalState) 345 if err != nil { 346 t.Fatal(err) 347 } 348 349 ui := new(cli.MockUi) 350 delCmd := &WorkspaceDeleteCommand{ 351 Meta: Meta{Ui: ui}, 352 } 353 args := []string{"test"} 354 if code := delCmd.Run(args); code == 0 { 355 t.Fatalf("expected failure without -force.\noutput: %s", ui.OutputWriter) 356 } 357 358 ui = new(cli.MockUi) 359 delCmd.Meta.Ui = ui 360 361 args = []string{"-force", "test"} 362 if code := delCmd.Run(args); code != 0 { 363 t.Fatalf("failure: %s", ui.ErrorWriter) 364 } 365 366 if _, err := os.Stat(filepath.Join(local.DefaultWorkspaceDir, "test")); !os.IsNotExist(err) { 367 t.Fatal("env 'test' still exists!") 368 } 369 }