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  `