88 "testing"
99
1010 "github.com/davecgh/go-spew/spew"
11+ "github.com/hashicorp/hcl/v2/hcltest"
1112 "github.com/zclconf/go-cty/cty"
1213
1314 "github.com/hashicorp/terraform/internal/addrs"
@@ -568,7 +569,7 @@ func TestEvaluatorGetResource_changes(t *testing.T) {
568569}
569570
570571func TestEvaluatorGetModule (t * testing.T ) {
571- evaluator := evaluatorForModule (states .NewState ().SyncWrapper (), plans .NewChanges ().SyncWrapper ())
572+ evaluator := evaluatorForModule (states .NewState ().SyncWrapper (), plans .NewChanges ().SyncWrapper (), nil , nil )
572573 evaluator .Instances .SetModuleSingle (addrs .RootModuleInstance , addrs.ModuleCall {Name : "mod" })
573574 evaluator .NamedValues .SetOutputValue (
574575 addrs.OutputValue {Name : "out" }.Absolute (addrs.ModuleInstance {addrs.ModuleInstanceStep {Name : "mod" }}),
@@ -593,29 +594,320 @@ func TestEvaluatorGetModule(t *testing.T) {
593594 }
594595}
595596
596- func evaluatorForModule (stateSync * states.SyncState , changesSync * plans.ChangesSync ) * Evaluator {
597+ func TestEvaluatorGetModule_validateTypedOutputs (t * testing.T ) {
598+ tests := map [string ]struct {
599+ configureModuleCall func (* configs.ModuleCall )
600+ want cty.Value
601+ }{
602+ "single" : {
603+ want : cty .ObjectVal (map [string ]cty.Value {
604+ "out" : cty .UnknownVal (cty .String ),
605+ }),
606+ },
607+ "count" : {
608+ configureModuleCall : func (call * configs.ModuleCall ) {
609+ call .Count = hcltest .MockExprLiteral (cty .NumberIntVal (1 ))
610+ },
611+ want : cty .UnknownVal (cty .List (cty .Object (map [string ]cty.Type {
612+ "out" : cty .String ,
613+ }))),
614+ },
615+ "for_each" : {
616+ configureModuleCall : func (call * configs.ModuleCall ) {
617+ call .ForEach = hcltest .MockExprLiteral (cty .MapVal (map [string ]cty.Value {
618+ "a" : cty .StringVal ("a" ),
619+ }))
620+ },
621+ want : cty .UnknownVal (cty .Map (cty .Object (map [string ]cty.Type {
622+ "out" : cty .String ,
623+ }))),
624+ },
625+ }
626+
627+ for name , test := range tests {
628+ t .Run (name , func (t * testing.T ) {
629+ evaluator := evaluatorForModule (states .NewState ().SyncWrapper (), plans .NewChanges ().SyncWrapper (), func (out * configs.Output ) {
630+ out .ConstraintType = cty .String
631+ out .TypeSet = true
632+ }, test .configureModuleCall )
633+
634+ data := & evaluationStateData {
635+ evaluationData : & evaluationData {
636+ Evaluator : evaluator ,
637+ },
638+ Operation : walkValidate ,
639+ }
640+ scope := evaluator .Scope (data , nil , nil , lang.ExternalFuncs {})
641+
642+ got , diags := scope .Data .GetModule (addrs.ModuleCall {
643+ Name : "mod" ,
644+ }, tfdiags.SourceRange {})
645+
646+ if len (diags ) != 0 {
647+ t .Errorf ("unexpected diagnostics %s" , spew .Sdump (diags ))
648+ }
649+ if ! got .RawEquals (test .want ) {
650+ t .Errorf ("wrong result\n got: %#v\n want: %#v" , got , test .want )
651+ }
652+ })
653+ }
654+ }
655+
656+ func TestEvaluatorGetModule_validateTypedOutputsWithDynamicTypes (t * testing.T ) {
657+ tests := map [string ]struct {
658+ configureModuleCall func (* configs.ModuleCall )
659+ }{
660+ "count" : {
661+ configureModuleCall : func (call * configs.ModuleCall ) {
662+ call .Count = hcltest .MockExprLiteral (cty .NumberIntVal (1 ))
663+ },
664+ },
665+ "for_each" : {
666+ configureModuleCall : func (call * configs.ModuleCall ) {
667+ call .ForEach = hcltest .MockExprLiteral (cty .MapVal (map [string ]cty.Value {
668+ "a" : cty .StringVal ("a" ),
669+ }))
670+ },
671+ },
672+ }
673+
674+ for name , test := range tests {
675+ t .Run (name , func (t * testing.T ) {
676+ evaluator := evaluatorForModule (states .NewState ().SyncWrapper (), plans .NewChanges ().SyncWrapper (), func (out * configs.Output ) {
677+ out .ConstraintType = cty .DynamicPseudoType
678+ out .TypeSet = true
679+ }, test .configureModuleCall )
680+
681+ data := & evaluationStateData {
682+ evaluationData : & evaluationData {
683+ Evaluator : evaluator ,
684+ },
685+ Operation : walkValidate ,
686+ }
687+ scope := evaluator .Scope (data , nil , nil , lang.ExternalFuncs {})
688+
689+ got , diags := scope .Data .GetModule (addrs.ModuleCall {
690+ Name : "mod" ,
691+ }, tfdiags.SourceRange {})
692+
693+ if len (diags ) != 0 {
694+ t .Errorf ("unexpected diagnostics %s" , spew .Sdump (diags ))
695+ }
696+ if ! got .RawEquals (cty .DynamicVal ) {
697+ t .Errorf ("wrong result\n got: %#v\n want: %#v" , got , cty .DynamicVal )
698+ }
699+ })
700+ }
701+ }
702+
703+ func TestEvaluatorGetModule_planTypedOutputs (t * testing.T ) {
704+ tests := map [string ]struct {
705+ setupInstances func (* instances.Expander )
706+ setupOutputs func (* namedvals.State )
707+ want cty.Value
708+ }{
709+ "count" : {
710+ setupInstances : func (expander * instances.Expander ) {
711+ expander .SetModuleCount (addrs .RootModuleInstance , addrs.ModuleCall {Name : "mod" }, 2 )
712+ },
713+ setupOutputs : func (namedValues * namedvals.State ) {
714+ namedValues .SetOutputValue (
715+ addrs.OutputValue {Name : "out" }.Absolute (addrs.ModuleInstance {
716+ addrs.ModuleInstanceStep {Name : "mod" , InstanceKey : addrs .IntKey (0 )},
717+ }),
718+ cty .StringVal ("first" ).Mark (marks .Sensitive ),
719+ )
720+ namedValues .SetOutputValue (
721+ addrs.OutputValue {Name : "out" }.Absolute (addrs.ModuleInstance {
722+ addrs.ModuleInstanceStep {Name : "mod" , InstanceKey : addrs .IntKey (1 )},
723+ }),
724+ cty .StringVal ("second" ).Mark (marks .Sensitive ),
725+ )
726+ },
727+ want : cty .ListVal ([]cty.Value {
728+ cty .ObjectVal (map [string ]cty.Value {"out" : cty .StringVal ("first" ).Mark (marks .Sensitive )}),
729+ cty .ObjectVal (map [string ]cty.Value {"out" : cty .StringVal ("second" ).Mark (marks .Sensitive )}),
730+ }),
731+ },
732+ "for_each" : {
733+ setupInstances : func (expander * instances.Expander ) {
734+ expander .SetModuleForEach (addrs .RootModuleInstance , addrs.ModuleCall {Name : "mod" }, map [string ]cty.Value {
735+ "a" : cty .StringVal ("a" ),
736+ "b" : cty .StringVal ("b" ),
737+ })
738+ },
739+ setupOutputs : func (namedValues * namedvals.State ) {
740+ namedValues .SetOutputValue (
741+ addrs.OutputValue {Name : "out" }.Absolute (addrs.ModuleInstance {
742+ addrs.ModuleInstanceStep {Name : "mod" , InstanceKey : addrs .StringKey ("a" )},
743+ }),
744+ cty .StringVal ("first" ).Mark (marks .Sensitive ),
745+ )
746+ namedValues .SetOutputValue (
747+ addrs.OutputValue {Name : "out" }.Absolute (addrs.ModuleInstance {
748+ addrs.ModuleInstanceStep {Name : "mod" , InstanceKey : addrs .StringKey ("b" )},
749+ }),
750+ cty .StringVal ("second" ).Mark (marks .Sensitive ),
751+ )
752+ },
753+ want : cty .MapVal (map [string ]cty.Value {
754+ "a" : cty .ObjectVal (map [string ]cty.Value {"out" : cty .StringVal ("first" ).Mark (marks .Sensitive )}),
755+ "b" : cty .ObjectVal (map [string ]cty.Value {"out" : cty .StringVal ("second" ).Mark (marks .Sensitive )}),
756+ }),
757+ },
758+ }
759+
760+ for name , test := range tests {
761+ t .Run (name , func (t * testing.T ) {
762+ evaluator := evaluatorForModule (states .NewState ().SyncWrapper (), plans .NewChanges ().SyncWrapper (), func (out * configs.Output ) {
763+ out .ConstraintType = cty .String
764+ out .TypeSet = true
765+ }, nil )
766+
767+ test .setupInstances (evaluator .Instances )
768+ test .setupOutputs (evaluator .NamedValues )
769+
770+ data := & evaluationStateData {
771+ evaluationData : & evaluationData {
772+ Evaluator : evaluator ,
773+ },
774+ Operation : walkPlan ,
775+ }
776+ scope := evaluator .Scope (data , nil , nil , lang.ExternalFuncs {})
777+
778+ got , diags := scope .Data .GetModule (addrs.ModuleCall {
779+ Name : "mod" ,
780+ }, tfdiags.SourceRange {})
781+
782+ if len (diags ) != 0 {
783+ t .Errorf ("unexpected diagnostics %s" , spew .Sdump (diags ))
784+ }
785+ if ! got .RawEquals (test .want ) {
786+ t .Errorf ("wrong result\n got: %#v\n want: %#v" , got , test .want )
787+ }
788+ })
789+ }
790+ }
791+
792+ func TestEvaluatorGetModule_planUntypedOutputsRemainStructural (t * testing.T ) {
793+ tests := map [string ]struct {
794+ setupInstances func (* instances.Expander )
795+ setupOutputs func (* namedvals.State )
796+ want cty.Value
797+ }{
798+ "count" : {
799+ setupInstances : func (expander * instances.Expander ) {
800+ expander .SetModuleCount (addrs .RootModuleInstance , addrs.ModuleCall {Name : "mod" }, 2 )
801+ },
802+ setupOutputs : func (namedValues * namedvals.State ) {
803+ namedValues .SetOutputValue (
804+ addrs.OutputValue {Name : "out" }.Absolute (addrs.ModuleInstance {
805+ addrs.ModuleInstanceStep {Name : "mod" , InstanceKey : addrs .IntKey (0 )},
806+ }),
807+ cty .StringVal ("first" ).Mark (marks .Sensitive ),
808+ )
809+ namedValues .SetOutputValue (
810+ addrs.OutputValue {Name : "out" }.Absolute (addrs.ModuleInstance {
811+ addrs.ModuleInstanceStep {Name : "mod" , InstanceKey : addrs .IntKey (1 )},
812+ }),
813+ cty .StringVal ("second" ).Mark (marks .Sensitive ),
814+ )
815+ },
816+ want : cty .TupleVal ([]cty.Value {
817+ cty .ObjectVal (map [string ]cty.Value {"out" : cty .StringVal ("first" ).Mark (marks .Sensitive )}),
818+ cty .ObjectVal (map [string ]cty.Value {"out" : cty .StringVal ("second" ).Mark (marks .Sensitive )}),
819+ }),
820+ },
821+ "for_each" : {
822+ setupInstances : func (expander * instances.Expander ) {
823+ expander .SetModuleForEach (addrs .RootModuleInstance , addrs.ModuleCall {Name : "mod" }, map [string ]cty.Value {
824+ "a" : cty .StringVal ("a" ),
825+ "b" : cty .StringVal ("b" ),
826+ })
827+ },
828+ setupOutputs : func (namedValues * namedvals.State ) {
829+ namedValues .SetOutputValue (
830+ addrs.OutputValue {Name : "out" }.Absolute (addrs.ModuleInstance {
831+ addrs.ModuleInstanceStep {Name : "mod" , InstanceKey : addrs .StringKey ("a" )},
832+ }),
833+ cty .StringVal ("first" ).Mark (marks .Sensitive ),
834+ )
835+ namedValues .SetOutputValue (
836+ addrs.OutputValue {Name : "out" }.Absolute (addrs.ModuleInstance {
837+ addrs.ModuleInstanceStep {Name : "mod" , InstanceKey : addrs .StringKey ("b" )},
838+ }),
839+ cty .StringVal ("second" ).Mark (marks .Sensitive ),
840+ )
841+ },
842+ want : cty .ObjectVal (map [string ]cty.Value {
843+ "a" : cty .ObjectVal (map [string ]cty.Value {"out" : cty .StringVal ("first" ).Mark (marks .Sensitive )}),
844+ "b" : cty .ObjectVal (map [string ]cty.Value {"out" : cty .StringVal ("second" ).Mark (marks .Sensitive )}),
845+ }),
846+ },
847+ }
848+
849+ for name , test := range tests {
850+ t .Run (name , func (t * testing.T ) {
851+ evaluator := evaluatorForModule (states .NewState ().SyncWrapper (), plans .NewChanges ().SyncWrapper (), nil , nil )
852+
853+ test .setupInstances (evaluator .Instances )
854+ test .setupOutputs (evaluator .NamedValues )
855+
856+ data := & evaluationStateData {
857+ evaluationData : & evaluationData {
858+ Evaluator : evaluator ,
859+ },
860+ Operation : walkPlan ,
861+ }
862+ scope := evaluator .Scope (data , nil , nil , lang.ExternalFuncs {})
863+
864+ got , diags := scope .Data .GetModule (addrs.ModuleCall {
865+ Name : "mod" ,
866+ }, tfdiags.SourceRange {})
867+
868+ if len (diags ) != 0 {
869+ t .Errorf ("unexpected diagnostics %s" , spew .Sdump (diags ))
870+ }
871+ if ! got .RawEquals (test .want ) {
872+ t .Errorf ("wrong result\n got: %#v\n want: %#v" , got , test .want )
873+ }
874+ })
875+ }
876+ }
877+
878+ func evaluatorForModule (stateSync * states.SyncState , changesSync * plans.ChangesSync , configureOutput func (* configs.Output ), configureModuleCall func (* configs.ModuleCall )) * Evaluator {
879+ moduleCall := & configs.ModuleCall {
880+ Name : "mod" ,
881+ }
882+ if configureModuleCall != nil {
883+ configureModuleCall (moduleCall )
884+ }
885+
886+ output := & configs.Output {
887+ Name : "out" ,
888+ Sensitive : true ,
889+ ConstraintType : cty .DynamicPseudoType ,
890+ }
891+ if configureOutput != nil {
892+ configureOutput (output )
893+ }
894+
597895 return & Evaluator {
598896 Meta : & ContextMeta {
599897 Env : "foo" ,
600898 },
601899 Config : & configs.Config {
602900 Module : & configs.Module {
603901 ModuleCalls : map [string ]* configs.ModuleCall {
604- "mod" : {
605- Name : "mod" ,
606- },
902+ "mod" : moduleCall ,
607903 },
608904 },
609905 Children : map [string ]* configs.Config {
610906 "mod" : {
611907 Path : addrs.Module {"module.mod" },
612908 Module : & configs.Module {
613909 Outputs : map [string ]* configs.Output {
614- "out" : {
615- Name : "out" ,
616- Sensitive : true ,
617- ConstraintType : cty .DynamicPseudoType ,
618- },
910+ "out" : output ,
619911 },
620912 },
621913 },
0 commit comments