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