github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/terraform/variables_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/davecgh/go-spew/spew"
     7  	"github.com/muratcelep/terraform/not-internal/tfdiags"
     8  
     9  	"github.com/go-test/deep"
    10  	"github.com/zclconf/go-cty/cty"
    11  )
    12  
    13  func TestVariables(t *testing.T) {
    14  	tests := map[string]struct {
    15  		Module   string
    16  		Override map[string]cty.Value
    17  		Want     InputValues
    18  	}{
    19  		"config only": {
    20  			"vars-basic",
    21  			nil,
    22  			InputValues{
    23  				"a": &InputValue{
    24  					Value:      cty.StringVal("foo"),
    25  					SourceType: ValueFromConfig,
    26  					SourceRange: tfdiags.SourceRange{
    27  						Filename: "testdata/vars-basic/main.tf",
    28  						Start:    tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0},
    29  						End:      tfdiags.SourcePos{Line: 1, Column: 13, Byte: 12},
    30  					},
    31  				},
    32  				"b": &InputValue{
    33  					Value:      cty.ListValEmpty(cty.String),
    34  					SourceType: ValueFromConfig,
    35  					SourceRange: tfdiags.SourceRange{
    36  						Filename: "testdata/vars-basic/main.tf",
    37  						Start:    tfdiags.SourcePos{Line: 6, Column: 1, Byte: 55},
    38  						End:      tfdiags.SourcePos{Line: 6, Column: 13, Byte: 67},
    39  					},
    40  				},
    41  				"c": &InputValue{
    42  					Value:      cty.MapValEmpty(cty.String),
    43  					SourceType: ValueFromConfig,
    44  					SourceRange: tfdiags.SourceRange{
    45  						Filename: "testdata/vars-basic/main.tf",
    46  						Start:    tfdiags.SourcePos{Line: 11, Column: 1, Byte: 113},
    47  						End:      tfdiags.SourcePos{Line: 11, Column: 13, Byte: 125},
    48  					},
    49  				},
    50  			},
    51  		},
    52  
    53  		"override": {
    54  			"vars-basic",
    55  			map[string]cty.Value{
    56  				"a": cty.StringVal("bar"),
    57  				"b": cty.ListVal([]cty.Value{
    58  					cty.StringVal("foo"),
    59  					cty.StringVal("bar"),
    60  				}),
    61  				"c": cty.MapVal(map[string]cty.Value{
    62  					"foo": cty.StringVal("bar"),
    63  				}),
    64  			},
    65  			InputValues{
    66  				"a": &InputValue{
    67  					Value:      cty.StringVal("bar"),
    68  					SourceType: ValueFromCaller,
    69  				},
    70  				"b": &InputValue{
    71  					Value: cty.ListVal([]cty.Value{
    72  						cty.StringVal("foo"),
    73  						cty.StringVal("bar"),
    74  					}),
    75  					SourceType: ValueFromCaller,
    76  				},
    77  				"c": &InputValue{
    78  					Value: cty.MapVal(map[string]cty.Value{
    79  						"foo": cty.StringVal("bar"),
    80  					}),
    81  					SourceType: ValueFromCaller,
    82  				},
    83  			},
    84  		},
    85  
    86  		"bools: config only": {
    87  			"vars-basic-bool",
    88  			nil,
    89  			InputValues{
    90  				"a": &InputValue{
    91  					Value:      cty.True,
    92  					SourceType: ValueFromConfig,
    93  					SourceRange: tfdiags.SourceRange{
    94  						Filename: "testdata/vars-basic-bool/main.tf",
    95  						Start:    tfdiags.SourcePos{Line: 4, Column: 1, Byte: 177},
    96  						End:      tfdiags.SourcePos{Line: 4, Column: 13, Byte: 189},
    97  					},
    98  				},
    99  				"b": &InputValue{
   100  					Value:      cty.False,
   101  					SourceType: ValueFromConfig,
   102  					SourceRange: tfdiags.SourceRange{
   103  						Filename: "testdata/vars-basic-bool/main.tf",
   104  						Start:    tfdiags.SourcePos{Line: 8, Column: 1, Byte: 214},
   105  						End:      tfdiags.SourcePos{Line: 8, Column: 13, Byte: 226},
   106  					},
   107  				},
   108  			},
   109  		},
   110  
   111  		"bools: override with string": {
   112  			"vars-basic-bool",
   113  			map[string]cty.Value{
   114  				"a": cty.StringVal("foo"),
   115  				"b": cty.StringVal("bar"),
   116  			},
   117  			InputValues{
   118  				"a": &InputValue{
   119  					Value:      cty.StringVal("foo"),
   120  					SourceType: ValueFromCaller,
   121  				},
   122  				"b": &InputValue{
   123  					Value:      cty.StringVal("bar"),
   124  					SourceType: ValueFromCaller,
   125  				},
   126  			},
   127  		},
   128  
   129  		"bools: override with bool": {
   130  			"vars-basic-bool",
   131  			map[string]cty.Value{
   132  				"a": cty.False,
   133  				"b": cty.True,
   134  			},
   135  			InputValues{
   136  				"a": &InputValue{
   137  					Value:      cty.False,
   138  					SourceType: ValueFromCaller,
   139  				},
   140  				"b": &InputValue{
   141  					Value:      cty.True,
   142  					SourceType: ValueFromCaller,
   143  				},
   144  			},
   145  		},
   146  	}
   147  
   148  	for name, test := range tests {
   149  		// Wrapped in a func so we can get defers to work
   150  		t.Run(name, func(t *testing.T) {
   151  			m := testModule(t, test.Module)
   152  			fromConfig := DefaultVariableValues(m.Module.Variables)
   153  			overrides := InputValuesFromCaller(test.Override)
   154  			got := fromConfig.Override(overrides)
   155  
   156  			if !got.Identical(test.Want) {
   157  				t.Errorf("wrong result\ngot: %swant: %s", spew.Sdump(got), spew.Sdump(test.Want))
   158  			}
   159  			for _, problem := range deep.Equal(got, test.Want) {
   160  				t.Errorf(problem)
   161  			}
   162  		})
   163  	}
   164  }
   165  
   166  func TestCheckInputVariables(t *testing.T) {
   167  	c := testModule(t, "input-variables")
   168  
   169  	t.Run("No variables set", func(t *testing.T) {
   170  		// No variables set
   171  		diags := checkInputVariables(c.Module.Variables, nil)
   172  		if !diags.HasErrors() {
   173  			t.Fatal("check succeeded, but want errors")
   174  		}
   175  
   176  		// Required variables set, optional variables unset
   177  		// This is still an error at this layer, since it's the caller's
   178  		// responsibility to have already merged in any default values.
   179  		diags = checkInputVariables(c.Module.Variables, InputValues{
   180  			"foo": &InputValue{
   181  				Value:      cty.StringVal("bar"),
   182  				SourceType: ValueFromCLIArg,
   183  			},
   184  		})
   185  		if !diags.HasErrors() {
   186  			t.Fatal("check succeeded, but want errors")
   187  		}
   188  	})
   189  
   190  	t.Run("All variables set", func(t *testing.T) {
   191  		diags := checkInputVariables(c.Module.Variables, InputValues{
   192  			"foo": &InputValue{
   193  				Value:      cty.StringVal("bar"),
   194  				SourceType: ValueFromCLIArg,
   195  			},
   196  			"bar": &InputValue{
   197  				Value:      cty.StringVal("baz"),
   198  				SourceType: ValueFromCLIArg,
   199  			},
   200  			"map": &InputValue{
   201  				Value:      cty.StringVal("baz"), // okay because config has no type constraint
   202  				SourceType: ValueFromCLIArg,
   203  			},
   204  			"object_map": &InputValue{
   205  				Value: cty.MapVal(map[string]cty.Value{
   206  					"uno": cty.ObjectVal(map[string]cty.Value{
   207  						"foo": cty.StringVal("baz"),
   208  						"bar": cty.NumberIntVal(2), // type = any
   209  					}),
   210  					"dos": cty.ObjectVal(map[string]cty.Value{
   211  						"foo": cty.StringVal("bat"),
   212  						"bar": cty.NumberIntVal(99), // type = any
   213  					}),
   214  				}),
   215  				SourceType: ValueFromCLIArg,
   216  			},
   217  			"object_list": &InputValue{
   218  				Value: cty.ListVal([]cty.Value{
   219  					cty.ObjectVal(map[string]cty.Value{
   220  						"foo": cty.StringVal("baz"),
   221  						"bar": cty.NumberIntVal(2), // type = any
   222  					}),
   223  					cty.ObjectVal(map[string]cty.Value{
   224  						"foo": cty.StringVal("bang"),
   225  						"bar": cty.NumberIntVal(42), // type = any
   226  					}),
   227  				}),
   228  				SourceType: ValueFromCLIArg,
   229  			},
   230  		})
   231  		if diags.HasErrors() {
   232  			t.Fatalf("unexpected errors: %s", diags.Err())
   233  		}
   234  	})
   235  
   236  	t.Run("Invalid Complex Types", func(t *testing.T) {
   237  		diags := checkInputVariables(c.Module.Variables, InputValues{
   238  			"foo": &InputValue{
   239  				Value:      cty.StringVal("bar"),
   240  				SourceType: ValueFromCLIArg,
   241  			},
   242  			"bar": &InputValue{
   243  				Value:      cty.StringVal("baz"),
   244  				SourceType: ValueFromCLIArg,
   245  			},
   246  			"map": &InputValue{
   247  				Value:      cty.StringVal("baz"), // okay because config has no type constraint
   248  				SourceType: ValueFromCLIArg,
   249  			},
   250  			"object_map": &InputValue{
   251  				Value: cty.MapVal(map[string]cty.Value{
   252  					"uno": cty.ObjectVal(map[string]cty.Value{
   253  						"foo": cty.StringVal("baz"),
   254  						"bar": cty.NumberIntVal(2), // type = any
   255  					}),
   256  					"dos": cty.ObjectVal(map[string]cty.Value{
   257  						"foo": cty.StringVal("bat"),
   258  						"bar": cty.NumberIntVal(99), // type = any
   259  					}),
   260  				}),
   261  				SourceType: ValueFromCLIArg,
   262  			},
   263  			"object_list": &InputValue{
   264  				Value: cty.TupleVal([]cty.Value{
   265  					cty.ObjectVal(map[string]cty.Value{
   266  						"foo": cty.StringVal("baz"),
   267  						"bar": cty.NumberIntVal(2), // type = any
   268  					}),
   269  					cty.ObjectVal(map[string]cty.Value{
   270  						"foo": cty.StringVal("bang"),
   271  						"bar": cty.StringVal("42"), // type = any, but mismatch with the first list item
   272  					}),
   273  				}),
   274  				SourceType: ValueFromCLIArg,
   275  			},
   276  		})
   277  
   278  		if diags.HasErrors() {
   279  			t.Fatalf("unexpected errors: %s", diags.Err())
   280  		}
   281  	})
   282  }