2016-11-05 19:58:38 -05:00
|
|
|
package terraform
|
|
|
|
|
|
|
|
import (
|
|
|
|
"strings"
|
|
|
|
"testing"
|
2018-05-04 21:24:06 -05:00
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
2018-09-05 16:35:30 -05:00
|
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
2018-08-17 14:32:35 -05:00
|
|
|
"github.com/hashicorp/terraform/providers"
|
2019-03-18 19:15:23 -05:00
|
|
|
"github.com/zclconf/go-cty/cty"
|
2016-11-05 19:58:38 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestPlanGraphBuilder_impl(t *testing.T) {
|
|
|
|
var _ GraphBuilder = new(PlanGraphBuilder)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPlanGraphBuilder(t *testing.T) {
|
2018-08-17 14:32:35 -05:00
|
|
|
awsProvider := &MockProvider{
|
2018-09-05 16:35:30 -05:00
|
|
|
GetSchemaReturn: &ProviderSchema{
|
|
|
|
Provider: simpleTestSchema(),
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_security_group": simpleTestSchema(),
|
|
|
|
"aws_instance": simpleTestSchema(),
|
|
|
|
"aws_load_balancer": simpleTestSchema(),
|
2018-05-31 14:39:45 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2018-08-17 14:32:35 -05:00
|
|
|
openstackProvider := &MockProvider{
|
2018-09-05 16:35:30 -05:00
|
|
|
GetSchemaReturn: &ProviderSchema{
|
|
|
|
Provider: simpleTestSchema(),
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"openstack_floating_ip": simpleTestSchema(),
|
2018-05-31 14:39:45 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
components := &basicComponentFactory{
|
2019-12-04 10:30:20 -06:00
|
|
|
providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewLegacyProvider("aws"): providers.FactoryFixed(awsProvider),
|
|
|
|
addrs.NewLegacyProvider("openstack"): providers.FactoryFixed(openstackProvider),
|
2018-05-31 14:39:45 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2016-11-05 19:58:38 -05:00
|
|
|
b := &PlanGraphBuilder{
|
2018-05-31 14:39:45 -05:00
|
|
|
Config: testModule(t, "graph-builder-plan-basic"),
|
|
|
|
Components: components,
|
|
|
|
Schemas: &Schemas{
|
2020-02-03 07:18:04 -06:00
|
|
|
Providers: map[addrs.Provider]*ProviderSchema{
|
|
|
|
addrs.NewLegacyProvider("aws"): awsProvider.GetSchemaReturn,
|
|
|
|
addrs.NewLegacyProvider("openstack"): openstackProvider.GetSchemaReturn,
|
2018-05-04 21:24:06 -05:00
|
|
|
},
|
|
|
|
},
|
2016-11-05 19:58:38 -05:00
|
|
|
DisableReduce: true,
|
|
|
|
}
|
|
|
|
|
2018-05-04 21:24:06 -05:00
|
|
|
g, err := b.Build(addrs.RootModuleInstance)
|
2016-11-05 19:58:38 -05:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
2018-05-04 21:24:06 -05:00
|
|
|
if g.Path.String() != addrs.RootModuleInstance.String() {
|
|
|
|
t.Fatalf("wrong module path %q", g.Path)
|
2016-11-05 19:58:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
actual := strings.TrimSpace(g.String())
|
|
|
|
expected := strings.TrimSpace(testPlanGraphBuilderStr)
|
|
|
|
if actual != expected {
|
2017-04-20 00:23:52 -05:00
|
|
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
2016-11-05 19:58:38 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-18 19:15:23 -05:00
|
|
|
func TestPlanGraphBuilder_dynamicBlock(t *testing.T) {
|
|
|
|
provider := &MockProvider{
|
|
|
|
GetSchemaReturn: &ProviderSchema{
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"test_thing": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"list": {Type: cty.List(cty.String), Computed: true},
|
|
|
|
},
|
|
|
|
BlockTypes: map[string]*configschema.NestedBlock{
|
|
|
|
"nested": {
|
|
|
|
Nesting: configschema.NestingList,
|
|
|
|
Block: configschema.Block{
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"foo": {Type: cty.String, Optional: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
components := &basicComponentFactory{
|
2019-12-04 10:30:20 -06:00
|
|
|
providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewLegacyProvider("test"): providers.FactoryFixed(provider),
|
2019-03-18 19:15:23 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
b := &PlanGraphBuilder{
|
|
|
|
Config: testModule(t, "graph-builder-plan-dynblock"),
|
|
|
|
Components: components,
|
|
|
|
Schemas: &Schemas{
|
2020-02-03 07:18:04 -06:00
|
|
|
Providers: map[addrs.Provider]*ProviderSchema{
|
|
|
|
addrs.NewLegacyProvider("test"): provider.GetSchemaReturn,
|
2019-03-18 19:15:23 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
DisableReduce: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
g, err := b.Build(addrs.RootModuleInstance)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.Path.String() != addrs.RootModuleInstance.String() {
|
|
|
|
t.Fatalf("wrong module path %q", g.Path)
|
|
|
|
}
|
|
|
|
|
|
|
|
// This test is here to make sure we properly detect references inside
|
|
|
|
// the special "dynamic" block construct. The most important thing here
|
|
|
|
// is that at the end test_thing.c depends on both test_thing.a and
|
|
|
|
// test_thing.b. Other details might shift over time as other logic in
|
|
|
|
// the graph builders changes.
|
|
|
|
actual := strings.TrimSpace(g.String())
|
|
|
|
expected := strings.TrimSpace(`
|
|
|
|
meta.count-boundary (EachMode fixup)
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"]
|
2019-03-18 19:15:23 -05:00
|
|
|
test_thing.a
|
|
|
|
test_thing.b
|
|
|
|
test_thing.c
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"]
|
|
|
|
provider["registry.terraform.io/-/test"] (close)
|
|
|
|
provider["registry.terraform.io/-/test"]
|
2019-03-18 19:15:23 -05:00
|
|
|
test_thing.a
|
|
|
|
test_thing.b
|
|
|
|
test_thing.c
|
|
|
|
root
|
|
|
|
meta.count-boundary (EachMode fixup)
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"] (close)
|
2019-03-18 19:15:23 -05:00
|
|
|
test_thing.a
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"]
|
2019-03-18 19:15:23 -05:00
|
|
|
test_thing.b
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"]
|
2019-03-18 19:15:23 -05:00
|
|
|
test_thing.c
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"]
|
2019-03-18 19:15:23 -05:00
|
|
|
test_thing.a
|
|
|
|
test_thing.b
|
|
|
|
`)
|
|
|
|
if actual != expected {
|
|
|
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-28 12:07:16 -05:00
|
|
|
func TestPlanGraphBuilder_attrAsBlocks(t *testing.T) {
|
|
|
|
provider := &MockProvider{
|
|
|
|
GetSchemaReturn: &ProviderSchema{
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"test_thing": {
|
|
|
|
Attributes: map[string]*configschema.Attribute{
|
|
|
|
"id": {Type: cty.String, Computed: true},
|
|
|
|
"nested": {
|
|
|
|
Type: cty.List(cty.Object(map[string]cty.Type{
|
|
|
|
"foo": cty.String,
|
|
|
|
})),
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
components := &basicComponentFactory{
|
2019-12-04 10:30:20 -06:00
|
|
|
providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewLegacyProvider("test"): providers.FactoryFixed(provider),
|
2019-03-28 12:07:16 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
b := &PlanGraphBuilder{
|
|
|
|
Config: testModule(t, "graph-builder-plan-attr-as-blocks"),
|
|
|
|
Components: components,
|
|
|
|
Schemas: &Schemas{
|
2020-02-03 07:18:04 -06:00
|
|
|
Providers: map[addrs.Provider]*ProviderSchema{
|
|
|
|
addrs.NewLegacyProvider("test"): provider.GetSchemaReturn,
|
2019-03-28 12:07:16 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
DisableReduce: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
g, err := b.Build(addrs.RootModuleInstance)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.Path.String() != addrs.RootModuleInstance.String() {
|
|
|
|
t.Fatalf("wrong module path %q", g.Path)
|
|
|
|
}
|
|
|
|
|
|
|
|
// This test is here to make sure we properly detect references inside
|
|
|
|
// the "nested" block that is actually defined in the schema as a
|
|
|
|
// list-of-objects attribute. This requires some special effort
|
|
|
|
// inside lang.ReferencesInBlock to make sure it searches blocks of
|
|
|
|
// type "nested" along with an attribute named "nested".
|
|
|
|
actual := strings.TrimSpace(g.String())
|
|
|
|
expected := strings.TrimSpace(`
|
|
|
|
meta.count-boundary (EachMode fixup)
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"]
|
2019-03-28 12:07:16 -05:00
|
|
|
test_thing.a
|
|
|
|
test_thing.b
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"]
|
|
|
|
provider["registry.terraform.io/-/test"] (close)
|
|
|
|
provider["registry.terraform.io/-/test"]
|
2019-03-28 12:07:16 -05:00
|
|
|
test_thing.a
|
|
|
|
test_thing.b
|
|
|
|
root
|
|
|
|
meta.count-boundary (EachMode fixup)
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"] (close)
|
2019-03-28 12:07:16 -05:00
|
|
|
test_thing.a
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"]
|
2019-03-28 12:07:16 -05:00
|
|
|
test_thing.b
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/test"]
|
2019-03-28 12:07:16 -05:00
|
|
|
test_thing.a
|
|
|
|
`)
|
|
|
|
if actual != expected {
|
|
|
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-17 11:21:29 -06:00
|
|
|
func TestPlanGraphBuilder_targetModule(t *testing.T) {
|
|
|
|
b := &PlanGraphBuilder{
|
2018-05-10 11:56:32 -05:00
|
|
|
Config: testModule(t, "graph-builder-plan-target-module-provider"),
|
|
|
|
Components: simpleMockComponentFactory(),
|
2018-05-31 14:39:45 -05:00
|
|
|
Schemas: simpleTestSchemas(),
|
2018-05-04 21:24:06 -05:00
|
|
|
Targets: []addrs.Targetable{
|
|
|
|
addrs.RootModuleInstance.Child("child2", addrs.NoKey),
|
|
|
|
},
|
2017-02-17 11:21:29 -06:00
|
|
|
}
|
|
|
|
|
2018-05-04 21:24:06 -05:00
|
|
|
g, err := b.Build(addrs.RootModuleInstance)
|
2017-02-17 11:21:29 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Logf("Graph: %s", g.String())
|
|
|
|
|
2020-02-13 14:32:58 -06:00
|
|
|
testGraphNotContains(t, g, `module.child1.provider["registry.terraform.io/-/test"]`)
|
2018-05-10 11:56:32 -05:00
|
|
|
testGraphNotContains(t, g, "module.child1.test_object.foo")
|
2017-02-17 11:21:29 -06:00
|
|
|
}
|
|
|
|
|
2019-06-12 10:07:32 -05:00
|
|
|
func TestPlanGraphBuilder_forEach(t *testing.T) {
|
|
|
|
awsProvider := &MockProvider{
|
|
|
|
GetSchemaReturn: &ProviderSchema{
|
|
|
|
Provider: simpleTestSchema(),
|
|
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
|
|
"aws_instance": simpleTestSchema(),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
components := &basicComponentFactory{
|
2019-12-04 10:30:20 -06:00
|
|
|
providers: map[addrs.Provider]providers.Factory{
|
|
|
|
addrs.NewLegacyProvider("aws"): providers.FactoryFixed(awsProvider),
|
2019-06-12 10:07:32 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
b := &PlanGraphBuilder{
|
|
|
|
Config: testModule(t, "plan-for-each"),
|
|
|
|
Components: components,
|
|
|
|
Schemas: &Schemas{
|
2020-02-03 07:18:04 -06:00
|
|
|
Providers: map[addrs.Provider]*ProviderSchema{
|
|
|
|
addrs.NewLegacyProvider("aws"): awsProvider.GetSchemaReturn,
|
2019-06-12 10:07:32 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
DisableReduce: true,
|
|
|
|
}
|
|
|
|
|
|
|
|
g, err := b.Build(addrs.RootModuleInstance)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("err: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if g.Path.String() != addrs.RootModuleInstance.String() {
|
|
|
|
t.Fatalf("wrong module path %q", g.Path)
|
|
|
|
}
|
|
|
|
|
|
|
|
actual := strings.TrimSpace(g.String())
|
|
|
|
// We're especially looking for the edge here, where aws_instance.bat
|
|
|
|
// has a dependency on aws_instance.boo
|
|
|
|
expected := strings.TrimSpace(testPlanGraphBuilderForEachStr)
|
|
|
|
if actual != expected {
|
|
|
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-05 19:58:38 -05:00
|
|
|
const testPlanGraphBuilderStr = `
|
|
|
|
aws_instance.web
|
|
|
|
aws_security_group.firewall
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2016-11-05 19:58:38 -05:00
|
|
|
var.foo
|
|
|
|
aws_load_balancer.weblb
|
|
|
|
aws_instance.web
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2016-11-05 19:58:38 -05:00
|
|
|
aws_security_group.firewall
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2017-07-01 11:48:37 -05:00
|
|
|
local.instance_id
|
|
|
|
aws_instance.web
|
2018-09-07 18:58:32 -05:00
|
|
|
meta.count-boundary (EachMode fixup)
|
2017-04-20 00:23:52 -05:00
|
|
|
aws_instance.web
|
|
|
|
aws_load_balancer.weblb
|
|
|
|
aws_security_group.firewall
|
2017-07-01 11:48:37 -05:00
|
|
|
local.instance_id
|
2017-04-20 00:23:52 -05:00
|
|
|
openstack_floating_ip.random
|
2017-07-01 11:48:37 -05:00
|
|
|
output.instance_id
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
|
|
|
provider["registry.terraform.io/-/openstack"]
|
2017-04-20 00:23:52 -05:00
|
|
|
var.foo
|
2016-11-05 19:58:38 -05:00
|
|
|
openstack_floating_ip.random
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/openstack"]
|
2017-07-01 11:48:37 -05:00
|
|
|
output.instance_id
|
|
|
|
local.instance_id
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2016-11-05 19:58:38 -05:00
|
|
|
openstack_floating_ip.random
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"] (close)
|
2017-04-12 16:25:15 -05:00
|
|
|
aws_instance.web
|
|
|
|
aws_load_balancer.weblb
|
|
|
|
aws_security_group.firewall
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
|
|
|
provider["registry.terraform.io/-/openstack"]
|
|
|
|
provider["registry.terraform.io/-/openstack"] (close)
|
2017-04-12 16:25:15 -05:00
|
|
|
openstack_floating_ip.random
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/openstack"]
|
2017-04-12 16:25:15 -05:00
|
|
|
root
|
2018-09-07 18:58:32 -05:00
|
|
|
meta.count-boundary (EachMode fixup)
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"] (close)
|
|
|
|
provider["registry.terraform.io/-/openstack"] (close)
|
2016-11-05 19:58:38 -05:00
|
|
|
var.foo
|
|
|
|
`
|
2019-06-12 10:07:32 -05:00
|
|
|
const testPlanGraphBuilderForEachStr = `
|
|
|
|
aws_instance.bar
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2019-09-10 09:37:54 -05:00
|
|
|
aws_instance.bar2
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2019-06-12 10:07:32 -05:00
|
|
|
aws_instance.bat
|
|
|
|
aws_instance.boo
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2019-06-12 10:07:32 -05:00
|
|
|
aws_instance.baz
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2019-06-12 10:07:32 -05:00
|
|
|
aws_instance.boo
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2019-06-12 10:07:32 -05:00
|
|
|
aws_instance.foo
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2019-06-12 10:07:32 -05:00
|
|
|
meta.count-boundary (EachMode fixup)
|
|
|
|
aws_instance.bar
|
2019-09-10 09:37:54 -05:00
|
|
|
aws_instance.bar2
|
2019-06-12 10:07:32 -05:00
|
|
|
aws_instance.bat
|
|
|
|
aws_instance.baz
|
|
|
|
aws_instance.boo
|
|
|
|
aws_instance.foo
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
|
|
|
provider["registry.terraform.io/-/aws"]
|
|
|
|
provider["registry.terraform.io/-/aws"] (close)
|
2019-06-12 10:07:32 -05:00
|
|
|
aws_instance.bar
|
2019-09-10 09:37:54 -05:00
|
|
|
aws_instance.bar2
|
2019-06-12 10:07:32 -05:00
|
|
|
aws_instance.bat
|
|
|
|
aws_instance.baz
|
|
|
|
aws_instance.boo
|
|
|
|
aws_instance.foo
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"]
|
2019-06-12 10:07:32 -05:00
|
|
|
root
|
|
|
|
meta.count-boundary (EachMode fixup)
|
2020-02-13 14:32:58 -06:00
|
|
|
provider["registry.terraform.io/-/aws"] (close)
|
2019-06-12 10:07:32 -05:00
|
|
|
`
|