github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/command/init_test.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"reflect"
     9  	"runtime"
    10  	"sort"
    11  	"strings"
    12  	"testing"
    13  
    14  	"github.com/hashicorp/terraform/backend/local"
    15  	"github.com/hashicorp/terraform/helper/copy"
    16  	"github.com/hashicorp/terraform/plugin/discovery"
    17  	"github.com/hashicorp/terraform/state"
    18  	"github.com/hashicorp/terraform/terraform"
    19  	"github.com/mitchellh/cli"
    20  )
    21  
    22  func TestInit_empty(t *testing.T) {
    23  	// Create a temporary working directory that is empty
    24  	td := tempDir(t)
    25  	os.MkdirAll(td, 0755)
    26  	defer os.RemoveAll(td)
    27  	defer testChdir(t, td)()
    28  
    29  	ui := new(cli.MockUi)
    30  	c := &InitCommand{
    31  		Meta: Meta{
    32  			testingOverrides: metaOverridesForProvider(testProvider()),
    33  			Ui:               ui,
    34  		},
    35  	}
    36  
    37  	args := []string{}
    38  	if code := c.Run(args); code != 0 {
    39  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
    40  	}
    41  }
    42  
    43  func TestInit_multipleArgs(t *testing.T) {
    44  	ui := new(cli.MockUi)
    45  	c := &InitCommand{
    46  		Meta: Meta{
    47  			testingOverrides: metaOverridesForProvider(testProvider()),
    48  			Ui:               ui,
    49  		},
    50  	}
    51  
    52  	args := []string{
    53  		"bad",
    54  		"bad",
    55  	}
    56  	if code := c.Run(args); code != 1 {
    57  		t.Fatalf("bad: \n%s", ui.OutputWriter.String())
    58  	}
    59  }
    60  
    61  func TestInit_fromModule_explicitDest(t *testing.T) {
    62  	dir := tempDir(t)
    63  
    64  	ui := new(cli.MockUi)
    65  	c := &InitCommand{
    66  		Meta: Meta{
    67  			testingOverrides: metaOverridesForProvider(testProvider()),
    68  			Ui:               ui,
    69  		},
    70  	}
    71  
    72  	args := []string{
    73  		"-from-module=" + testFixturePath("init"),
    74  		dir,
    75  	}
    76  	if code := c.Run(args); code != 0 {
    77  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
    78  	}
    79  
    80  	if _, err := os.Stat(filepath.Join(dir, "hello.tf")); err != nil {
    81  		t.Fatalf("err: %s", err)
    82  	}
    83  }
    84  
    85  func TestInit_fromModule_cwdDest(t *testing.T) {
    86  	// Create a temporary working directory that is empty
    87  	td := tempDir(t)
    88  	os.MkdirAll(td, os.ModePerm)
    89  	defer os.RemoveAll(td)
    90  	defer testChdir(t, td)()
    91  
    92  	ui := new(cli.MockUi)
    93  	c := &InitCommand{
    94  		Meta: Meta{
    95  			testingOverrides: metaOverridesForProvider(testProvider()),
    96  			Ui:               ui,
    97  		},
    98  	}
    99  
   100  	args := []string{
   101  		"-from-module=" + testFixturePath("init"),
   102  	}
   103  	if code := c.Run(args); code != 0 {
   104  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   105  	}
   106  
   107  	if _, err := os.Stat(filepath.Join(td, "hello.tf")); err != nil {
   108  		t.Fatalf("err: %s", err)
   109  	}
   110  }
   111  
   112  // https://github.com/hashicorp/terraform/issues/518
   113  func TestInit_fromModule_dstInSrc(t *testing.T) {
   114  	dir := tempDir(t)
   115  	if err := os.MkdirAll(dir, 0755); err != nil {
   116  		t.Fatalf("err: %s", err)
   117  	}
   118  
   119  	// Change to the temporary directory
   120  	cwd, err := os.Getwd()
   121  	if err != nil {
   122  		t.Fatalf("err: %s", err)
   123  	}
   124  	if err := os.Chdir(dir); err != nil {
   125  		t.Fatalf("err: %s", err)
   126  	}
   127  	defer os.Chdir(cwd)
   128  
   129  	if _, err := os.Create("issue518.tf"); err != nil {
   130  		t.Fatalf("err: %s", err)
   131  	}
   132  
   133  	ui := new(cli.MockUi)
   134  	c := &InitCommand{
   135  		Meta: Meta{
   136  			testingOverrides: metaOverridesForProvider(testProvider()),
   137  			Ui:               ui,
   138  		},
   139  	}
   140  
   141  	args := []string{
   142  		"-from-module=.",
   143  		"foo",
   144  	}
   145  	if code := c.Run(args); code != 0 {
   146  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   147  	}
   148  
   149  	if _, err := os.Stat(filepath.Join(dir, "foo", "issue518.tf")); err != nil {
   150  		t.Fatalf("err: %s", err)
   151  	}
   152  }
   153  
   154  func TestInit_get(t *testing.T) {
   155  	// Create a temporary working directory that is empty
   156  	td := tempDir(t)
   157  	copy.CopyDir(testFixturePath("init-get"), td)
   158  	defer os.RemoveAll(td)
   159  	defer testChdir(t, td)()
   160  
   161  	ui := new(cli.MockUi)
   162  	c := &InitCommand{
   163  		Meta: Meta{
   164  			testingOverrides: metaOverridesForProvider(testProvider()),
   165  			Ui:               ui,
   166  		},
   167  	}
   168  
   169  	args := []string{}
   170  	if code := c.Run(args); code != 0 {
   171  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   172  	}
   173  
   174  	// Check output
   175  	output := ui.OutputWriter.String()
   176  	if !strings.Contains(output, "Getting source") {
   177  		t.Fatalf("doesn't look like get: %s", output)
   178  	}
   179  }
   180  
   181  func TestInit_getUpgradeModules(t *testing.T) {
   182  	// Create a temporary working directory that is empty
   183  	td := tempDir(t)
   184  	os.MkdirAll(td, 0755)
   185  	// copy.CopyDir(testFixturePath("init-get"), td)
   186  	defer os.RemoveAll(td)
   187  	defer testChdir(t, td)()
   188  
   189  	ui := new(cli.MockUi)
   190  	c := &InitCommand{
   191  		Meta: Meta{
   192  			testingOverrides: metaOverridesForProvider(testProvider()),
   193  			Ui:               ui,
   194  		},
   195  	}
   196  
   197  	args := []string{
   198  		"-get=true",
   199  		"-get-plugins=false",
   200  		"-upgrade",
   201  		testFixturePath("init-get"),
   202  	}
   203  	if code := c.Run(args); code != 0 {
   204  		t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String())
   205  	}
   206  
   207  	// Check output
   208  	output := ui.OutputWriter.String()
   209  	if !strings.Contains(output, "Updating source") {
   210  		t.Fatalf("doesn't look like get upgrade: %s", output)
   211  	}
   212  }
   213  
   214  func TestInit_backend(t *testing.T) {
   215  	// Create a temporary working directory that is empty
   216  	td := tempDir(t)
   217  	copy.CopyDir(testFixturePath("init-backend"), td)
   218  	defer os.RemoveAll(td)
   219  	defer testChdir(t, td)()
   220  
   221  	ui := new(cli.MockUi)
   222  	c := &InitCommand{
   223  		Meta: Meta{
   224  			testingOverrides: metaOverridesForProvider(testProvider()),
   225  			Ui:               ui,
   226  		},
   227  	}
   228  
   229  	args := []string{}
   230  	if code := c.Run(args); code != 0 {
   231  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   232  	}
   233  
   234  	if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil {
   235  		t.Fatalf("err: %s", err)
   236  	}
   237  }
   238  
   239  func TestInit_backendUnset(t *testing.T) {
   240  	// Create a temporary working directory that is empty
   241  	td := tempDir(t)
   242  	copy.CopyDir(testFixturePath("init-backend"), td)
   243  	defer os.RemoveAll(td)
   244  	defer testChdir(t, td)()
   245  
   246  	{
   247  		ui := new(cli.MockUi)
   248  		c := &InitCommand{
   249  			Meta: Meta{
   250  				testingOverrides: metaOverridesForProvider(testProvider()),
   251  				Ui:               ui,
   252  			},
   253  		}
   254  
   255  		// Init
   256  		args := []string{}
   257  		if code := c.Run(args); code != 0 {
   258  			t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   259  		}
   260  
   261  		if _, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename)); err != nil {
   262  			t.Fatalf("err: %s", err)
   263  		}
   264  	}
   265  
   266  	{
   267  		// Unset
   268  		if err := ioutil.WriteFile("main.tf", []byte(""), 0644); err != nil {
   269  			t.Fatalf("err: %s", err)
   270  		}
   271  
   272  		ui := new(cli.MockUi)
   273  		c := &InitCommand{
   274  			Meta: Meta{
   275  				testingOverrides: metaOverridesForProvider(testProvider()),
   276  				Ui:               ui,
   277  			},
   278  		}
   279  
   280  		args := []string{"-force-copy"}
   281  		if code := c.Run(args); code != 0 {
   282  			t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   283  		}
   284  
   285  		s := testStateRead(t, filepath.Join(
   286  			DefaultDataDir, DefaultStateFilename))
   287  		if !s.Backend.Empty() {
   288  			t.Fatal("should not have backend config")
   289  		}
   290  	}
   291  }
   292  
   293  func TestInit_backendConfigFile(t *testing.T) {
   294  	// Create a temporary working directory that is empty
   295  	td := tempDir(t)
   296  	copy.CopyDir(testFixturePath("init-backend-config-file"), td)
   297  	defer os.RemoveAll(td)
   298  	defer testChdir(t, td)()
   299  
   300  	ui := new(cli.MockUi)
   301  	c := &InitCommand{
   302  		Meta: Meta{
   303  			testingOverrides: metaOverridesForProvider(testProvider()),
   304  			Ui:               ui,
   305  		},
   306  	}
   307  
   308  	args := []string{"-backend-config", "input.config"}
   309  	if code := c.Run(args); code != 0 {
   310  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   311  	}
   312  
   313  	// Read our saved backend config and verify we have our settings
   314  	state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
   315  	if v := state.Backend.Config["path"]; v != "hello" {
   316  		t.Fatalf("bad: %#v", v)
   317  	}
   318  }
   319  
   320  func TestInit_backendConfigFileChange(t *testing.T) {
   321  	// Create a temporary working directory that is empty
   322  	td := tempDir(t)
   323  	copy.CopyDir(testFixturePath("init-backend-config-file-change"), td)
   324  	defer os.RemoveAll(td)
   325  	defer testChdir(t, td)()
   326  
   327  	// Ask input
   328  	defer testInputMap(t, map[string]string{
   329  		"backend-migrate-to-new": "no",
   330  	})()
   331  
   332  	ui := new(cli.MockUi)
   333  	c := &InitCommand{
   334  		Meta: Meta{
   335  			testingOverrides: metaOverridesForProvider(testProvider()),
   336  			Ui:               ui,
   337  		},
   338  	}
   339  
   340  	args := []string{"-backend-config", "input.config"}
   341  	if code := c.Run(args); code != 0 {
   342  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   343  	}
   344  
   345  	// Read our saved backend config and verify we have our settings
   346  	state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
   347  	if v := state.Backend.Config["path"]; v != "hello" {
   348  		t.Fatalf("bad: %#v", v)
   349  	}
   350  }
   351  
   352  func TestInit_backendConfigKV(t *testing.T) {
   353  	// Create a temporary working directory that is empty
   354  	td := tempDir(t)
   355  	copy.CopyDir(testFixturePath("init-backend-config-kv"), td)
   356  	defer os.RemoveAll(td)
   357  	defer testChdir(t, td)()
   358  
   359  	ui := new(cli.MockUi)
   360  	c := &InitCommand{
   361  		Meta: Meta{
   362  			testingOverrides: metaOverridesForProvider(testProvider()),
   363  			Ui:               ui,
   364  		},
   365  	}
   366  
   367  	args := []string{"-backend-config", "path=hello"}
   368  	if code := c.Run(args); code != 0 {
   369  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   370  	}
   371  
   372  	// Read our saved backend config and verify we have our settings
   373  	state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
   374  	if v := state.Backend.Config["path"]; v != "hello" {
   375  		t.Fatalf("bad: %#v", v)
   376  	}
   377  }
   378  
   379  func TestInit_targetSubdir(t *testing.T) {
   380  	// Create a temporary working directory that is empty
   381  	td := tempDir(t)
   382  	os.MkdirAll(td, 0755)
   383  	defer os.RemoveAll(td)
   384  	defer testChdir(t, td)()
   385  
   386  	// copy the source into a subdir
   387  	copy.CopyDir(testFixturePath("init-backend"), filepath.Join(td, "source"))
   388  
   389  	ui := new(cli.MockUi)
   390  	c := &InitCommand{
   391  		Meta: Meta{
   392  			testingOverrides: metaOverridesForProvider(testProvider()),
   393  			Ui:               ui,
   394  		},
   395  	}
   396  
   397  	args := []string{
   398  		"source",
   399  	}
   400  	if code := c.Run(args); code != 0 {
   401  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   402  	}
   403  
   404  	if _, err := os.Stat(filepath.Join(td, DefaultDataDir, DefaultStateFilename)); err != nil {
   405  		t.Fatalf("err: %s", err)
   406  	}
   407  
   408  	// a data directory should not have been added to out working dir
   409  	if _, err := os.Stat(filepath.Join(td, "source", DefaultDataDir)); !os.IsNotExist(err) {
   410  		t.Fatalf("err: %s", err)
   411  	}
   412  }
   413  
   414  func TestInit_backendReinitWithExtra(t *testing.T) {
   415  	td := tempDir(t)
   416  	copy.CopyDir(testFixturePath("init-backend-empty"), td)
   417  	defer os.RemoveAll(td)
   418  	defer testChdir(t, td)()
   419  
   420  	m := testMetaBackend(t, nil)
   421  	opts := &BackendOpts{
   422  		ConfigExtra: map[string]interface{}{"path": "hello"},
   423  		Init:        true,
   424  	}
   425  
   426  	b, err := m.backendConfig(opts)
   427  	if err != nil {
   428  		t.Fatal(err)
   429  	}
   430  
   431  	ui := new(cli.MockUi)
   432  	c := &InitCommand{
   433  		Meta: Meta{
   434  			testingOverrides: metaOverridesForProvider(testProvider()),
   435  			Ui:               ui,
   436  		},
   437  	}
   438  
   439  	args := []string{"-backend-config", "path=hello"}
   440  	if code := c.Run(args); code != 0 {
   441  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   442  	}
   443  
   444  	// Read our saved backend config and verify we have our settings
   445  	state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
   446  	if v := state.Backend.Config["path"]; v != "hello" {
   447  		t.Fatalf("bad: %#v", v)
   448  	}
   449  
   450  	if state.Backend.Hash != b.Hash {
   451  		t.Fatal("mismatched state and config backend hashes")
   452  	}
   453  
   454  	if state.Backend.Rehash() != b.Rehash() {
   455  		t.Fatal("mismatched state and config re-hashes")
   456  	}
   457  
   458  	// init again and make sure nothing changes
   459  	if code := c.Run(args); code != 0 {
   460  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   461  	}
   462  	state = testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
   463  	if v := state.Backend.Config["path"]; v != "hello" {
   464  		t.Fatalf("bad: %#v", v)
   465  	}
   466  
   467  	if state.Backend.Hash != b.Hash {
   468  		t.Fatal("mismatched state and config backend hashes")
   469  	}
   470  }
   471  
   472  // move option from config to -backend-config args
   473  func TestInit_backendReinitConfigToExtra(t *testing.T) {
   474  	td := tempDir(t)
   475  	copy.CopyDir(testFixturePath("init-backend"), td)
   476  	defer os.RemoveAll(td)
   477  	defer testChdir(t, td)()
   478  
   479  	ui := new(cli.MockUi)
   480  	c := &InitCommand{
   481  		Meta: Meta{
   482  			testingOverrides: metaOverridesForProvider(testProvider()),
   483  			Ui:               ui,
   484  		},
   485  	}
   486  
   487  	if code := c.Run([]string{"-input=false"}); code != 0 {
   488  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   489  	}
   490  
   491  	// Read our saved backend config and verify we have our settings
   492  	state := testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
   493  	if v := state.Backend.Config["path"]; v != "foo" {
   494  		t.Fatalf("bad: %#v", v)
   495  	}
   496  
   497  	backendHash := state.Backend.Hash
   498  
   499  	// init again but remove the path option from the config
   500  	cfg := "terraform {\n  backend \"local\" {}\n}\n"
   501  	if err := ioutil.WriteFile("main.tf", []byte(cfg), 0644); err != nil {
   502  		t.Fatal(err)
   503  	}
   504  
   505  	args := []string{"-input=false", "-backend-config=path=foo"}
   506  	if code := c.Run(args); code != 0 {
   507  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   508  	}
   509  	state = testStateRead(t, filepath.Join(DefaultDataDir, DefaultStateFilename))
   510  
   511  	if state.Backend.Hash == backendHash {
   512  		t.Fatal("state.Backend.Hash was not updated")
   513  	}
   514  }
   515  
   516  // make sure inputFalse stops execution on migrate
   517  func TestInit_inputFalse(t *testing.T) {
   518  	td := tempDir(t)
   519  	copy.CopyDir(testFixturePath("init-backend"), td)
   520  	defer os.RemoveAll(td)
   521  	defer testChdir(t, td)()
   522  
   523  	ui := new(cli.MockUi)
   524  	c := &InitCommand{
   525  		Meta: Meta{
   526  			testingOverrides: metaOverridesForProvider(testProvider()),
   527  			Ui:               ui,
   528  		},
   529  	}
   530  
   531  	args := []string{"-input=false", "-backend-config=path=foo"}
   532  	if code := c.Run([]string{"-input=false"}); code != 0 {
   533  		t.Fatalf("bad: \n%s", ui.ErrorWriter)
   534  	}
   535  
   536  	// write different states for foo and bar
   537  	s := terraform.NewState()
   538  	s.Lineage = "foo"
   539  	if err := (&state.LocalState{Path: "foo"}).WriteState(s); err != nil {
   540  		t.Fatal(err)
   541  	}
   542  	s.Lineage = "bar"
   543  	if err := (&state.LocalState{Path: "bar"}).WriteState(s); err != nil {
   544  		t.Fatal(err)
   545  	}
   546  
   547  	ui = new(cli.MockUi)
   548  	c = &InitCommand{
   549  		Meta: Meta{
   550  			testingOverrides: metaOverridesForProvider(testProvider()),
   551  			Ui:               ui,
   552  		},
   553  	}
   554  
   555  	args = []string{"-input=false", "-backend-config=path=bar"}
   556  	if code := c.Run(args); code == 0 {
   557  		t.Fatal("init should have failed", ui.OutputWriter)
   558  	}
   559  
   560  	errMsg := ui.ErrorWriter.String()
   561  	if !strings.Contains(errMsg, "input disabled") {
   562  		t.Fatal("expected input disabled error, got", errMsg)
   563  	}
   564  
   565  	ui = new(cli.MockUi)
   566  	c = &InitCommand{
   567  		Meta: Meta{
   568  			testingOverrides: metaOverridesForProvider(testProvider()),
   569  			Ui:               ui,
   570  		},
   571  	}
   572  
   573  	// A missing input=false should abort rather than loop infinitely
   574  	args = []string{"-backend-config=path=bar"}
   575  	if code := c.Run(args); code == 0 {
   576  		t.Fatal("init should have failed", ui.OutputWriter)
   577  	}
   578  }
   579  
   580  func TestInit_getProvider(t *testing.T) {
   581  	// Create a temporary working directory that is empty
   582  	td := tempDir(t)
   583  	copy.CopyDir(testFixturePath("init-get-providers"), td)
   584  	defer os.RemoveAll(td)
   585  	defer testChdir(t, td)()
   586  
   587  	overrides := metaOverridesForProvider(testProvider())
   588  	ui := new(cli.MockUi)
   589  	m := Meta{
   590  		testingOverrides: overrides,
   591  		Ui:               ui,
   592  	}
   593  	installer := &mockProviderInstaller{
   594  		Providers: map[string][]string{
   595  			// looking for an exact version
   596  			"exact": []string{"1.2.3"},
   597  			// config requires >= 2.3.3
   598  			"greater_than": []string{"2.3.4", "2.3.3", "2.3.0"},
   599  			// config specifies
   600  			"between": []string{"3.4.5", "2.3.4", "1.2.3"},
   601  		},
   602  
   603  		Dir: m.pluginDir(),
   604  	}
   605  
   606  	c := &InitCommand{
   607  		Meta:              m,
   608  		providerInstaller: installer,
   609  	}
   610  
   611  	args := []string{
   612  		"-backend=false", // should be possible to install plugins without backend init
   613  	}
   614  	if code := c.Run(args); code != 0 {
   615  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   616  	}
   617  
   618  	if !installer.PurgeUnusedCalled {
   619  		t.Errorf("init didn't purge providers, but should have")
   620  	}
   621  
   622  	// check that we got the providers for our config
   623  	exactPath := filepath.Join(c.pluginDir(), installer.FileName("exact", "1.2.3"))
   624  	if _, err := os.Stat(exactPath); os.IsNotExist(err) {
   625  		t.Fatal("provider 'exact' not downloaded")
   626  	}
   627  	greaterThanPath := filepath.Join(c.pluginDir(), installer.FileName("greater_than", "2.3.4"))
   628  	if _, err := os.Stat(greaterThanPath); os.IsNotExist(err) {
   629  		t.Fatal("provider 'greater_than' not downloaded")
   630  	}
   631  	betweenPath := filepath.Join(c.pluginDir(), installer.FileName("between", "2.3.4"))
   632  	if _, err := os.Stat(betweenPath); os.IsNotExist(err) {
   633  		t.Fatal("provider 'between' not downloaded")
   634  	}
   635  
   636  	t.Run("future-state", func(t *testing.T) {
   637  		// getting providers should fail if a state from a newer version of
   638  		// terraform exists, since InitCommand.getProviders needs to inspect that
   639  		// state.
   640  		s := terraform.NewState()
   641  		s.TFVersion = "100.1.0"
   642  		local := &state.LocalState{
   643  			Path: local.DefaultStateFilename,
   644  		}
   645  		if err := local.WriteState(s); err != nil {
   646  			t.Fatal(err)
   647  		}
   648  
   649  		ui := new(cli.MockUi)
   650  		m.Ui = ui
   651  		c := &InitCommand{
   652  			Meta:              m,
   653  			providerInstaller: installer,
   654  		}
   655  
   656  		if code := c.Run(nil); code == 0 {
   657  			t.Fatal("expected error, got:", ui.OutputWriter)
   658  		}
   659  
   660  		errMsg := ui.ErrorWriter.String()
   661  		if !strings.Contains(errMsg, "future Terraform version") {
   662  			t.Fatal("unexpected error:", errMsg)
   663  		}
   664  	})
   665  }
   666  
   667  // make sure we can locate providers in various paths
   668  func TestInit_findVendoredProviders(t *testing.T) {
   669  	// Create a temporary working directory that is empty
   670  	td := tempDir(t)
   671  
   672  	configDirName := "init-get-providers"
   673  	copy.CopyDir(testFixturePath(configDirName), filepath.Join(td, configDirName))
   674  	defer os.RemoveAll(td)
   675  	defer testChdir(t, td)()
   676  
   677  	ui := new(cli.MockUi)
   678  	m := Meta{
   679  		testingOverrides: metaOverridesForProvider(testProvider()),
   680  		Ui:               ui,
   681  	}
   682  
   683  	c := &InitCommand{
   684  		Meta:              m,
   685  		providerInstaller: &mockProviderInstaller{},
   686  	}
   687  
   688  	// make our plugin paths
   689  	if err := os.MkdirAll(c.pluginDir(), 0755); err != nil {
   690  		t.Fatal(err)
   691  	}
   692  	if err := os.MkdirAll(DefaultPluginVendorDir, 0755); err != nil {
   693  		t.Fatal(err)
   694  	}
   695  
   696  	// add some dummy providers
   697  	// the auto plugin directory
   698  	exactPath := filepath.Join(c.pluginDir(), "terraform-provider-exact_v1.2.3_x4")
   699  	if err := ioutil.WriteFile(exactPath, []byte("test bin"), 0755); err != nil {
   700  		t.Fatal(err)
   701  	}
   702  	// the vendor path
   703  	greaterThanPath := filepath.Join(DefaultPluginVendorDir, "terraform-provider-greater_than_v2.3.4_x4")
   704  	if err := ioutil.WriteFile(greaterThanPath, []byte("test bin"), 0755); err != nil {
   705  		t.Fatal(err)
   706  	}
   707  	// Check the current directory too
   708  	betweenPath := filepath.Join(".", "terraform-provider-between_v2.3.4_x4")
   709  	if err := ioutil.WriteFile(betweenPath, []byte("test bin"), 0755); err != nil {
   710  		t.Fatal(err)
   711  	}
   712  
   713  	args := []string{configDirName}
   714  	if code := c.Run(args); code != 0 {
   715  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   716  	}
   717  }
   718  
   719  // make sure we can locate providers defined in the legacy rc file
   720  func TestInit_rcProviders(t *testing.T) {
   721  	// Create a temporary working directory that is empty
   722  	td := tempDir(t)
   723  
   724  	configDirName := "init-legacy-rc"
   725  	copy.CopyDir(testFixturePath(configDirName), filepath.Join(td, configDirName))
   726  	defer os.RemoveAll(td)
   727  	defer testChdir(t, td)()
   728  
   729  	pluginDir := filepath.Join(td, "custom")
   730  	pluginPath := filepath.Join(pluginDir, "terraform-provider-legacy")
   731  
   732  	ui := new(cli.MockUi)
   733  	m := Meta{
   734  		Ui: ui,
   735  		PluginOverrides: &PluginOverrides{
   736  			Providers: map[string]string{
   737  				"legacy": pluginPath,
   738  			},
   739  		},
   740  	}
   741  
   742  	c := &InitCommand{
   743  		Meta:              m,
   744  		providerInstaller: &mockProviderInstaller{},
   745  	}
   746  
   747  	// make our plugin paths
   748  	if err := os.MkdirAll(pluginDir, 0755); err != nil {
   749  		t.Fatal(err)
   750  	}
   751  
   752  	if err := ioutil.WriteFile(pluginPath, []byte("test bin"), 0755); err != nil {
   753  		t.Fatal(err)
   754  	}
   755  
   756  	args := []string{configDirName}
   757  	if code := c.Run(args); code != 0 {
   758  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   759  	}
   760  }
   761  
   762  func TestInit_getUpgradePlugins(t *testing.T) {
   763  	// Create a temporary working directory that is empty
   764  	td := tempDir(t)
   765  	copy.CopyDir(testFixturePath("init-get-providers"), td)
   766  	defer os.RemoveAll(td)
   767  	defer testChdir(t, td)()
   768  
   769  	ui := new(cli.MockUi)
   770  	m := Meta{
   771  		testingOverrides: metaOverridesForProvider(testProvider()),
   772  		Ui:               ui,
   773  	}
   774  
   775  	installer := &mockProviderInstaller{
   776  		Providers: map[string][]string{
   777  			// looking for an exact version
   778  			"exact": []string{"1.2.3"},
   779  			// config requires >= 2.3.3
   780  			"greater_than": []string{"2.3.4", "2.3.3", "2.3.0"},
   781  			// config specifies
   782  			"between": []string{"3.4.5", "2.3.4", "1.2.3"},
   783  		},
   784  
   785  		Dir: m.pluginDir(),
   786  	}
   787  
   788  	err := os.MkdirAll(m.pluginDir(), os.ModePerm)
   789  	if err != nil {
   790  		t.Fatal(err)
   791  	}
   792  	exactUnwanted := filepath.Join(m.pluginDir(), installer.FileName("exact", "0.0.1"))
   793  	err = ioutil.WriteFile(exactUnwanted, []byte{}, os.ModePerm)
   794  	if err != nil {
   795  		t.Fatal(err)
   796  	}
   797  	greaterThanUnwanted := filepath.Join(m.pluginDir(), installer.FileName("greater_than", "2.3.3"))
   798  	err = ioutil.WriteFile(greaterThanUnwanted, []byte{}, os.ModePerm)
   799  	if err != nil {
   800  		t.Fatal(err)
   801  	}
   802  	betweenOverride := installer.FileName("between", "2.3.4") // intentionally directly in cwd, and should override auto-install
   803  	err = ioutil.WriteFile(betweenOverride, []byte{}, os.ModePerm)
   804  	if err != nil {
   805  		t.Fatal(err)
   806  	}
   807  
   808  	c := &InitCommand{
   809  		Meta:              m,
   810  		providerInstaller: installer,
   811  	}
   812  
   813  	args := []string{
   814  		"-upgrade=true",
   815  	}
   816  	if code := c.Run(args); code != 0 {
   817  		t.Fatalf("command did not complete successfully:\n%s", ui.ErrorWriter.String())
   818  	}
   819  
   820  	files, err := ioutil.ReadDir(m.pluginDir())
   821  	if err != nil {
   822  		t.Fatal(err)
   823  	}
   824  
   825  	if !installer.PurgeUnusedCalled {
   826  		t.Errorf("init -upgrade didn't purge providers, but should have")
   827  	}
   828  
   829  	gotFilenames := make([]string, len(files))
   830  	for i, info := range files {
   831  		gotFilenames[i] = info.Name()
   832  	}
   833  	sort.Strings(gotFilenames)
   834  
   835  	wantFilenames := []string{
   836  		"lock.json",
   837  
   838  		// no "between" because the file in cwd overrides it
   839  
   840  		// The mock PurgeUnused doesn't actually purge anything, so the dir
   841  		// includes both our old and new versions.
   842  		"terraform-provider-exact_v0.0.1_x4",
   843  		"terraform-provider-exact_v1.2.3_x4",
   844  		"terraform-provider-greater_than_v2.3.3_x4",
   845  		"terraform-provider-greater_than_v2.3.4_x4",
   846  	}
   847  
   848  	if !reflect.DeepEqual(gotFilenames, wantFilenames) {
   849  		t.Errorf("wrong directory contents after upgrade\ngot:  %#v\nwant: %#v", gotFilenames, wantFilenames)
   850  	}
   851  
   852  }
   853  
   854  func TestInit_getProviderMissing(t *testing.T) {
   855  	// Create a temporary working directory that is empty
   856  	td := tempDir(t)
   857  	copy.CopyDir(testFixturePath("init-get-providers"), td)
   858  	defer os.RemoveAll(td)
   859  	defer testChdir(t, td)()
   860  
   861  	ui := new(cli.MockUi)
   862  	m := Meta{
   863  		testingOverrides: metaOverridesForProvider(testProvider()),
   864  		Ui:               ui,
   865  	}
   866  
   867  	installer := &mockProviderInstaller{
   868  		Providers: map[string][]string{
   869  			// looking for exact version 1.2.3
   870  			"exact": []string{"1.2.4"},
   871  			// config requires >= 2.3.3
   872  			"greater_than": []string{"2.3.4", "2.3.3", "2.3.0"},
   873  			// config specifies
   874  			"between": []string{"3.4.5", "2.3.4", "1.2.3"},
   875  		},
   876  
   877  		Dir: m.pluginDir(),
   878  	}
   879  
   880  	c := &InitCommand{
   881  		Meta:              m,
   882  		providerInstaller: installer,
   883  	}
   884  
   885  	args := []string{}
   886  	if code := c.Run(args); code == 0 {
   887  		t.Fatalf("expceted error, got output: \n%s", ui.OutputWriter.String())
   888  	}
   889  
   890  	if !strings.Contains(ui.ErrorWriter.String(), "no suitable version for provider") {
   891  		t.Fatalf("unexpected error output: %s", ui.ErrorWriter)
   892  	}
   893  }
   894  
   895  func TestInit_getProviderHaveLegacyVersion(t *testing.T) {
   896  	// Create a temporary working directory that is empty
   897  	td := tempDir(t)
   898  	copy.CopyDir(testFixturePath("init-providers-lock"), td)
   899  	defer os.RemoveAll(td)
   900  	defer testChdir(t, td)()
   901  
   902  	if err := ioutil.WriteFile("terraform-provider-test", []byte("provider bin"), 0755); err != nil {
   903  		t.Fatal(err)
   904  	}
   905  
   906  	// provider test has a version constraint in the config, which should
   907  	// trigger the getProvider error below.
   908  	ui := new(cli.MockUi)
   909  	c := &InitCommand{
   910  		Meta: Meta{
   911  			testingOverrides: metaOverridesForProvider(testProvider()),
   912  			Ui:               ui,
   913  		},
   914  		providerInstaller: callbackPluginInstaller(func(provider string, req discovery.Constraints) (discovery.PluginMeta, error) {
   915  			return discovery.PluginMeta{}, fmt.Errorf("EXPECTED PROVIDER ERROR %s", provider)
   916  		}),
   917  	}
   918  
   919  	args := []string{}
   920  	if code := c.Run(args); code == 0 {
   921  		t.Fatalf("expceted error, got output: \n%s", ui.OutputWriter.String())
   922  	}
   923  
   924  	if !strings.Contains(ui.ErrorWriter.String(), "EXPECTED PROVIDER ERROR test") {
   925  		t.Fatalf("unexpected error output: %s", ui.ErrorWriter)
   926  	}
   927  }
   928  
   929  func TestInit_getProviderCheckRequiredVersion(t *testing.T) {
   930  	// Create a temporary working directory that is empty
   931  	td := tempDir(t)
   932  	copy.CopyDir(testFixturePath("init-check-required-version"), td)
   933  	defer os.RemoveAll(td)
   934  	defer testChdir(t, td)()
   935  
   936  	ui := new(cli.MockUi)
   937  	c := &InitCommand{
   938  		Meta: Meta{
   939  			testingOverrides: metaOverridesForProvider(testProvider()),
   940  			Ui:               ui,
   941  		},
   942  	}
   943  
   944  	args := []string{}
   945  	if code := c.Run(args); code != 1 {
   946  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   947  	}
   948  }
   949  
   950  func TestInit_providerLockFile(t *testing.T) {
   951  	// Create a temporary working directory that is empty
   952  	td := tempDir(t)
   953  	copy.CopyDir(testFixturePath("init-provider-lock-file"), td)
   954  	defer os.RemoveAll(td)
   955  	defer testChdir(t, td)()
   956  
   957  	ui := new(cli.MockUi)
   958  	m := Meta{
   959  		testingOverrides: metaOverridesForProvider(testProvider()),
   960  		Ui:               ui,
   961  	}
   962  
   963  	installer := &mockProviderInstaller{
   964  		Providers: map[string][]string{
   965  			"test": []string{"1.2.3"},
   966  		},
   967  
   968  		Dir: m.pluginDir(),
   969  	}
   970  
   971  	c := &InitCommand{
   972  		Meta:              m,
   973  		providerInstaller: installer,
   974  	}
   975  
   976  	args := []string{}
   977  	if code := c.Run(args); code != 0 {
   978  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   979  	}
   980  
   981  	providersLockFile := fmt.Sprintf(
   982  		".terraform/plugins/%s_%s/lock.json",
   983  		runtime.GOOS, runtime.GOARCH,
   984  	)
   985  	buf, err := ioutil.ReadFile(providersLockFile)
   986  	if err != nil {
   987  		t.Fatalf("failed to read providers lock file %s: %s", providersLockFile, err)
   988  	}
   989  	// The hash in here is for the empty files that mockGetProvider produces
   990  	wantLockFile := strings.TrimSpace(`
   991  {
   992    "test": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
   993  }
   994  `)
   995  	if string(buf) != wantLockFile {
   996  		t.Errorf("wrong provider lock file contents\ngot:  %s\nwant: %s", buf, wantLockFile)
   997  	}
   998  }
   999  
  1000  func TestInit_pluginDirReset(t *testing.T) {
  1001  	td, err := ioutil.TempDir("", "tf")
  1002  	if err != nil {
  1003  		t.Fatal(err)
  1004  	}
  1005  	defer os.RemoveAll(td)
  1006  	defer testChdir(t, td)()
  1007  
  1008  	ui := new(cli.MockUi)
  1009  	c := &InitCommand{
  1010  		Meta: Meta{
  1011  			testingOverrides: metaOverridesForProvider(testProvider()),
  1012  			Ui:               ui,
  1013  		},
  1014  		providerInstaller: &mockProviderInstaller{},
  1015  	}
  1016  
  1017  	// make our vendor paths
  1018  	pluginPath := []string{"a", "b", "c"}
  1019  	for _, p := range pluginPath {
  1020  		if err := os.MkdirAll(p, 0755); err != nil {
  1021  			t.Fatal(err)
  1022  		}
  1023  	}
  1024  
  1025  	// run once and save the -plugin-dir
  1026  	args := []string{"-plugin-dir", "a"}
  1027  	if code := c.Run(args); code != 0 {
  1028  		t.Fatalf("bad: \n%s", ui.ErrorWriter)
  1029  	}
  1030  
  1031  	pluginDirs, err := c.loadPluginPath()
  1032  	if err != nil {
  1033  		t.Fatal(err)
  1034  	}
  1035  
  1036  	if len(pluginDirs) != 1 || pluginDirs[0] != "a" {
  1037  		t.Fatalf(`expected plugin dir ["a"], got %q`, pluginDirs)
  1038  	}
  1039  
  1040  	ui = new(cli.MockUi)
  1041  	c = &InitCommand{
  1042  		Meta: Meta{
  1043  			testingOverrides: metaOverridesForProvider(testProvider()),
  1044  			Ui:               ui,
  1045  		},
  1046  		providerInstaller: &mockProviderInstaller{},
  1047  	}
  1048  
  1049  	// make sure we remove the plugin-dir record
  1050  	args = []string{"-plugin-dir="}
  1051  	if code := c.Run(args); code != 0 {
  1052  		t.Fatalf("bad: \n%s", ui.ErrorWriter)
  1053  	}
  1054  
  1055  	pluginDirs, err = c.loadPluginPath()
  1056  	if err != nil {
  1057  		t.Fatal(err)
  1058  	}
  1059  
  1060  	if len(pluginDirs) != 0 {
  1061  		t.Fatalf("expected no plugin dirs got %q", pluginDirs)
  1062  	}
  1063  }
  1064  
  1065  // Test user-supplied -plugin-dir
  1066  func TestInit_pluginDirProviders(t *testing.T) {
  1067  	td := tempDir(t)
  1068  	copy.CopyDir(testFixturePath("init-get-providers"), td)
  1069  	defer os.RemoveAll(td)
  1070  	defer testChdir(t, td)()
  1071  
  1072  	ui := new(cli.MockUi)
  1073  	m := Meta{
  1074  		testingOverrides: metaOverridesForProvider(testProvider()),
  1075  		Ui:               ui,
  1076  	}
  1077  
  1078  	c := &InitCommand{
  1079  		Meta:              m,
  1080  		providerInstaller: &mockProviderInstaller{},
  1081  	}
  1082  
  1083  	// make our vendor paths
  1084  	pluginPath := []string{"a", "b", "c"}
  1085  	for _, p := range pluginPath {
  1086  		if err := os.MkdirAll(p, 0755); err != nil {
  1087  			t.Fatal(err)
  1088  		}
  1089  	}
  1090  
  1091  	// add some dummy providers in our plugin dirs
  1092  	for i, name := range []string{
  1093  		"terraform-provider-exact_v1.2.3_x4",
  1094  		"terraform-provider-greater_than_v2.3.4_x4",
  1095  		"terraform-provider-between_v2.3.4_x4",
  1096  	} {
  1097  
  1098  		if err := ioutil.WriteFile(filepath.Join(pluginPath[i], name), []byte("test bin"), 0755); err != nil {
  1099  			t.Fatal(err)
  1100  		}
  1101  	}
  1102  
  1103  	args := []string{
  1104  		"-plugin-dir", "a",
  1105  		"-plugin-dir", "b",
  1106  		"-plugin-dir", "c",
  1107  	}
  1108  	if code := c.Run(args); code != 0 {
  1109  		t.Fatalf("bad: \n%s", ui.ErrorWriter)
  1110  	}
  1111  }
  1112  
  1113  // Test user-supplied -plugin-dir doesn't allow auto-install
  1114  func TestInit_pluginDirProvidersDoesNotGet(t *testing.T) {
  1115  	td := tempDir(t)
  1116  	copy.CopyDir(testFixturePath("init-get-providers"), td)
  1117  	defer os.RemoveAll(td)
  1118  	defer testChdir(t, td)()
  1119  
  1120  	ui := new(cli.MockUi)
  1121  	m := Meta{
  1122  		testingOverrides: metaOverridesForProvider(testProvider()),
  1123  		Ui:               ui,
  1124  	}
  1125  
  1126  	c := &InitCommand{
  1127  		Meta: m,
  1128  		providerInstaller: callbackPluginInstaller(func(provider string, req discovery.Constraints) (discovery.PluginMeta, error) {
  1129  			t.Fatalf("plugin installer should not have been called for %q", provider)
  1130  			return discovery.PluginMeta{}, nil
  1131  		}),
  1132  	}
  1133  
  1134  	// make our vendor paths
  1135  	pluginPath := []string{"a", "b"}
  1136  	for _, p := range pluginPath {
  1137  		if err := os.MkdirAll(p, 0755); err != nil {
  1138  			t.Fatal(err)
  1139  		}
  1140  	}
  1141  
  1142  	// add some dummy providers in our plugin dirs
  1143  	for i, name := range []string{
  1144  		"terraform-provider-exact_v1.2.3_x4",
  1145  		"terraform-provider-greater_than_v2.3.4_x4",
  1146  	} {
  1147  
  1148  		if err := ioutil.WriteFile(filepath.Join(pluginPath[i], name), []byte("test bin"), 0755); err != nil {
  1149  			t.Fatal(err)
  1150  		}
  1151  	}
  1152  
  1153  	args := []string{
  1154  		"-plugin-dir", "a",
  1155  		"-plugin-dir", "b",
  1156  	}
  1157  	if code := c.Run(args); code == 0 {
  1158  		// should have been an error
  1159  		t.Fatalf("bad: \n%s", ui.OutputWriter)
  1160  	}
  1161  }
  1162  
  1163  // Verify that plugin-dir doesn't prevent discovery of internal providers
  1164  func TestInit_pluginWithInternal(t *testing.T) {
  1165  	td := tempDir(t)
  1166  	copy.CopyDir(testFixturePath("init-internal"), td)
  1167  	defer os.RemoveAll(td)
  1168  	defer testChdir(t, td)()
  1169  
  1170  	ui := new(cli.MockUi)
  1171  	m := Meta{
  1172  		testingOverrides: metaOverridesForProvider(testProvider()),
  1173  		Ui:               ui,
  1174  	}
  1175  
  1176  	c := &InitCommand{
  1177  		Meta: m,
  1178  	}
  1179  
  1180  	args := []string{"-plugin-dir", "./"}
  1181  	//args := []string{}
  1182  	if code := c.Run(args); code != 0 {
  1183  		t.Fatalf("error: %s", ui.ErrorWriter)
  1184  	}
  1185  }