github.com/kanishk98/terraform@v1.3.0-dev.0.20220917174235-661ca8088a6a/internal/terraform/graph_builder_plan_test.go (about) 1 package terraform 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8 "github.com/zclconf/go-cty/cty" 9 10 "github.com/hashicorp/terraform/internal/addrs" 11 "github.com/hashicorp/terraform/internal/configs/configschema" 12 "github.com/hashicorp/terraform/internal/providers" 13 ) 14 15 func TestPlanGraphBuilder_impl(t *testing.T) { 16 var _ GraphBuilder = new(PlanGraphBuilder) 17 } 18 19 func TestPlanGraphBuilder(t *testing.T) { 20 awsProvider := &MockProvider{ 21 GetProviderSchemaResponse: &providers.GetProviderSchemaResponse{ 22 Provider: providers.Schema{Block: simpleTestSchema()}, 23 ResourceTypes: map[string]providers.Schema{ 24 "aws_security_group": {Block: simpleTestSchema()}, 25 "aws_instance": {Block: simpleTestSchema()}, 26 "aws_load_balancer": {Block: simpleTestSchema()}, 27 }, 28 }, 29 } 30 openstackProvider := mockProviderWithResourceTypeSchema("openstack_floating_ip", simpleTestSchema()) 31 plugins := newContextPlugins(map[addrs.Provider]providers.Factory{ 32 addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider), 33 addrs.NewDefaultProvider("openstack"): providers.FactoryFixed(openstackProvider), 34 }, nil) 35 36 b := &PlanGraphBuilder{ 37 Config: testModule(t, "graph-builder-plan-basic"), 38 Plugins: plugins, 39 Operation: walkPlan, 40 } 41 42 g, err := b.Build(addrs.RootModuleInstance) 43 if err != nil { 44 t.Fatalf("err: %s", err) 45 } 46 47 if g.Path.String() != addrs.RootModuleInstance.String() { 48 t.Fatalf("wrong module path %q", g.Path) 49 } 50 51 got := strings.TrimSpace(g.String()) 52 want := strings.TrimSpace(testPlanGraphBuilderStr) 53 if diff := cmp.Diff(want, got); diff != "" { 54 t.Fatalf("wrong result\n%s", diff) 55 } 56 } 57 58 func TestPlanGraphBuilder_dynamicBlock(t *testing.T) { 59 provider := mockProviderWithResourceTypeSchema("test_thing", &configschema.Block{ 60 Attributes: map[string]*configschema.Attribute{ 61 "id": {Type: cty.String, Computed: true}, 62 "list": {Type: cty.List(cty.String), Computed: true}, 63 }, 64 BlockTypes: map[string]*configschema.NestedBlock{ 65 "nested": { 66 Nesting: configschema.NestingList, 67 Block: configschema.Block{ 68 Attributes: map[string]*configschema.Attribute{ 69 "foo": {Type: cty.String, Optional: true}, 70 }, 71 }, 72 }, 73 }, 74 }) 75 plugins := newContextPlugins(map[addrs.Provider]providers.Factory{ 76 addrs.NewDefaultProvider("test"): providers.FactoryFixed(provider), 77 }, nil) 78 79 b := &PlanGraphBuilder{ 80 Config: testModule(t, "graph-builder-plan-dynblock"), 81 Plugins: plugins, 82 Operation: walkPlan, 83 } 84 85 g, err := b.Build(addrs.RootModuleInstance) 86 if err != nil { 87 t.Fatalf("err: %s", err) 88 } 89 90 if g.Path.String() != addrs.RootModuleInstance.String() { 91 t.Fatalf("wrong module path %q", g.Path) 92 } 93 94 // This test is here to make sure we properly detect references inside 95 // the special "dynamic" block construct. The most important thing here 96 // is that at the end test_thing.c depends on both test_thing.a and 97 // test_thing.b. Other details might shift over time as other logic in 98 // the graph builders changes. 99 got := strings.TrimSpace(g.String()) 100 want := strings.TrimSpace(` 101 provider["registry.terraform.io/hashicorp/test"] 102 provider["registry.terraform.io/hashicorp/test"] (close) 103 test_thing.c (expand) 104 root 105 provider["registry.terraform.io/hashicorp/test"] (close) 106 test_thing.a (expand) 107 provider["registry.terraform.io/hashicorp/test"] 108 test_thing.b (expand) 109 provider["registry.terraform.io/hashicorp/test"] 110 test_thing.c (expand) 111 test_thing.a (expand) 112 test_thing.b (expand) 113 `) 114 if diff := cmp.Diff(want, got); diff != "" { 115 t.Fatalf("wrong result\n%s", diff) 116 } 117 } 118 119 func TestPlanGraphBuilder_attrAsBlocks(t *testing.T) { 120 provider := mockProviderWithResourceTypeSchema("test_thing", &configschema.Block{ 121 Attributes: map[string]*configschema.Attribute{ 122 "id": {Type: cty.String, Computed: true}, 123 "nested": { 124 Type: cty.List(cty.Object(map[string]cty.Type{ 125 "foo": cty.String, 126 })), 127 Optional: true, 128 }, 129 }, 130 }) 131 plugins := newContextPlugins(map[addrs.Provider]providers.Factory{ 132 addrs.NewDefaultProvider("test"): providers.FactoryFixed(provider), 133 }, nil) 134 135 b := &PlanGraphBuilder{ 136 Config: testModule(t, "graph-builder-plan-attr-as-blocks"), 137 Plugins: plugins, 138 Operation: walkPlan, 139 } 140 141 g, err := b.Build(addrs.RootModuleInstance) 142 if err != nil { 143 t.Fatalf("err: %s", err) 144 } 145 146 if g.Path.String() != addrs.RootModuleInstance.String() { 147 t.Fatalf("wrong module path %q", g.Path) 148 } 149 150 // This test is here to make sure we properly detect references inside 151 // the "nested" block that is actually defined in the schema as a 152 // list-of-objects attribute. This requires some special effort 153 // inside lang.ReferencesInBlock to make sure it searches blocks of 154 // type "nested" along with an attribute named "nested". 155 got := strings.TrimSpace(g.String()) 156 want := strings.TrimSpace(` 157 provider["registry.terraform.io/hashicorp/test"] 158 provider["registry.terraform.io/hashicorp/test"] (close) 159 test_thing.b (expand) 160 root 161 provider["registry.terraform.io/hashicorp/test"] (close) 162 test_thing.a (expand) 163 provider["registry.terraform.io/hashicorp/test"] 164 test_thing.b (expand) 165 test_thing.a (expand) 166 `) 167 if diff := cmp.Diff(want, got); diff != "" { 168 t.Fatalf("wrong result\n%s", diff) 169 } 170 } 171 172 func TestPlanGraphBuilder_targetModule(t *testing.T) { 173 b := &PlanGraphBuilder{ 174 Config: testModule(t, "graph-builder-plan-target-module-provider"), 175 Plugins: simpleMockPluginLibrary(), 176 Targets: []addrs.Targetable{ 177 addrs.RootModuleInstance.Child("child2", addrs.NoKey), 178 }, 179 Operation: walkPlan, 180 } 181 182 g, err := b.Build(addrs.RootModuleInstance) 183 if err != nil { 184 t.Fatalf("err: %s", err) 185 } 186 187 t.Logf("Graph: %s", g.String()) 188 189 testGraphNotContains(t, g, `module.child1.provider["registry.terraform.io/hashicorp/test"]`) 190 testGraphNotContains(t, g, "module.child1.test_object.foo") 191 } 192 193 func TestPlanGraphBuilder_forEach(t *testing.T) { 194 awsProvider := mockProviderWithResourceTypeSchema("aws_instance", simpleTestSchema()) 195 196 plugins := newContextPlugins(map[addrs.Provider]providers.Factory{ 197 addrs.NewDefaultProvider("aws"): providers.FactoryFixed(awsProvider), 198 }, nil) 199 200 b := &PlanGraphBuilder{ 201 Config: testModule(t, "plan-for-each"), 202 Plugins: plugins, 203 Operation: walkPlan, 204 } 205 206 g, err := b.Build(addrs.RootModuleInstance) 207 if err != nil { 208 t.Fatalf("err: %s", err) 209 } 210 211 if g.Path.String() != addrs.RootModuleInstance.String() { 212 t.Fatalf("wrong module path %q", g.Path) 213 } 214 215 got := strings.TrimSpace(g.String()) 216 // We're especially looking for the edge here, where aws_instance.bat 217 // has a dependency on aws_instance.boo 218 want := strings.TrimSpace(testPlanGraphBuilderForEachStr) 219 if diff := cmp.Diff(want, got); diff != "" { 220 t.Fatalf("wrong result\n%s", diff) 221 } 222 } 223 224 const testPlanGraphBuilderStr = ` 225 aws_instance.web (expand) 226 aws_security_group.firewall (expand) 227 var.foo 228 aws_load_balancer.weblb (expand) 229 aws_instance.web (expand) 230 aws_security_group.firewall (expand) 231 provider["registry.terraform.io/hashicorp/aws"] 232 local.instance_id (expand) 233 aws_instance.web (expand) 234 openstack_floating_ip.random (expand) 235 provider["registry.terraform.io/hashicorp/openstack"] 236 output.instance_id (expand) 237 local.instance_id (expand) 238 provider["registry.terraform.io/hashicorp/aws"] 239 openstack_floating_ip.random (expand) 240 provider["registry.terraform.io/hashicorp/aws"] (close) 241 aws_load_balancer.weblb (expand) 242 provider["registry.terraform.io/hashicorp/openstack"] 243 provider["registry.terraform.io/hashicorp/openstack"] (close) 244 openstack_floating_ip.random (expand) 245 root 246 output.instance_id (expand) 247 provider["registry.terraform.io/hashicorp/aws"] (close) 248 provider["registry.terraform.io/hashicorp/openstack"] (close) 249 var.foo 250 ` 251 const testPlanGraphBuilderForEachStr = ` 252 aws_instance.bar (expand) 253 provider["registry.terraform.io/hashicorp/aws"] 254 aws_instance.bar2 (expand) 255 provider["registry.terraform.io/hashicorp/aws"] 256 aws_instance.bat (expand) 257 aws_instance.boo (expand) 258 aws_instance.baz (expand) 259 provider["registry.terraform.io/hashicorp/aws"] 260 aws_instance.boo (expand) 261 provider["registry.terraform.io/hashicorp/aws"] 262 aws_instance.foo (expand) 263 provider["registry.terraform.io/hashicorp/aws"] 264 provider["registry.terraform.io/hashicorp/aws"] 265 provider["registry.terraform.io/hashicorp/aws"] (close) 266 aws_instance.bar (expand) 267 aws_instance.bar2 (expand) 268 aws_instance.bat (expand) 269 aws_instance.baz (expand) 270 aws_instance.foo (expand) 271 root 272 provider["registry.terraform.io/hashicorp/aws"] (close) 273 `