github.com/medzin/terraform@v0.11.11/config/raw_config_test.go (about) 1 package config 2 3 import ( 4 "encoding/gob" 5 "reflect" 6 "testing" 7 8 hcl2 "github.com/hashicorp/hcl2/hcl" 9 "github.com/hashicorp/hil/ast" 10 ) 11 12 func TestNewRawConfig(t *testing.T) { 13 raw := map[string]interface{}{ 14 "foo": "${var.bar}", 15 "bar": `${file("boom.txt")}`, 16 } 17 18 rc, err := NewRawConfig(raw) 19 if err != nil { 20 t.Fatalf("err: %s", err) 21 } 22 23 if len(rc.Interpolations) != 2 { 24 t.Fatalf("bad: %#v", rc.Interpolations) 25 } 26 if len(rc.Variables) != 1 { 27 t.Fatalf("bad: %#v", rc.Variables) 28 } 29 } 30 31 func TestRawConfig_basic(t *testing.T) { 32 raw := map[string]interface{}{ 33 "foo": "${var.bar}", 34 } 35 36 rc, err := NewRawConfig(raw) 37 if err != nil { 38 t.Fatalf("err: %s", err) 39 } 40 41 // Before interpolate, Config() should be the raw 42 if !reflect.DeepEqual(rc.Config(), raw) { 43 t.Fatalf("bad: %#v", rc.Config()) 44 } 45 46 vars := map[string]ast.Variable{ 47 "var.bar": ast.Variable{ 48 Value: "baz", 49 Type: ast.TypeString, 50 }, 51 } 52 if err := rc.Interpolate(vars); err != nil { 53 t.Fatalf("err: %s", err) 54 } 55 56 actual := rc.Config() 57 expected := map[string]interface{}{ 58 "foo": "baz", 59 } 60 61 if !reflect.DeepEqual(actual, expected) { 62 t.Fatalf("bad: %#v", actual) 63 } 64 if len(rc.UnknownKeys()) != 0 { 65 t.Fatalf("bad: %#v", rc.UnknownKeys()) 66 } 67 } 68 69 func TestRawConfig_double(t *testing.T) { 70 raw := map[string]interface{}{ 71 "foo": "${var.bar}", 72 } 73 74 rc, err := NewRawConfig(raw) 75 if err != nil { 76 t.Fatalf("err: %s", err) 77 } 78 79 vars := map[string]ast.Variable{ 80 "var.bar": ast.Variable{ 81 Value: "baz", 82 Type: ast.TypeString, 83 }, 84 } 85 if err := rc.Interpolate(vars); err != nil { 86 t.Fatalf("err: %s", err) 87 } 88 89 actual := rc.Config() 90 expected := map[string]interface{}{ 91 "foo": "baz", 92 } 93 94 if !reflect.DeepEqual(actual, expected) { 95 t.Fatalf("bad: %#v", actual) 96 } 97 98 vars = map[string]ast.Variable{ 99 "var.bar": ast.Variable{ 100 Value: "what", 101 Type: ast.TypeString, 102 }, 103 } 104 if err := rc.Interpolate(vars); err != nil { 105 t.Fatalf("err: %s", err) 106 } 107 108 actual = rc.Config() 109 expected = map[string]interface{}{ 110 "foo": "what", 111 } 112 113 if !reflect.DeepEqual(actual, expected) { 114 t.Fatalf("bad: %#v", actual) 115 } 116 } 117 118 func TestRawConfigInterpolate_escaped(t *testing.T) { 119 raw := map[string]interface{}{ 120 "foo": "bar-$${baz}", 121 } 122 123 rc, err := NewRawConfig(raw) 124 if err != nil { 125 t.Fatalf("err: %s", err) 126 } 127 128 // Before interpolate, Config() should be the raw 129 if !reflect.DeepEqual(rc.Config(), raw) { 130 t.Fatalf("bad: %#v", rc.Config()) 131 } 132 133 if err := rc.Interpolate(nil); err != nil { 134 t.Fatalf("err: %s", err) 135 } 136 137 actual := rc.Config() 138 expected := map[string]interface{}{ 139 "foo": "bar-${baz}", 140 } 141 142 if !reflect.DeepEqual(actual, expected) { 143 t.Fatalf("bad: %#v", actual) 144 } 145 if len(rc.UnknownKeys()) != 0 { 146 t.Fatalf("bad: %#v", rc.UnknownKeys()) 147 } 148 } 149 150 func TestRawConfig_merge(t *testing.T) { 151 raw1 := map[string]interface{}{ 152 "foo": "${var.foo}", 153 "bar": "${var.bar}", 154 } 155 156 rc1, err := NewRawConfig(raw1) 157 if err != nil { 158 t.Fatalf("err: %s", err) 159 } 160 161 { 162 vars := map[string]ast.Variable{ 163 "var.foo": ast.Variable{ 164 Value: "foovalue", 165 Type: ast.TypeString, 166 }, 167 "var.bar": ast.Variable{ 168 Value: "nope", 169 Type: ast.TypeString, 170 }, 171 } 172 if err := rc1.Interpolate(vars); err != nil { 173 t.Fatalf("err: %s", err) 174 } 175 } 176 177 raw2 := map[string]interface{}{ 178 "bar": "${var.bar}", 179 "baz": "${var.baz}", 180 } 181 182 rc2, err := NewRawConfig(raw2) 183 if err != nil { 184 t.Fatalf("err: %s", err) 185 } 186 187 { 188 vars := map[string]ast.Variable{ 189 "var.bar": ast.Variable{ 190 Value: "barvalue", 191 Type: ast.TypeString, 192 }, 193 "var.baz": ast.Variable{ 194 Value: UnknownVariableValue, 195 Type: ast.TypeUnknown, 196 }, 197 } 198 if err := rc2.Interpolate(vars); err != nil { 199 t.Fatalf("err: %s", err) 200 } 201 } 202 203 // Merge the two 204 rc3 := rc1.Merge(rc2) 205 206 // Raw should be merged 207 raw3 := map[string]interface{}{ 208 "foo": "${var.foo}", 209 "bar": "${var.bar}", 210 "baz": "${var.baz}", 211 } 212 if !reflect.DeepEqual(rc3.Raw, raw3) { 213 t.Fatalf("bad: %#v", rc3.Raw) 214 } 215 216 actual := rc3.Config() 217 expected := map[string]interface{}{ 218 "foo": "foovalue", 219 "bar": "barvalue", 220 "baz": UnknownVariableValue, 221 } 222 if !reflect.DeepEqual(actual, expected) { 223 t.Fatalf("bad: %#v", actual) 224 } 225 226 expectedKeys := []string{"baz"} 227 if !reflect.DeepEqual(rc3.UnknownKeys(), expectedKeys) { 228 t.Fatalf("bad: %#v", rc3.UnknownKeys()) 229 } 230 } 231 232 func TestRawConfig_syntax(t *testing.T) { 233 raw := map[string]interface{}{ 234 "foo": "${var", 235 } 236 237 if _, err := NewRawConfig(raw); err == nil { 238 t.Fatal("should error") 239 } 240 } 241 242 func TestRawConfig_unknown(t *testing.T) { 243 raw := map[string]interface{}{ 244 "foo": "${var.bar}", 245 } 246 247 rc, err := NewRawConfig(raw) 248 if err != nil { 249 t.Fatalf("err: %s", err) 250 } 251 252 vars := map[string]ast.Variable{ 253 "var.bar": ast.Variable{ 254 Value: UnknownVariableValue, 255 Type: ast.TypeUnknown, 256 }, 257 } 258 if err := rc.Interpolate(vars); err != nil { 259 t.Fatalf("err: %s", err) 260 } 261 262 actual := rc.Config() 263 expected := map[string]interface{}{"foo": UnknownVariableValue} 264 265 if !reflect.DeepEqual(actual, expected) { 266 t.Fatalf("bad: %#v", actual) 267 } 268 269 expectedKeys := []string{"foo"} 270 if !reflect.DeepEqual(rc.UnknownKeys(), expectedKeys) { 271 t.Fatalf("bad: %#v", rc.UnknownKeys()) 272 } 273 } 274 275 func TestRawConfig_unknownPartial(t *testing.T) { 276 raw := map[string]interface{}{ 277 "foo": "${var.bar}/32", 278 } 279 280 rc, err := NewRawConfig(raw) 281 if err != nil { 282 t.Fatalf("err: %s", err) 283 } 284 285 vars := map[string]ast.Variable{ 286 "var.bar": ast.Variable{ 287 Value: UnknownVariableValue, 288 Type: ast.TypeUnknown, 289 }, 290 } 291 if err := rc.Interpolate(vars); err != nil { 292 t.Fatalf("err: %s", err) 293 } 294 295 actual := rc.Config() 296 expected := map[string]interface{}{"foo": UnknownVariableValue} 297 298 if !reflect.DeepEqual(actual, expected) { 299 t.Fatalf("bad: %#v", actual) 300 } 301 302 expectedKeys := []string{"foo"} 303 if !reflect.DeepEqual(rc.UnknownKeys(), expectedKeys) { 304 t.Fatalf("bad: %#v", rc.UnknownKeys()) 305 } 306 } 307 308 func TestRawConfig_unknownPartialList(t *testing.T) { 309 raw := map[string]interface{}{ 310 "foo": []interface{}{ 311 "${var.bar}/32", 312 }, 313 } 314 315 rc, err := NewRawConfig(raw) 316 if err != nil { 317 t.Fatalf("err: %s", err) 318 } 319 320 vars := map[string]ast.Variable{ 321 "var.bar": ast.Variable{ 322 Value: UnknownVariableValue, 323 Type: ast.TypeUnknown, 324 }, 325 } 326 if err := rc.Interpolate(vars); err != nil { 327 t.Fatalf("err: %s", err) 328 } 329 330 actual := rc.Config() 331 expected := map[string]interface{}{"foo": []interface{}{UnknownVariableValue}} 332 333 if !reflect.DeepEqual(actual, expected) { 334 t.Fatalf("bad: %#v", actual) 335 } 336 337 expectedKeys := []string{"foo"} 338 if !reflect.DeepEqual(rc.UnknownKeys(), expectedKeys) { 339 t.Fatalf("bad: %#v", rc.UnknownKeys()) 340 } 341 } 342 343 // This tests a race found where we were not maintaining the "slice index" 344 // accounting properly. The result would be that some computed keys would 345 // look like they had no slice index when they in fact do. This test is not 346 // very reliable but it did fail before the fix and passed after. 347 func TestRawConfig_sliceIndexLoss(t *testing.T) { 348 raw := map[string]interface{}{ 349 "slice": []map[string]interface{}{ 350 map[string]interface{}{ 351 "foo": []interface{}{"foo/${var.unknown}"}, 352 "bar": []interface{}{"bar"}, 353 }, 354 }, 355 } 356 357 vars := map[string]ast.Variable{ 358 "var.unknown": ast.Variable{ 359 Value: UnknownVariableValue, 360 Type: ast.TypeUnknown, 361 }, 362 "var.known": ast.Variable{ 363 Value: "123456", 364 Type: ast.TypeString, 365 }, 366 } 367 368 // We run it a lot because its fast and we try to get a race out 369 for i := 0; i < 50; i++ { 370 rc, err := NewRawConfig(raw) 371 if err != nil { 372 t.Fatalf("err: %s", err) 373 } 374 375 if err := rc.Interpolate(vars); err != nil { 376 t.Fatalf("err: %s", err) 377 } 378 379 expectedKeys := []string{"slice.0.foo"} 380 if !reflect.DeepEqual(rc.UnknownKeys(), expectedKeys) { 381 t.Fatalf("bad: %#v", rc.UnknownKeys()) 382 } 383 } 384 } 385 386 func TestRawConfigCopy(t *testing.T) { 387 raw := map[string]interface{}{ 388 "foo": "${var.bar}", 389 } 390 391 rc, err := NewRawConfig(raw) 392 if err != nil { 393 t.Fatalf("err: %s", err) 394 } 395 396 rc.Key = "foo" 397 if rc.Value() != "${var.bar}" { 398 t.Fatalf("err: %#v", rc.Value()) 399 } 400 401 // Interpolate the first one 402 vars := map[string]ast.Variable{ 403 "var.bar": ast.Variable{ 404 Value: "baz", 405 Type: ast.TypeString, 406 }, 407 } 408 if err := rc.Interpolate(vars); err != nil { 409 t.Fatalf("err: %s", err) 410 } 411 412 if rc.Value() != "baz" { 413 t.Fatalf("bad: %#v", rc.Value()) 414 } 415 416 // Copy and interpolate 417 { 418 rc2 := rc.Copy() 419 if rc2.Value() != "${var.bar}" { 420 t.Fatalf("err: %#v", rc2.Value()) 421 } 422 423 vars := map[string]ast.Variable{ 424 "var.bar": ast.Variable{ 425 Value: "qux", 426 Type: ast.TypeString, 427 }, 428 } 429 if err := rc2.Interpolate(vars); err != nil { 430 t.Fatalf("err: %s", err) 431 } 432 433 if rc2.Value() != "qux" { 434 t.Fatalf("bad: %#v", rc2.Value()) 435 } 436 } 437 } 438 439 func TestRawConfigCopyHCL2(t *testing.T) { 440 rc := NewRawConfigHCL2(hcl2.EmptyBody()) 441 rc2 := rc.Copy() 442 443 if rc.Body == nil { 444 t.Errorf("RawConfig copy has a nil Body") 445 } 446 if rc2.Raw != nil { 447 t.Errorf("RawConfig copy got a non-nil Raw") 448 } 449 } 450 451 func TestRawConfigValue(t *testing.T) { 452 raw := map[string]interface{}{ 453 "foo": "${var.bar}", 454 } 455 456 rc, err := NewRawConfig(raw) 457 if err != nil { 458 t.Fatalf("err: %s", err) 459 } 460 461 rc.Key = "" 462 if rc.Value() != nil { 463 t.Fatalf("bad: %#v", rc.Value()) 464 } 465 466 rc.Key = "foo" 467 if rc.Value() != "${var.bar}" { 468 t.Fatalf("err: %#v", rc.Value()) 469 } 470 471 vars := map[string]ast.Variable{ 472 "var.bar": ast.Variable{ 473 Value: "baz", 474 Type: ast.TypeString, 475 }, 476 } 477 if err := rc.Interpolate(vars); err != nil { 478 t.Fatalf("err: %s", err) 479 } 480 481 if rc.Value() != "baz" { 482 t.Fatalf("bad: %#v", rc.Value()) 483 } 484 } 485 486 func TestRawConfig_implGob(t *testing.T) { 487 var _ gob.GobDecoder = new(RawConfig) 488 var _ gob.GobEncoder = new(RawConfig) 489 } 490 491 // verify that RawMap returns a identical copy 492 func TestNewRawConfig_rawMap(t *testing.T) { 493 raw := map[string]interface{}{ 494 "foo": "${var.bar}", 495 "bar": `${file("boom.txt")}`, 496 } 497 498 rc, err := NewRawConfig(raw) 499 if err != nil { 500 t.Fatalf("err: %s", err) 501 } 502 503 rawCopy := rc.RawMap() 504 if !reflect.DeepEqual(raw, rawCopy) { 505 t.Fatalf("bad: %#v", rawCopy) 506 } 507 508 // make sure they aren't the same map 509 raw["test"] = "value" 510 if reflect.DeepEqual(raw, rawCopy) { 511 t.Fatal("RawMap() didn't return a copy") 512 } 513 }