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  `