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