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  `