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 }