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