github.com/tomaszheflik/terraform@v0.7.3-0.20160827060421-32f990b41594/terraform/context_input_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"sync"
     7  	"testing"
     8  )
     9  
    10  func TestContext2Input(t *testing.T) {
    11  	input := new(MockUIInput)
    12  	m := testModule(t, "input-vars")
    13  	p := testProvider("aws")
    14  	p.ApplyFn = testApplyFn
    15  	p.DiffFn = testDiffFn
    16  	ctx := testContext2(t, &ContextOpts{
    17  		Module: m,
    18  		Providers: map[string]ResourceProviderFactory{
    19  			"aws": testProviderFuncFixed(p),
    20  		},
    21  		Variables: map[string]interface{}{
    22  			"foo": "us-west-2",
    23  			"amis": []map[string]interface{}{
    24  				map[string]interface{}{
    25  					"us-east-1": "override",
    26  				},
    27  			},
    28  		},
    29  		UIInput: input,
    30  	})
    31  
    32  	input.InputReturnMap = map[string]string{
    33  		"var.foo": "us-east-1",
    34  	}
    35  
    36  	if err := ctx.Input(InputModeStd); err != nil {
    37  		t.Fatalf("err: %s", err)
    38  	}
    39  
    40  	if _, err := ctx.Plan(); err != nil {
    41  		t.Fatalf("err: %s", err)
    42  	}
    43  
    44  	state, err := ctx.Apply()
    45  	if err != nil {
    46  		t.Fatalf("err: %s", err)
    47  	}
    48  
    49  	actual := strings.TrimSpace(state.String())
    50  	expected := strings.TrimSpace(testTerraformInputVarsStr)
    51  	if actual != expected {
    52  		t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual)
    53  	}
    54  }
    55  
    56  func TestContext2Input_moduleComputedOutputElement(t *testing.T) {
    57  	m := testModule(t, "input-module-computed-output-element")
    58  	p := testProvider("aws")
    59  	p.ApplyFn = testApplyFn
    60  	p.DiffFn = testDiffFn
    61  	ctx := testContext2(t, &ContextOpts{
    62  		Module: m,
    63  		Providers: map[string]ResourceProviderFactory{
    64  			"aws": testProviderFuncFixed(p),
    65  		},
    66  	})
    67  
    68  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
    69  		return c, nil
    70  	}
    71  
    72  	if err := ctx.Input(InputModeStd); err != nil {
    73  		t.Fatalf("err: %s", err)
    74  	}
    75  }
    76  
    77  func TestContext2Input_badVarDefault(t *testing.T) {
    78  	m := testModule(t, "input-bad-var-default")
    79  	p := testProvider("aws")
    80  	p.ApplyFn = testApplyFn
    81  	p.DiffFn = testDiffFn
    82  	ctx := testContext2(t, &ContextOpts{
    83  		Module: m,
    84  		Providers: map[string]ResourceProviderFactory{
    85  			"aws": testProviderFuncFixed(p),
    86  		},
    87  	})
    88  
    89  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
    90  		c.Config["foo"] = "bar"
    91  		return c, nil
    92  	}
    93  
    94  	if err := ctx.Input(InputModeStd); err != nil {
    95  		t.Fatalf("err: %s", err)
    96  	}
    97  }
    98  
    99  func TestContext2Input_provider(t *testing.T) {
   100  	m := testModule(t, "input-provider")
   101  	p := testProvider("aws")
   102  	p.ApplyFn = testApplyFn
   103  	p.DiffFn = testDiffFn
   104  	ctx := testContext2(t, &ContextOpts{
   105  		Module: m,
   106  		Providers: map[string]ResourceProviderFactory{
   107  			"aws": testProviderFuncFixed(p),
   108  		},
   109  	})
   110  
   111  	var actual interface{}
   112  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   113  		c.Config["foo"] = "bar"
   114  		return c, nil
   115  	}
   116  	p.ConfigureFn = func(c *ResourceConfig) error {
   117  		actual = c.Config["foo"]
   118  		return nil
   119  	}
   120  	p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
   121  		return nil, c.CheckSet([]string{"foo"})
   122  	}
   123  
   124  	if err := ctx.Input(InputModeStd); err != nil {
   125  		t.Fatalf("err: %s", err)
   126  	}
   127  
   128  	if _, err := ctx.Plan(); err != nil {
   129  		t.Fatalf("err: %s", err)
   130  	}
   131  
   132  	if _, err := ctx.Apply(); err != nil {
   133  		t.Fatalf("err: %s", err)
   134  	}
   135  
   136  	if !reflect.DeepEqual(actual, "bar") {
   137  		t.Fatalf("bad: %#v", actual)
   138  	}
   139  }
   140  
   141  func TestContext2Input_providerMulti(t *testing.T) {
   142  	m := testModule(t, "input-provider-multi")
   143  	p := testProvider("aws")
   144  	p.ApplyFn = testApplyFn
   145  	p.DiffFn = testDiffFn
   146  	ctx := testContext2(t, &ContextOpts{
   147  		Module: m,
   148  		Providers: map[string]ResourceProviderFactory{
   149  			"aws": testProviderFuncFixed(p),
   150  		},
   151  	})
   152  
   153  	var actual []interface{}
   154  	var lock sync.Mutex
   155  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   156  		c.Config["foo"] = "bar"
   157  		return c, nil
   158  	}
   159  	p.ConfigureFn = func(c *ResourceConfig) error {
   160  		lock.Lock()
   161  		defer lock.Unlock()
   162  		actual = append(actual, c.Config["foo"])
   163  		return nil
   164  	}
   165  	p.ValidateFn = func(c *ResourceConfig) ([]string, []error) {
   166  		return nil, c.CheckSet([]string{"foo"})
   167  	}
   168  
   169  	if err := ctx.Input(InputModeStd); err != nil {
   170  		t.Fatalf("err: %s", err)
   171  	}
   172  
   173  	if _, err := ctx.Plan(); err != nil {
   174  		t.Fatalf("err: %s", err)
   175  	}
   176  
   177  	if _, err := ctx.Apply(); err != nil {
   178  		t.Fatalf("err: %s", err)
   179  	}
   180  
   181  	expected := []interface{}{"bar", "bar"}
   182  	if !reflect.DeepEqual(actual, expected) {
   183  		t.Fatalf("bad: %#v", actual)
   184  	}
   185  }
   186  
   187  func TestContext2Input_providerOnce(t *testing.T) {
   188  	m := testModule(t, "input-provider-once")
   189  	p := testProvider("aws")
   190  	p.ApplyFn = testApplyFn
   191  	p.DiffFn = testDiffFn
   192  	ctx := testContext2(t, &ContextOpts{
   193  		Module: m,
   194  		Providers: map[string]ResourceProviderFactory{
   195  			"aws": testProviderFuncFixed(p),
   196  		},
   197  	})
   198  
   199  	count := 0
   200  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   201  		count++
   202  		return nil, nil
   203  	}
   204  
   205  	if err := ctx.Input(InputModeStd); err != nil {
   206  		t.Fatalf("err: %s", err)
   207  	}
   208  
   209  	if count != 1 {
   210  		t.Fatalf("should only be called once: %d", count)
   211  	}
   212  }
   213  
   214  func TestContext2Input_providerId(t *testing.T) {
   215  	input := new(MockUIInput)
   216  	m := testModule(t, "input-provider")
   217  	p := testProvider("aws")
   218  	p.ApplyFn = testApplyFn
   219  	p.DiffFn = testDiffFn
   220  	ctx := testContext2(t, &ContextOpts{
   221  		Module: m,
   222  		Providers: map[string]ResourceProviderFactory{
   223  			"aws": testProviderFuncFixed(p),
   224  		},
   225  		UIInput: input,
   226  	})
   227  
   228  	var actual interface{}
   229  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   230  		v, err := i.Input(&InputOpts{Id: "foo"})
   231  		if err != nil {
   232  			return nil, err
   233  		}
   234  
   235  		c.Config["foo"] = v
   236  		return c, nil
   237  	}
   238  	p.ConfigureFn = func(c *ResourceConfig) error {
   239  		actual = c.Config["foo"]
   240  		return nil
   241  	}
   242  
   243  	input.InputReturnMap = map[string]string{
   244  		"provider.aws.foo": "bar",
   245  	}
   246  
   247  	if err := ctx.Input(InputModeStd); err != nil {
   248  		t.Fatalf("err: %s", err)
   249  	}
   250  
   251  	if _, err := ctx.Plan(); err != nil {
   252  		t.Fatalf("err: %s", err)
   253  	}
   254  
   255  	if _, err := ctx.Apply(); err != nil {
   256  		t.Fatalf("err: %s", err)
   257  	}
   258  
   259  	if !reflect.DeepEqual(actual, "bar") {
   260  		t.Fatalf("bad: %#v", actual)
   261  	}
   262  }
   263  
   264  func TestContext2Input_providerOnly(t *testing.T) {
   265  	input := new(MockUIInput)
   266  	m := testModule(t, "input-provider-vars")
   267  	p := testProvider("aws")
   268  	p.ApplyFn = testApplyFn
   269  	p.DiffFn = testDiffFn
   270  	ctx := testContext2(t, &ContextOpts{
   271  		Module: m,
   272  		Providers: map[string]ResourceProviderFactory{
   273  			"aws": testProviderFuncFixed(p),
   274  		},
   275  		Variables: map[string]interface{}{
   276  			"foo": "us-west-2",
   277  		},
   278  		UIInput: input,
   279  	})
   280  
   281  	input.InputReturnMap = map[string]string{
   282  		"var.foo": "us-east-1",
   283  	}
   284  
   285  	var actual interface{}
   286  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   287  		c.Config["foo"] = "bar"
   288  		return c, nil
   289  	}
   290  	p.ConfigureFn = func(c *ResourceConfig) error {
   291  		actual = c.Config["foo"]
   292  		return nil
   293  	}
   294  
   295  	if err := ctx.Input(InputModeProvider); err != nil {
   296  		t.Fatalf("err: %s", err)
   297  	}
   298  
   299  	if _, err := ctx.Plan(); err != nil {
   300  		t.Fatalf("err: %s", err)
   301  	}
   302  
   303  	state, err := ctx.Apply()
   304  	if err != nil {
   305  		t.Fatalf("err: %s", err)
   306  	}
   307  
   308  	if !reflect.DeepEqual(actual, "bar") {
   309  		t.Fatalf("bad: %#v", actual)
   310  	}
   311  
   312  	actualStr := strings.TrimSpace(state.String())
   313  	expectedStr := strings.TrimSpace(testTerraformInputProviderOnlyStr)
   314  	if actualStr != expectedStr {
   315  		t.Fatalf("bad: \n%s", actualStr)
   316  	}
   317  }
   318  
   319  func TestContext2Input_providerVars(t *testing.T) {
   320  	input := new(MockUIInput)
   321  	m := testModule(t, "input-provider-with-vars")
   322  	p := testProvider("aws")
   323  	p.ApplyFn = testApplyFn
   324  	p.DiffFn = testDiffFn
   325  	ctx := testContext2(t, &ContextOpts{
   326  		Module: m,
   327  		Providers: map[string]ResourceProviderFactory{
   328  			"aws": testProviderFuncFixed(p),
   329  		},
   330  		Variables: map[string]interface{}{
   331  			"foo": "bar",
   332  		},
   333  		UIInput: input,
   334  	})
   335  
   336  	input.InputReturnMap = map[string]string{
   337  		"var.foo": "bar",
   338  	}
   339  
   340  	var actual interface{}
   341  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   342  		c.Config["bar"] = "baz"
   343  		return c, nil
   344  	}
   345  	p.ConfigureFn = func(c *ResourceConfig) error {
   346  		actual, _ = c.Get("foo")
   347  		return nil
   348  	}
   349  
   350  	if err := ctx.Input(InputModeStd); err != nil {
   351  		t.Fatalf("err: %s", err)
   352  	}
   353  
   354  	if _, err := ctx.Plan(); err != nil {
   355  		t.Fatalf("err: %s", err)
   356  	}
   357  
   358  	if _, err := ctx.Apply(); err != nil {
   359  		t.Fatalf("err: %s", err)
   360  	}
   361  
   362  	if !reflect.DeepEqual(actual, "bar") {
   363  		t.Fatalf("bad: %#v", actual)
   364  	}
   365  }
   366  
   367  func TestContext2Input_providerVarsModuleInherit(t *testing.T) {
   368  	input := new(MockUIInput)
   369  	m := testModule(t, "input-provider-with-vars-and-module")
   370  	p := testProvider("aws")
   371  	p.ApplyFn = testApplyFn
   372  	p.DiffFn = testDiffFn
   373  	ctx := testContext2(t, &ContextOpts{
   374  		Module: m,
   375  		Providers: map[string]ResourceProviderFactory{
   376  			"aws": testProviderFuncFixed(p),
   377  		},
   378  		UIInput: input,
   379  	})
   380  
   381  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   382  		if errs := c.CheckSet([]string{"access_key"}); len(errs) > 0 {
   383  			return c, errs[0]
   384  		}
   385  		return c, nil
   386  	}
   387  	p.ConfigureFn = func(c *ResourceConfig) error {
   388  		return nil
   389  	}
   390  
   391  	if err := ctx.Input(InputModeStd); err != nil {
   392  		t.Fatalf("err: %s", err)
   393  	}
   394  }
   395  
   396  func TestContext2Input_varOnly(t *testing.T) {
   397  	input := new(MockUIInput)
   398  	m := testModule(t, "input-provider-vars")
   399  	p := testProvider("aws")
   400  	p.ApplyFn = testApplyFn
   401  	p.DiffFn = testDiffFn
   402  	ctx := testContext2(t, &ContextOpts{
   403  		Module: m,
   404  		Providers: map[string]ResourceProviderFactory{
   405  			"aws": testProviderFuncFixed(p),
   406  		},
   407  		Variables: map[string]interface{}{
   408  			"foo": "us-west-2",
   409  		},
   410  		UIInput: input,
   411  	})
   412  
   413  	input.InputReturnMap = map[string]string{
   414  		"var.foo": "us-east-1",
   415  	}
   416  
   417  	var actual interface{}
   418  	p.InputFn = func(i UIInput, c *ResourceConfig) (*ResourceConfig, error) {
   419  		c.Raw["foo"] = "bar"
   420  		return c, nil
   421  	}
   422  	p.ConfigureFn = func(c *ResourceConfig) error {
   423  		actual = c.Raw["foo"]
   424  		return nil
   425  	}
   426  
   427  	if err := ctx.Input(InputModeVar); err != nil {
   428  		t.Fatalf("err: %s", err)
   429  	}
   430  
   431  	if _, err := ctx.Plan(); err != nil {
   432  		t.Fatalf("err: %s", err)
   433  	}
   434  
   435  	state, err := ctx.Apply()
   436  	if err != nil {
   437  		t.Fatalf("err: %s", err)
   438  	}
   439  
   440  	if reflect.DeepEqual(actual, "bar") {
   441  		t.Fatalf("bad: %#v", actual)
   442  	}
   443  
   444  	actualStr := strings.TrimSpace(state.String())
   445  	expectedStr := strings.TrimSpace(testTerraformInputVarOnlyStr)
   446  	if actualStr != expectedStr {
   447  		t.Fatalf("bad: \n%s", actualStr)
   448  	}
   449  }
   450  
   451  func TestContext2Input_varOnlyUnset(t *testing.T) {
   452  	input := new(MockUIInput)
   453  	m := testModule(t, "input-vars-unset")
   454  	p := testProvider("aws")
   455  	p.ApplyFn = testApplyFn
   456  	p.DiffFn = testDiffFn
   457  	ctx := testContext2(t, &ContextOpts{
   458  		Module: m,
   459  		Providers: map[string]ResourceProviderFactory{
   460  			"aws": testProviderFuncFixed(p),
   461  		},
   462  		Variables: map[string]interface{}{
   463  			"foo": "foovalue",
   464  		},
   465  		UIInput: input,
   466  	})
   467  
   468  	input.InputReturnMap = map[string]string{
   469  		"var.foo": "nope",
   470  		"var.bar": "baz",
   471  	}
   472  
   473  	if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil {
   474  		t.Fatalf("err: %s", err)
   475  	}
   476  
   477  	if _, err := ctx.Plan(); err != nil {
   478  		t.Fatalf("err: %s", err)
   479  	}
   480  
   481  	state, err := ctx.Apply()
   482  	if err != nil {
   483  		t.Fatalf("err: %s", err)
   484  	}
   485  
   486  	actualStr := strings.TrimSpace(state.String())
   487  	expectedStr := strings.TrimSpace(testTerraformInputVarOnlyUnsetStr)
   488  	if actualStr != expectedStr {
   489  		t.Fatalf("bad: \n%s", actualStr)
   490  	}
   491  }
   492  
   493  func TestContext2Input_varWithDefault(t *testing.T) {
   494  	input := new(MockUIInput)
   495  	m := testModule(t, "input-var-default")
   496  	p := testProvider("aws")
   497  	p.ApplyFn = testApplyFn
   498  	p.DiffFn = testDiffFn
   499  	ctx := testContext2(t, &ContextOpts{
   500  		Module: m,
   501  		Providers: map[string]ResourceProviderFactory{
   502  			"aws": testProviderFuncFixed(p),
   503  		},
   504  		Variables: map[string]interface{}{},
   505  		UIInput:   input,
   506  	})
   507  
   508  	input.InputFn = func(opts *InputOpts) (string, error) {
   509  		t.Fatalf(
   510  			"Input should never be called because variable has a default: %#v", opts)
   511  		return "", nil
   512  	}
   513  
   514  	if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil {
   515  		t.Fatalf("err: %s", err)
   516  	}
   517  
   518  	if _, err := ctx.Plan(); err != nil {
   519  		t.Fatalf("err: %s", err)
   520  	}
   521  
   522  	state, err := ctx.Apply()
   523  	if err != nil {
   524  		t.Fatalf("err: %s", err)
   525  	}
   526  
   527  	actualStr := strings.TrimSpace(state.String())
   528  	expectedStr := strings.TrimSpace(`
   529  aws_instance.foo:
   530    ID = foo
   531    foo = 123
   532    type = aws_instance
   533  	`)
   534  	if actualStr != expectedStr {
   535  		t.Fatalf("expected: \n%s\ngot: \n%s\n", expectedStr, actualStr)
   536  	}
   537  }
   538  
   539  func TestContext2Input_varPartiallyComputed(t *testing.T) {
   540  	input := new(MockUIInput)
   541  	m := testModule(t, "input-var-partially-computed")
   542  	p := testProvider("aws")
   543  	p.ApplyFn = testApplyFn
   544  	p.DiffFn = testDiffFn
   545  	ctx := testContext2(t, &ContextOpts{
   546  		Module: m,
   547  		Providers: map[string]ResourceProviderFactory{
   548  			"aws": testProviderFuncFixed(p),
   549  		},
   550  		Variables: map[string]interface{}{
   551  			"foo": "foovalue",
   552  		},
   553  		UIInput: input,
   554  		State: &State{
   555  			Modules: []*ModuleState{
   556  				&ModuleState{
   557  					Path: rootModulePath,
   558  					Resources: map[string]*ResourceState{
   559  						"aws_instance.foo": &ResourceState{
   560  							Type: "aws_instance",
   561  							Primary: &InstanceState{
   562  								ID: "i-abc123",
   563  								Attributes: map[string]string{
   564  									"id": "i-abc123",
   565  								},
   566  							},
   567  						},
   568  					},
   569  				},
   570  				&ModuleState{
   571  					Path: append(rootModulePath, "child"),
   572  					Resources: map[string]*ResourceState{
   573  						"aws_instance.mod": &ResourceState{
   574  							Type: "aws_instance",
   575  							Primary: &InstanceState{
   576  								ID: "i-bcd345",
   577  								Attributes: map[string]string{
   578  									"id":    "i-bcd345",
   579  									"value": "one,i-abc123",
   580  								},
   581  							},
   582  						},
   583  					},
   584  				},
   585  			},
   586  		},
   587  	})
   588  
   589  	if err := ctx.Input(InputModeStd); err != nil {
   590  		t.Fatalf("err: %s", err)
   591  	}
   592  
   593  	if _, err := ctx.Plan(); err != nil {
   594  		t.Fatalf("err: %s", err)
   595  	}
   596  }
   597  
   598  // Module variables weren't being interpolated during the Input walk.
   599  // https://github.com/hashicorp/terraform/issues/5322
   600  func TestContext2Input_interpolateVar(t *testing.T) {
   601  	input := new(MockUIInput)
   602  
   603  	m := testModule(t, "input-interpolate-var")
   604  	p := testProvider("null")
   605  	p.ApplyFn = testApplyFn
   606  	p.DiffFn = testDiffFn
   607  
   608  	ctx := testContext2(t, &ContextOpts{
   609  		Module: m,
   610  		Providers: map[string]ResourceProviderFactory{
   611  			"template": testProviderFuncFixed(p),
   612  		},
   613  		UIInput: input,
   614  	})
   615  
   616  	if err := ctx.Input(InputModeStd); err != nil {
   617  		t.Fatalf("err: %s", err)
   618  	}
   619  }
   620  
   621  func TestContext2Input_hcl(t *testing.T) {
   622  	input := new(MockUIInput)
   623  	m := testModule(t, "input-hcl")
   624  	p := testProvider("hcl")
   625  	p.ApplyFn = testApplyFn
   626  	p.DiffFn = testDiffFn
   627  	ctx := testContext2(t, &ContextOpts{
   628  		Module: m,
   629  		Providers: map[string]ResourceProviderFactory{
   630  			"hcl": testProviderFuncFixed(p),
   631  		},
   632  		Variables: map[string]interface{}{},
   633  		UIInput:   input,
   634  	})
   635  
   636  	input.InputReturnMap = map[string]string{
   637  		"var.listed": `["a", "b"]`,
   638  		"var.mapped": `{x = "y", w = "z"}`,
   639  	}
   640  
   641  	if err := ctx.Input(InputModeVar | InputModeVarUnset); err != nil {
   642  		t.Fatalf("err: %s", err)
   643  	}
   644  
   645  	if _, err := ctx.Plan(); err != nil {
   646  		t.Fatalf("err: %s", err)
   647  	}
   648  
   649  	state, err := ctx.Apply()
   650  	if err != nil {
   651  		t.Fatalf("err: %s", err)
   652  	}
   653  
   654  	actualStr := strings.TrimSpace(state.String())
   655  	expectedStr := strings.TrimSpace(testTerraformInputHCL)
   656  	if actualStr != expectedStr {
   657  		t.Logf("expected: \n%s", expectedStr)
   658  		t.Fatalf("bad: \n%s", actualStr)
   659  	}
   660  }