github.com/pulumi/terraform@v1.4.0/pkg/command/meta_test.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"reflect"
     9  	"strings"
    10  	"testing"
    11  
    12  	"github.com/google/go-cmp/cmp"
    13  
    14  	"github.com/pulumi/terraform/pkg/backend"
    15  	"github.com/pulumi/terraform/pkg/backend/local"
    16  	"github.com/pulumi/terraform/pkg/terraform"
    17  	"github.com/mitchellh/cli"
    18  )
    19  
    20  func TestMetaColorize(t *testing.T) {
    21  	var m *Meta
    22  	var args, args2 []string
    23  
    24  	// Test basic, color
    25  	m = new(Meta)
    26  	m.Color = true
    27  	args = []string{"foo", "bar"}
    28  	args2 = []string{"foo", "bar"}
    29  	args = m.process(args)
    30  	if !reflect.DeepEqual(args, args2) {
    31  		t.Fatalf("bad: %#v", args)
    32  	}
    33  	if m.Colorize().Disable {
    34  		t.Fatal("should not be disabled")
    35  	}
    36  
    37  	// Test basic, no change
    38  	m = new(Meta)
    39  	args = []string{"foo", "bar"}
    40  	args2 = []string{"foo", "bar"}
    41  	args = m.process(args)
    42  	if !reflect.DeepEqual(args, args2) {
    43  		t.Fatalf("bad: %#v", args)
    44  	}
    45  	if !m.Colorize().Disable {
    46  		t.Fatal("should be disabled")
    47  	}
    48  
    49  	// Test disable #1
    50  	m = new(Meta)
    51  	m.Color = true
    52  	args = []string{"foo", "-no-color", "bar"}
    53  	args2 = []string{"foo", "bar"}
    54  	args = m.process(args)
    55  	if !reflect.DeepEqual(args, args2) {
    56  		t.Fatalf("bad: %#v", args)
    57  	}
    58  	if !m.Colorize().Disable {
    59  		t.Fatal("should be disabled")
    60  	}
    61  
    62  	// Test disable #2
    63  	// Verify multiple -no-color options are removed from args slice.
    64  	// E.g. an additional -no-color arg could be added by TF_CLI_ARGS.
    65  	m = new(Meta)
    66  	m.Color = true
    67  	args = []string{"foo", "-no-color", "bar", "-no-color"}
    68  	args2 = []string{"foo", "bar"}
    69  	args = m.process(args)
    70  	if !reflect.DeepEqual(args, args2) {
    71  		t.Fatalf("bad: %#v", args)
    72  	}
    73  	if !m.Colorize().Disable {
    74  		t.Fatal("should be disabled")
    75  	}
    76  }
    77  
    78  func TestMetaInputMode(t *testing.T) {
    79  	test = false
    80  	defer func() { test = true }()
    81  
    82  	m := new(Meta)
    83  	args := []string{}
    84  
    85  	fs := m.extendedFlagSet("foo")
    86  	if err := fs.Parse(args); err != nil {
    87  		t.Fatalf("err: %s", err)
    88  	}
    89  
    90  	if m.InputMode() != terraform.InputModeStd {
    91  		t.Fatalf("bad: %#v", m.InputMode())
    92  	}
    93  }
    94  
    95  func TestMetaInputMode_envVar(t *testing.T) {
    96  	test = false
    97  	defer func() { test = true }()
    98  	old := os.Getenv(InputModeEnvVar)
    99  	defer os.Setenv(InputModeEnvVar, old)
   100  
   101  	m := new(Meta)
   102  	args := []string{}
   103  
   104  	fs := m.extendedFlagSet("foo")
   105  	if err := fs.Parse(args); err != nil {
   106  		t.Fatalf("err: %s", err)
   107  	}
   108  
   109  	off := terraform.InputMode(0)
   110  	on := terraform.InputModeStd
   111  	cases := []struct {
   112  		EnvVar   string
   113  		Expected terraform.InputMode
   114  	}{
   115  		{"false", off},
   116  		{"0", off},
   117  		{"true", on},
   118  		{"1", on},
   119  	}
   120  
   121  	for _, tc := range cases {
   122  		os.Setenv(InputModeEnvVar, tc.EnvVar)
   123  		if m.InputMode() != tc.Expected {
   124  			t.Fatalf("expected InputMode: %#v, got: %#v", tc.Expected, m.InputMode())
   125  		}
   126  	}
   127  }
   128  
   129  func TestMetaInputMode_disable(t *testing.T) {
   130  	test = false
   131  	defer func() { test = true }()
   132  
   133  	m := new(Meta)
   134  	args := []string{"-input=false"}
   135  
   136  	fs := m.extendedFlagSet("foo")
   137  	if err := fs.Parse(args); err != nil {
   138  		t.Fatalf("err: %s", err)
   139  	}
   140  
   141  	if m.InputMode() > 0 {
   142  		t.Fatalf("bad: %#v", m.InputMode())
   143  	}
   144  }
   145  
   146  func TestMeta_initStatePaths(t *testing.T) {
   147  	m := new(Meta)
   148  	m.initStatePaths()
   149  
   150  	if m.statePath != DefaultStateFilename {
   151  		t.Fatalf("bad: %#v", m)
   152  	}
   153  	if m.stateOutPath != DefaultStateFilename {
   154  		t.Fatalf("bad: %#v", m)
   155  	}
   156  	if m.backupPath != DefaultStateFilename+DefaultBackupExtension {
   157  		t.Fatalf("bad: %#v", m)
   158  	}
   159  
   160  	m = new(Meta)
   161  	m.statePath = "foo"
   162  	m.initStatePaths()
   163  
   164  	if m.stateOutPath != "foo" {
   165  		t.Fatalf("bad: %#v", m)
   166  	}
   167  	if m.backupPath != "foo"+DefaultBackupExtension {
   168  		t.Fatalf("bad: %#v", m)
   169  	}
   170  
   171  	m = new(Meta)
   172  	m.stateOutPath = "foo"
   173  	m.initStatePaths()
   174  
   175  	if m.statePath != DefaultStateFilename {
   176  		t.Fatalf("bad: %#v", m)
   177  	}
   178  	if m.backupPath != "foo"+DefaultBackupExtension {
   179  		t.Fatalf("bad: %#v", m)
   180  	}
   181  }
   182  
   183  func TestMeta_Env(t *testing.T) {
   184  	td := t.TempDir()
   185  	os.MkdirAll(td, 0755)
   186  	defer testChdir(t, td)()
   187  
   188  	m := new(Meta)
   189  
   190  	env, err := m.Workspace()
   191  	if err != nil {
   192  		t.Fatal(err)
   193  	}
   194  
   195  	if env != backend.DefaultStateName {
   196  		t.Fatalf("expected env %q, got env %q", backend.DefaultStateName, env)
   197  	}
   198  
   199  	testEnv := "test_env"
   200  	if err := m.SetWorkspace(testEnv); err != nil {
   201  		t.Fatal("error setting env:", err)
   202  	}
   203  
   204  	env, _ = m.Workspace()
   205  	if env != testEnv {
   206  		t.Fatalf("expected env %q, got env %q", testEnv, env)
   207  	}
   208  
   209  	if err := m.SetWorkspace(backend.DefaultStateName); err != nil {
   210  		t.Fatal("error setting env:", err)
   211  	}
   212  
   213  	env, _ = m.Workspace()
   214  	if env != backend.DefaultStateName {
   215  		t.Fatalf("expected env %q, got env %q", backend.DefaultStateName, env)
   216  	}
   217  }
   218  
   219  func TestMeta_Workspace_override(t *testing.T) {
   220  	defer func(value string) {
   221  		os.Setenv(WorkspaceNameEnvVar, value)
   222  	}(os.Getenv(WorkspaceNameEnvVar))
   223  
   224  	m := new(Meta)
   225  
   226  	testCases := map[string]struct {
   227  		workspace string
   228  		err       error
   229  	}{
   230  		"": {
   231  			"default",
   232  			nil,
   233  		},
   234  		"development": {
   235  			"development",
   236  			nil,
   237  		},
   238  		"invalid name": {
   239  			"",
   240  			errInvalidWorkspaceNameEnvVar,
   241  		},
   242  	}
   243  
   244  	for name, tc := range testCases {
   245  		t.Run(name, func(t *testing.T) {
   246  			os.Setenv(WorkspaceNameEnvVar, name)
   247  			workspace, err := m.Workspace()
   248  			if workspace != tc.workspace {
   249  				t.Errorf("Unexpected workspace\n got: %s\nwant: %s\n", workspace, tc.workspace)
   250  			}
   251  			if err != tc.err {
   252  				t.Errorf("Unexpected error\n got: %s\nwant: %s\n", err, tc.err)
   253  			}
   254  		})
   255  	}
   256  }
   257  
   258  func TestMeta_Workspace_invalidSelected(t *testing.T) {
   259  	td := t.TempDir()
   260  	os.MkdirAll(td, 0755)
   261  	defer testChdir(t, td)()
   262  
   263  	// this is an invalid workspace name
   264  	workspace := "test workspace"
   265  
   266  	// create the workspace directories
   267  	if err := os.MkdirAll(filepath.Join(local.DefaultWorkspaceDir, workspace), 0755); err != nil {
   268  		t.Fatal(err)
   269  	}
   270  
   271  	// create the workspace file to select it
   272  	if err := os.MkdirAll(DefaultDataDir, 0755); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  	if err := ioutil.WriteFile(filepath.Join(DefaultDataDir, local.DefaultWorkspaceFile), []byte(workspace), 0644); err != nil {
   276  		t.Fatal(err)
   277  	}
   278  
   279  	m := new(Meta)
   280  
   281  	ws, err := m.Workspace()
   282  	if ws != workspace {
   283  		t.Errorf("Unexpected workspace\n got: %s\nwant: %s\n", ws, workspace)
   284  	}
   285  	if err != nil {
   286  		t.Errorf("Unexpected error: %s", err)
   287  	}
   288  }
   289  
   290  func TestMeta_process(t *testing.T) {
   291  	test = false
   292  	defer func() { test = true }()
   293  
   294  	// Create a temporary directory for our cwd
   295  	d := t.TempDir()
   296  	os.MkdirAll(d, 0755)
   297  	defer testChdir(t, d)()
   298  
   299  	// At one point it was the responsibility of this process function to
   300  	// insert fake additional -var-file options into the command line
   301  	// if the automatic tfvars files were present. This is no longer the
   302  	// responsibility of process (it happens in collectVariableValues instead)
   303  	// but we're still testing with these files in place to verify that
   304  	// they _aren't_ being interpreted by process, since that could otherwise
   305  	// cause them to be added more than once and mess up the precedence order.
   306  	defaultVarsfile := "terraform.tfvars"
   307  	err := ioutil.WriteFile(
   308  		filepath.Join(d, defaultVarsfile),
   309  		[]byte(""),
   310  		0644)
   311  	if err != nil {
   312  		t.Fatalf("err: %s", err)
   313  	}
   314  	fileFirstAlphabetical := "a-file.auto.tfvars"
   315  	err = ioutil.WriteFile(
   316  		filepath.Join(d, fileFirstAlphabetical),
   317  		[]byte(""),
   318  		0644)
   319  	if err != nil {
   320  		t.Fatalf("err: %s", err)
   321  	}
   322  	fileLastAlphabetical := "z-file.auto.tfvars"
   323  	err = ioutil.WriteFile(
   324  		filepath.Join(d, fileLastAlphabetical),
   325  		[]byte(""),
   326  		0644)
   327  	if err != nil {
   328  		t.Fatalf("err: %s", err)
   329  	}
   330  	// Regular tfvars files will not be autoloaded
   331  	fileIgnored := "ignored.tfvars"
   332  	err = ioutil.WriteFile(
   333  		filepath.Join(d, fileIgnored),
   334  		[]byte(""),
   335  		0644)
   336  	if err != nil {
   337  		t.Fatalf("err: %s", err)
   338  	}
   339  
   340  	tests := []struct {
   341  		GivenArgs    []string
   342  		FilteredArgs []string
   343  		ExtraCheck   func(*testing.T, *Meta)
   344  	}{
   345  		{
   346  			[]string{},
   347  			[]string{},
   348  			func(t *testing.T, m *Meta) {
   349  				if got, want := m.color, true; got != want {
   350  					t.Errorf("wrong m.color value %#v; want %#v", got, want)
   351  				}
   352  				if got, want := m.Color, true; got != want {
   353  					t.Errorf("wrong m.Color value %#v; want %#v", got, want)
   354  				}
   355  			},
   356  		},
   357  		{
   358  			[]string{"-no-color"},
   359  			[]string{},
   360  			func(t *testing.T, m *Meta) {
   361  				if got, want := m.color, false; got != want {
   362  					t.Errorf("wrong m.color value %#v; want %#v", got, want)
   363  				}
   364  				if got, want := m.Color, false; got != want {
   365  					t.Errorf("wrong m.Color value %#v; want %#v", got, want)
   366  				}
   367  			},
   368  		},
   369  	}
   370  
   371  	for _, test := range tests {
   372  		t.Run(fmt.Sprintf("%s", test.GivenArgs), func(t *testing.T) {
   373  			m := new(Meta)
   374  			m.Color = true // this is the default also for normal use, overridden by -no-color
   375  			args := test.GivenArgs
   376  			args = m.process(args)
   377  
   378  			if !cmp.Equal(test.FilteredArgs, args) {
   379  				t.Errorf("wrong filtered arguments\n%s", cmp.Diff(test.FilteredArgs, args))
   380  			}
   381  
   382  			if test.ExtraCheck != nil {
   383  				test.ExtraCheck(t, m)
   384  			}
   385  		})
   386  	}
   387  }
   388  
   389  func TestCommand_checkRequiredVersion(t *testing.T) {
   390  	// Create a temporary working directory that is empty
   391  	td := t.TempDir()
   392  	testCopyDir(t, testFixturePath("command-check-required-version"), td)
   393  	defer testChdir(t, td)()
   394  
   395  	ui := cli.NewMockUi()
   396  	meta := Meta{
   397  		Ui: ui,
   398  	}
   399  
   400  	diags := meta.checkRequiredVersion()
   401  	if diags == nil {
   402  		t.Fatalf("diagnostics should contain unmet version constraint, but is nil")
   403  	}
   404  
   405  	meta.showDiagnostics(diags)
   406  
   407  	// Required version diags are correct
   408  	errStr := ui.ErrorWriter.String()
   409  	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
   410  		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
   411  	}
   412  	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
   413  		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
   414  	}
   415  }