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  }