github.com/aspring/terraform@v0.8.2-0.20161216122603-6a8619a5db2e/terraform/interpolate_test.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "os" 6 "reflect" 7 "sort" 8 "sync" 9 "testing" 10 11 "github.com/davecgh/go-spew/spew" 12 "github.com/hashicorp/hil" 13 "github.com/hashicorp/hil/ast" 14 "github.com/hashicorp/terraform/config" 15 ) 16 17 func TestInterpolater_simpleVar(t *testing.T) { 18 i := &Interpolater{} 19 scope := &InterpolationScope{} 20 testInterpolateErr(t, i, scope, "simple") 21 } 22 23 func TestInterpolater_countIndex(t *testing.T) { 24 i := &Interpolater{} 25 26 scope := &InterpolationScope{ 27 Path: rootModulePath, 28 Resource: &Resource{CountIndex: 42}, 29 } 30 31 testInterpolate(t, i, scope, "count.index", ast.Variable{ 32 Value: 42, 33 Type: ast.TypeInt, 34 }) 35 } 36 37 func TestInterpolater_countIndexInWrongContext(t *testing.T) { 38 i := &Interpolater{} 39 40 scope := &InterpolationScope{ 41 Path: rootModulePath, 42 } 43 44 n := "count.index" 45 46 v, err := config.NewInterpolatedVariable(n) 47 if err != nil { 48 t.Fatalf("err: %s", err) 49 } 50 51 expectedErr := fmt.Errorf("foo: count.index is only valid within resources") 52 53 _, err = i.Values(scope, map[string]config.InterpolatedVariable{ 54 "foo": v, 55 }) 56 57 if !reflect.DeepEqual(expectedErr, err) { 58 t.Fatalf("expected: %#v, got %#v", expectedErr, err) 59 } 60 } 61 62 func TestInterpolater_moduleVariable(t *testing.T) { 63 lock := new(sync.RWMutex) 64 state := &State{ 65 Modules: []*ModuleState{ 66 &ModuleState{ 67 Path: rootModulePath, 68 Resources: map[string]*ResourceState{ 69 "aws_instance.web": &ResourceState{ 70 Type: "aws_instance", 71 Primary: &InstanceState{ 72 ID: "bar", 73 }, 74 }, 75 }, 76 }, 77 &ModuleState{ 78 Path: []string{RootModuleName, "child"}, 79 Outputs: map[string]*OutputState{ 80 "foo": &OutputState{ 81 Type: "string", 82 Value: "bar", 83 }, 84 }, 85 }, 86 }, 87 } 88 89 i := &Interpolater{ 90 State: state, 91 StateLock: lock, 92 } 93 94 scope := &InterpolationScope{ 95 Path: rootModulePath, 96 } 97 98 testInterpolate(t, i, scope, "module.child.foo", ast.Variable{ 99 Value: "bar", 100 Type: ast.TypeString, 101 }) 102 } 103 104 func TestInterpolater_pathCwd(t *testing.T) { 105 i := &Interpolater{} 106 scope := &InterpolationScope{} 107 108 expected, err := os.Getwd() 109 if err != nil { 110 t.Fatalf("err: %s", err) 111 } 112 113 testInterpolate(t, i, scope, "path.cwd", ast.Variable{ 114 Value: expected, 115 Type: ast.TypeString, 116 }) 117 } 118 119 func TestInterpolater_pathModule(t *testing.T) { 120 mod := testModule(t, "interpolate-path-module") 121 i := &Interpolater{ 122 Module: mod, 123 } 124 scope := &InterpolationScope{ 125 Path: []string{RootModuleName, "child"}, 126 } 127 128 path := mod.Child([]string{"child"}).Config().Dir 129 testInterpolate(t, i, scope, "path.module", ast.Variable{ 130 Value: path, 131 Type: ast.TypeString, 132 }) 133 } 134 135 func TestInterpolater_pathRoot(t *testing.T) { 136 mod := testModule(t, "interpolate-path-module") 137 i := &Interpolater{ 138 Module: mod, 139 } 140 scope := &InterpolationScope{ 141 Path: []string{RootModuleName, "child"}, 142 } 143 144 path := mod.Config().Dir 145 testInterpolate(t, i, scope, "path.root", ast.Variable{ 146 Value: path, 147 Type: ast.TypeString, 148 }) 149 } 150 151 func TestInterpolater_resourceVariableMap(t *testing.T) { 152 lock := new(sync.RWMutex) 153 state := &State{ 154 Modules: []*ModuleState{ 155 &ModuleState{ 156 Path: rootModulePath, 157 Resources: map[string]*ResourceState{ 158 "aws_instance.web": &ResourceState{ 159 Type: "aws_instance", 160 Primary: &InstanceState{ 161 ID: "bar", 162 Attributes: map[string]string{ 163 "amap.%": "3", 164 "amap.key1": "value1", 165 "amap.key2": "value2", 166 "amap.key3": "value3", 167 }, 168 }, 169 }, 170 }, 171 }, 172 }, 173 } 174 175 i := &Interpolater{ 176 Module: testModule(t, "interpolate-resource-variable"), 177 State: state, 178 StateLock: lock, 179 } 180 181 scope := &InterpolationScope{ 182 Path: rootModulePath, 183 } 184 185 expected := map[string]interface{}{ 186 "key1": "value1", 187 "key2": "value2", 188 "key3": "value3", 189 } 190 191 testInterpolate(t, i, scope, "aws_instance.web.amap", 192 interfaceToVariableSwallowError(expected)) 193 } 194 195 func TestInterpolater_resourceVariableComplexMap(t *testing.T) { 196 lock := new(sync.RWMutex) 197 state := &State{ 198 Modules: []*ModuleState{ 199 &ModuleState{ 200 Path: rootModulePath, 201 Resources: map[string]*ResourceState{ 202 "aws_instance.web": &ResourceState{ 203 Type: "aws_instance", 204 Primary: &InstanceState{ 205 ID: "bar", 206 Attributes: map[string]string{ 207 "amap.%": "2", 208 "amap.key1.#": "2", 209 "amap.key1.0": "hello", 210 "amap.key1.1": "world", 211 "amap.key2.#": "1", 212 "amap.key2.0": "foo", 213 }, 214 }, 215 }, 216 }, 217 }, 218 }, 219 } 220 221 i := &Interpolater{ 222 Module: testModule(t, "interpolate-resource-variable"), 223 State: state, 224 StateLock: lock, 225 } 226 227 scope := &InterpolationScope{ 228 Path: rootModulePath, 229 } 230 231 expected := map[string]interface{}{ 232 "key1": []interface{}{"hello", "world"}, 233 "key2": []interface{}{"foo"}, 234 } 235 236 testInterpolate(t, i, scope, "aws_instance.web.amap", 237 interfaceToVariableSwallowError(expected)) 238 } 239 240 func TestInterpolater_resourceVariable(t *testing.T) { 241 lock := new(sync.RWMutex) 242 state := &State{ 243 Modules: []*ModuleState{ 244 &ModuleState{ 245 Path: rootModulePath, 246 Resources: map[string]*ResourceState{ 247 "aws_instance.web": &ResourceState{ 248 Type: "aws_instance", 249 Primary: &InstanceState{ 250 ID: "bar", 251 Attributes: map[string]string{ 252 "foo": "bar", 253 }, 254 }, 255 }, 256 }, 257 }, 258 }, 259 } 260 261 i := &Interpolater{ 262 Module: testModule(t, "interpolate-resource-variable"), 263 State: state, 264 StateLock: lock, 265 } 266 267 scope := &InterpolationScope{ 268 Path: rootModulePath, 269 } 270 271 testInterpolate(t, i, scope, "aws_instance.web.foo", ast.Variable{ 272 Value: "bar", 273 Type: ast.TypeString, 274 }) 275 } 276 277 func TestInterpolater_resourceVariableMissingDuringInput(t *testing.T) { 278 // During the input walk, computed resource attributes may be entirely 279 // absent since we've not yet produced diffs that tell us what computed 280 // attributes to expect. In that case, interpolator tolerates it and 281 // indicates the value is computed. 282 283 lock := new(sync.RWMutex) 284 state := &State{ 285 Modules: []*ModuleState{ 286 &ModuleState{ 287 Path: rootModulePath, 288 Resources: map[string]*ResourceState{ 289 // No resources at all yet, because we're still dealing 290 // with input and so the resources haven't been created. 291 }, 292 }, 293 }, 294 } 295 296 { 297 i := &Interpolater{ 298 Operation: walkInput, 299 Module: testModule(t, "interpolate-resource-variable"), 300 State: state, 301 StateLock: lock, 302 } 303 304 scope := &InterpolationScope{ 305 Path: rootModulePath, 306 } 307 308 testInterpolate(t, i, scope, "aws_instance.web.foo", ast.Variable{ 309 Value: config.UnknownVariableValue, 310 Type: ast.TypeUnknown, 311 }) 312 } 313 314 // This doesn't apply during other walks, like plan 315 { 316 i := &Interpolater{ 317 Operation: walkPlan, 318 Module: testModule(t, "interpolate-resource-variable"), 319 State: state, 320 StateLock: lock, 321 } 322 323 scope := &InterpolationScope{ 324 Path: rootModulePath, 325 } 326 327 testInterpolateErr(t, i, scope, "aws_instance.web.foo") 328 } 329 } 330 331 func TestInterpolater_resourceVariableMulti(t *testing.T) { 332 lock := new(sync.RWMutex) 333 state := &State{ 334 Modules: []*ModuleState{ 335 &ModuleState{ 336 Path: rootModulePath, 337 Resources: map[string]*ResourceState{ 338 "aws_instance.web": &ResourceState{ 339 Type: "aws_instance", 340 Primary: &InstanceState{ 341 ID: "bar", 342 Attributes: map[string]string{ 343 "foo": config.UnknownVariableValue, 344 }, 345 }, 346 }, 347 }, 348 }, 349 }, 350 } 351 352 i := &Interpolater{ 353 Module: testModule(t, "interpolate-resource-variable"), 354 State: state, 355 StateLock: lock, 356 } 357 358 scope := &InterpolationScope{ 359 Path: rootModulePath, 360 } 361 362 testInterpolate(t, i, scope, "aws_instance.web.*.foo", ast.Variable{ 363 Value: config.UnknownVariableValue, 364 Type: ast.TypeUnknown, 365 }) 366 } 367 368 // When a splat reference is made to an attribute that is a computed list, 369 // the result should be unknown. 370 func TestInterpolater_resourceVariableMultiList(t *testing.T) { 371 lock := new(sync.RWMutex) 372 state := &State{ 373 Modules: []*ModuleState{ 374 &ModuleState{ 375 Path: rootModulePath, 376 Resources: map[string]*ResourceState{ 377 "aws_instance.web.0": &ResourceState{ 378 Type: "aws_instance", 379 Primary: &InstanceState{ 380 ID: "bar", 381 Attributes: map[string]string{ 382 "ip.#": config.UnknownVariableValue, 383 }, 384 }, 385 }, 386 387 "aws_instance.web.1": &ResourceState{ 388 Type: "aws_instance", 389 Primary: &InstanceState{ 390 ID: "bar", 391 Attributes: map[string]string{ 392 "ip.#": "0", 393 }, 394 }, 395 }, 396 }, 397 }, 398 }, 399 } 400 401 i := &Interpolater{ 402 Module: testModule(t, "interpolate-resource-variable"), 403 State: state, 404 StateLock: lock, 405 } 406 407 scope := &InterpolationScope{ 408 Path: rootModulePath, 409 } 410 411 testInterpolate(t, i, scope, "aws_instance.web.*.ip", ast.Variable{ 412 Value: config.UnknownVariableValue, 413 Type: ast.TypeUnknown, 414 }) 415 } 416 417 func TestInterpolater_resourceVariableMulti_interpolated(t *testing.T) { 418 lock := new(sync.RWMutex) 419 state := &State{ 420 Modules: []*ModuleState{ 421 &ModuleState{ 422 Path: rootModulePath, 423 Resources: map[string]*ResourceState{ 424 "aws_instance.web.0": &ResourceState{ 425 Type: "aws_instance", 426 Primary: &InstanceState{ 427 ID: "a", 428 Attributes: map[string]string{"foo": "a"}, 429 }, 430 }, 431 432 "aws_instance.web.1": &ResourceState{ 433 Type: "aws_instance", 434 Primary: &InstanceState{ 435 ID: "b", 436 Attributes: map[string]string{"foo": "b"}, 437 }, 438 }, 439 }, 440 }, 441 }, 442 } 443 444 i := &Interpolater{ 445 Operation: walkApply, 446 Module: testModule(t, "interpolate-multi-interp"), 447 State: state, 448 StateLock: lock, 449 } 450 451 scope := &InterpolationScope{ 452 Path: rootModulePath, 453 } 454 455 expected := []interface{}{"a", "b"} 456 testInterpolate(t, i, scope, "aws_instance.web.*.foo", 457 interfaceToVariableSwallowError(expected)) 458 } 459 460 func interfaceToVariableSwallowError(input interface{}) ast.Variable { 461 variable, _ := hil.InterfaceToVariable(input) 462 return variable 463 } 464 465 func TestInterpolator_resourceMultiAttributes(t *testing.T) { 466 lock := new(sync.RWMutex) 467 state := &State{ 468 Modules: []*ModuleState{ 469 { 470 Path: rootModulePath, 471 Resources: map[string]*ResourceState{ 472 "aws_route53_zone.yada": { 473 Type: "aws_route53_zone", 474 Dependencies: []string{}, 475 Primary: &InstanceState{ 476 ID: "AAABBBCCCDDDEEE", 477 Attributes: map[string]string{ 478 "name_servers.#": "4", 479 "name_servers.0": "ns-1334.awsdns-38.org", 480 "name_servers.1": "ns-1680.awsdns-18.co.uk", 481 "name_servers.2": "ns-498.awsdns-62.com", 482 "name_servers.3": "ns-601.awsdns-11.net", 483 "listeners.#": "1", 484 "listeners.0": "red", 485 "tags.%": "1", 486 "tags.Name": "reindeer", 487 "nothing.#": "0", 488 }, 489 }, 490 }, 491 }, 492 }, 493 }, 494 } 495 496 i := &Interpolater{ 497 Module: testModule(t, "interpolate-multi-vars"), 498 StateLock: lock, 499 State: state, 500 } 501 502 scope := &InterpolationScope{ 503 Path: rootModulePath, 504 } 505 506 name_servers := []interface{}{ 507 "ns-1334.awsdns-38.org", 508 "ns-1680.awsdns-18.co.uk", 509 "ns-498.awsdns-62.com", 510 "ns-601.awsdns-11.net", 511 } 512 513 // More than 1 element 514 testInterpolate(t, i, scope, "aws_route53_zone.yada.name_servers", 515 interfaceToVariableSwallowError(name_servers)) 516 517 // Exactly 1 element 518 testInterpolate(t, i, scope, "aws_route53_zone.yada.listeners", 519 interfaceToVariableSwallowError([]interface{}{"red"})) 520 521 // Zero elements 522 testInterpolate(t, i, scope, "aws_route53_zone.yada.nothing", 523 interfaceToVariableSwallowError([]interface{}{})) 524 525 // Maps still need to work 526 testInterpolate(t, i, scope, "aws_route53_zone.yada.tags.Name", ast.Variable{ 527 Value: "reindeer", 528 Type: ast.TypeString, 529 }) 530 } 531 532 func TestInterpolator_resourceMultiAttributesWithResourceCount(t *testing.T) { 533 i := getInterpolaterFixture(t) 534 scope := &InterpolationScope{ 535 Path: rootModulePath, 536 } 537 538 name_servers := []interface{}{ 539 "ns-1334.awsdns-38.org", 540 "ns-1680.awsdns-18.co.uk", 541 "ns-498.awsdns-62.com", 542 "ns-601.awsdns-11.net", 543 "ns-000.awsdns-38.org", 544 "ns-444.awsdns-18.co.uk", 545 "ns-999.awsdns-62.com", 546 "ns-666.awsdns-11.net", 547 } 548 549 // More than 1 element 550 testInterpolate(t, i, scope, "aws_route53_zone.terra.0.name_servers", 551 interfaceToVariableSwallowError(name_servers[:4])) 552 553 // More than 1 element in both 554 testInterpolate(t, i, scope, "aws_route53_zone.terra.*.name_servers", 555 interfaceToVariableSwallowError([]interface{}{name_servers[:4], name_servers[4:]})) 556 557 // Exactly 1 element 558 testInterpolate(t, i, scope, "aws_route53_zone.terra.0.listeners", 559 interfaceToVariableSwallowError([]interface{}{"red"})) 560 561 // Exactly 1 element in both 562 testInterpolate(t, i, scope, "aws_route53_zone.terra.*.listeners", 563 interfaceToVariableSwallowError([]interface{}{[]interface{}{"red"}, []interface{}{"blue"}})) 564 565 // Zero elements 566 testInterpolate(t, i, scope, "aws_route53_zone.terra.0.nothing", 567 interfaceToVariableSwallowError([]interface{}{})) 568 569 // Zero + 1 element 570 testInterpolate(t, i, scope, "aws_route53_zone.terra.*.special", 571 interfaceToVariableSwallowError([]interface{}{[]interface{}{"extra"}})) 572 573 // Maps still need to work 574 testInterpolate(t, i, scope, "aws_route53_zone.terra.0.tags.Name", ast.Variable{ 575 Value: "reindeer", 576 Type: ast.TypeString, 577 }) 578 579 // Maps still need to work in both 580 testInterpolate(t, i, scope, "aws_route53_zone.terra.*.tags.Name", 581 interfaceToVariableSwallowError([]interface{}{"reindeer", "white-hart"})) 582 } 583 584 func TestInterpolator_resourceMultiAttributesComputed(t *testing.T) { 585 lock := new(sync.RWMutex) 586 // The state would never be written with an UnknownVariableValue in it, but 587 // it can/does exist that way in memory during the plan phase. 588 state := &State{ 589 Modules: []*ModuleState{ 590 &ModuleState{ 591 Path: rootModulePath, 592 Resources: map[string]*ResourceState{ 593 "aws_route53_zone.yada": &ResourceState{ 594 Type: "aws_route53_zone", 595 Primary: &InstanceState{ 596 ID: "z-abc123", 597 Attributes: map[string]string{ 598 "name_servers.#": config.UnknownVariableValue, 599 }, 600 }, 601 }, 602 }, 603 }, 604 }, 605 } 606 i := &Interpolater{ 607 Module: testModule(t, "interpolate-multi-vars"), 608 StateLock: lock, 609 State: state, 610 } 611 612 scope := &InterpolationScope{ 613 Path: rootModulePath, 614 } 615 616 testInterpolate(t, i, scope, "aws_route53_zone.yada.name_servers", ast.Variable{ 617 Value: config.UnknownVariableValue, 618 Type: ast.TypeUnknown, 619 }) 620 } 621 622 func TestInterpolator_resourceAttributeComputed(t *testing.T) { 623 lock := new(sync.RWMutex) 624 // The state would never be written with an UnknownVariableValue in it, but 625 // it can/does exist that way in memory during the plan phase. 626 state := &State{ 627 Modules: []*ModuleState{ 628 &ModuleState{ 629 Path: rootModulePath, 630 Resources: map[string]*ResourceState{ 631 "aws_route53_zone.yada": &ResourceState{ 632 Type: "aws_route53_zone", 633 Primary: &InstanceState{ 634 ID: "z-abc123", 635 Attributes: map[string]string{ 636 "id": config.UnknownVariableValue, 637 }, 638 }, 639 }, 640 }, 641 }, 642 }, 643 } 644 i := &Interpolater{ 645 Module: testModule(t, "interpolate-multi-vars"), 646 StateLock: lock, 647 State: state, 648 } 649 650 scope := &InterpolationScope{ 651 Path: rootModulePath, 652 } 653 654 testInterpolate(t, i, scope, "aws_route53_zone.yada.id", ast.Variable{ 655 Value: config.UnknownVariableValue, 656 Type: ast.TypeUnknown, 657 }) 658 } 659 660 func TestInterpolater_selfVarWithoutResource(t *testing.T) { 661 i := &Interpolater{} 662 663 scope := &InterpolationScope{ 664 Path: rootModulePath, 665 } 666 667 v, err := config.NewInterpolatedVariable("self.name") 668 if err != nil { 669 t.Fatalf("err: %s", err) 670 } 671 672 _, err = i.Values(scope, map[string]config.InterpolatedVariable{"foo": v}) 673 if err == nil { 674 t.Fatalf("expected err, got none") 675 } 676 } 677 678 // Verify sorting by key index number 679 func TestInterpolator_indexKeySort(t *testing.T) { 680 keys := []string{"a.1", "a.2", "a.10", "a.20", "a.3"} 681 sorted := []string{"a.1", "a.2", "a.3", "a.10", "a.20"} 682 683 sort.Sort(indexKeys(keys)) 684 for i := range keys { 685 if keys[i] != sorted[i] { 686 t.Fatalf("indexes out of order\nexpected: %q\ngot: %q", sorted, keys) 687 } 688 } 689 } 690 691 func TestInterpolator_interpolatedListOrder(t *testing.T) { 692 state := &State{ 693 Modules: []*ModuleState{ 694 &ModuleState{ 695 Path: rootModulePath, 696 Resources: map[string]*ResourceState{ 697 "aws_route53_zone.list": &ResourceState{ 698 Type: "aws_route53_zone", 699 Dependencies: []string{}, 700 Primary: &InstanceState{ 701 ID: "null", 702 Attributes: map[string]string{ 703 "foo.#": "12", 704 "foo.0": "a", 705 "foo.1": "b", 706 "foo.2": "c", 707 "foo.3": "d", 708 "foo.4": "e", 709 "foo.5": "f", 710 "foo.6": "g", 711 "foo.7": "h", 712 "foo.8": "i", 713 "foo.9": "j", 714 "foo.10": "k", 715 "foo.11": "l", 716 }, 717 }, 718 }, 719 }, 720 }, 721 }, 722 } 723 724 i := &Interpolater{ 725 Module: testModule(t, "interpolate-multi-vars"), 726 StateLock: new(sync.RWMutex), 727 State: state, 728 } 729 730 scope := &InterpolationScope{ 731 Path: rootModulePath, 732 } 733 734 list := []interface{}{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"} 735 736 testInterpolate(t, i, scope, "aws_route53_zone.list.foo", 737 interfaceToVariableSwallowError(list)) 738 } 739 740 func getInterpolaterFixture(t *testing.T) *Interpolater { 741 lock := new(sync.RWMutex) 742 state := &State{ 743 Modules: []*ModuleState{ 744 &ModuleState{ 745 Path: rootModulePath, 746 Resources: map[string]*ResourceState{ 747 "aws_route53_zone.terra.0": &ResourceState{ 748 Type: "aws_route53_zone", 749 Dependencies: []string{}, 750 Primary: &InstanceState{ 751 ID: "AAABBBCCCDDDEEE", 752 Attributes: map[string]string{ 753 "name_servers.#": "4", 754 "name_servers.0": "ns-1334.awsdns-38.org", 755 "name_servers.1": "ns-1680.awsdns-18.co.uk", 756 "name_servers.2": "ns-498.awsdns-62.com", 757 "name_servers.3": "ns-601.awsdns-11.net", 758 "listeners.#": "1", 759 "listeners.0": "red", 760 "tags.%": "1", 761 "tags.Name": "reindeer", 762 "nothing.#": "0", 763 }, 764 }, 765 }, 766 "aws_route53_zone.terra.1": &ResourceState{ 767 Type: "aws_route53_zone", 768 Dependencies: []string{}, 769 Primary: &InstanceState{ 770 ID: "EEEFFFGGGHHHIII", 771 Attributes: map[string]string{ 772 "name_servers.#": "4", 773 "name_servers.0": "ns-000.awsdns-38.org", 774 "name_servers.1": "ns-444.awsdns-18.co.uk", 775 "name_servers.2": "ns-999.awsdns-62.com", 776 "name_servers.3": "ns-666.awsdns-11.net", 777 "listeners.#": "1", 778 "listeners.0": "blue", 779 "special.#": "1", 780 "special.0": "extra", 781 "tags.%": "1", 782 "tags.Name": "white-hart", 783 "nothing.#": "0", 784 }, 785 }, 786 }, 787 }, 788 }, 789 }, 790 } 791 792 return &Interpolater{ 793 Module: testModule(t, "interpolate-multi-vars"), 794 StateLock: lock, 795 State: state, 796 } 797 } 798 799 func testInterpolate( 800 t *testing.T, i *Interpolater, 801 scope *InterpolationScope, 802 n string, expectedVar ast.Variable) { 803 v, err := config.NewInterpolatedVariable(n) 804 if err != nil { 805 t.Fatalf("err: %s", err) 806 } 807 808 actual, err := i.Values(scope, map[string]config.InterpolatedVariable{ 809 "foo": v, 810 }) 811 if err != nil { 812 t.Fatalf("err: %s", err) 813 } 814 815 expected := map[string]ast.Variable{ 816 "foo": expectedVar, 817 } 818 if !reflect.DeepEqual(actual, expected) { 819 spew.Config.DisableMethods = true 820 t.Fatalf("%q:\n\n actual: %#v\nexpected: %#v\n\n%s\n\n%s\n\n", n, actual, expected, 821 spew.Sdump(actual), spew.Sdump(expected)) 822 } 823 } 824 825 func testInterpolateErr( 826 t *testing.T, i *Interpolater, 827 scope *InterpolationScope, 828 n string) { 829 v, err := config.NewInterpolatedVariable(n) 830 if err != nil { 831 t.Fatalf("err: %s", err) 832 } 833 834 _, err = i.Values(scope, map[string]config.InterpolatedVariable{ 835 "foo": v, 836 }) 837 if err == nil { 838 t.Fatalf("%q: succeeded, but wanted error", n) 839 } 840 }