github.com/adamar/terraform@v0.2.2-0.20141016210445-2e703afdad0e/terraform/graph_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"reflect"
     5  	"sort"
     6  	"strings"
     7  	"testing"
     8  )
     9  
    10  func TestGraph_basic(t *testing.T) {
    11  	m := testModule(t, "graph-basic")
    12  
    13  	g, err := Graph(&GraphOpts{Module: m})
    14  	if err != nil {
    15  		t.Fatalf("err: %s", err)
    16  	}
    17  
    18  	actual := strings.TrimSpace(g.String())
    19  	expected := strings.TrimSpace(testTerraformGraphStr)
    20  	if actual != expected {
    21  		t.Fatalf("bad:\n\n%s", actual)
    22  	}
    23  }
    24  
    25  func TestGraph_configRequired(t *testing.T) {
    26  	if _, err := Graph(new(GraphOpts)); err == nil {
    27  		t.Fatal("should error")
    28  	}
    29  }
    30  
    31  func TestGraph_count(t *testing.T) {
    32  	m := testModule(t, "graph-count")
    33  
    34  	g, err := Graph(&GraphOpts{Module: m})
    35  	if err != nil {
    36  		t.Fatalf("err: %s", err)
    37  	}
    38  
    39  	actual := strings.TrimSpace(g.String())
    40  	expected := strings.TrimSpace(testTerraformGraphCountStr)
    41  	if actual != expected {
    42  		t.Fatalf("bad:\n\n%s", actual)
    43  	}
    44  }
    45  
    46  func TestGraph_countTainted(t *testing.T) {
    47  	m := testModule(t, "graph-count")
    48  	state := &State{
    49  		Modules: []*ModuleState{
    50  			&ModuleState{
    51  				Path: []string{"root"},
    52  				Resources: map[string]*ResourceState{
    53  					"aws_instance.web.0": &ResourceState{
    54  						Type: "aws_instance",
    55  						Tainted: []*InstanceState{
    56  							&InstanceState{
    57  								ID: "foo",
    58  							},
    59  						},
    60  					},
    61  				},
    62  			},
    63  		},
    64  	}
    65  
    66  	g, err := Graph(&GraphOpts{Module: m, State: state})
    67  	if err != nil {
    68  		t.Fatalf("err: %s", err)
    69  	}
    70  
    71  	actual := strings.TrimSpace(g.String())
    72  	expected := strings.TrimSpace(testTerraformGraphCountTaintedStr)
    73  	if actual != expected {
    74  		t.Fatalf("bad:\n\n%s", actual)
    75  	}
    76  }
    77  
    78  func TestGraph_varResource(t *testing.T) {
    79  	m := testModule(t, "graph-count-var-resource")
    80  
    81  	g, err := Graph(&GraphOpts{Module: m})
    82  	if err != nil {
    83  		t.Fatalf("err: %s", err)
    84  	}
    85  
    86  	actual := strings.TrimSpace(g.String())
    87  	expected := strings.TrimSpace(testTerraformGraphCountVarResourceStr)
    88  	if actual != expected {
    89  		t.Fatalf("bad:\n\n%s", actual)
    90  	}
    91  }
    92  
    93  func TestGraph_cycle(t *testing.T) {
    94  	m := testModule(t, "graph-cycle")
    95  
    96  	_, err := Graph(&GraphOpts{Module: m})
    97  	if err == nil {
    98  		t.Fatal("should error")
    99  	}
   100  }
   101  
   102  func TestGraph_dependsOn(t *testing.T) {
   103  	m := testModule(t, "graph-depends-on")
   104  
   105  	g, err := Graph(&GraphOpts{Module: m})
   106  	if err != nil {
   107  		t.Fatalf("err: %s", err)
   108  	}
   109  
   110  	actual := strings.TrimSpace(g.String())
   111  	expected := strings.TrimSpace(testTerraformGraphDependsStr)
   112  	if actual != expected {
   113  		t.Fatalf("bad:\n\n%s", actual)
   114  	}
   115  }
   116  
   117  func TestGraph_dependsOnCount(t *testing.T) {
   118  	m := testModule(t, "graph-depends-on-count")
   119  
   120  	g, err := Graph(&GraphOpts{Module: m})
   121  	if err != nil {
   122  		t.Fatalf("err: %s", err)
   123  	}
   124  
   125  	actual := strings.TrimSpace(g.String())
   126  	expected := strings.TrimSpace(testTerraformGraphDependsCountStr)
   127  	if actual != expected {
   128  		t.Fatalf("bad:\n\n%s", actual)
   129  	}
   130  }
   131  
   132  func TestGraph_dependsOnWithOrphan(t *testing.T) {
   133  	m := testModule(t, "graph-depends-on")
   134  
   135  	state := &State{
   136  		Modules: []*ModuleState{
   137  			&ModuleState{
   138  				Path: []string{"root"},
   139  				Resources: map[string]*ResourceState{
   140  					"aws_instance.old": &ResourceState{
   141  						Type: "aws_instance",
   142  						Primary: &InstanceState{
   143  							ID: "foo",
   144  						},
   145  					},
   146  				},
   147  			},
   148  		},
   149  	}
   150  
   151  	g, err := Graph(&GraphOpts{Module: m, State: state})
   152  	if err != nil {
   153  		t.Fatalf("err: %s", err)
   154  	}
   155  
   156  	actual := strings.TrimSpace(g.String())
   157  	expected := strings.TrimSpace(testTerraformGraphDependsOrphanStr)
   158  	if actual != expected {
   159  		t.Fatalf("bad:\n\n%s", actual)
   160  	}
   161  }
   162  
   163  func TestGraph_modules(t *testing.T) {
   164  	m := testModule(t, "graph-modules")
   165  
   166  	g, err := Graph(&GraphOpts{Module: m})
   167  	if err != nil {
   168  		t.Fatalf("err: %s", err)
   169  	}
   170  
   171  	actual := strings.TrimSpace(g.String())
   172  	expected := strings.TrimSpace(testTerraformGraphModulesStr)
   173  	if actual != expected {
   174  		t.Fatalf("bad:\n\n%s", actual)
   175  	}
   176  
   177  	n := g.Noun("module.consul")
   178  	if n == nil {
   179  		t.Fatal("can't find noun")
   180  	}
   181  	mn := n.Meta.(*GraphNodeModule)
   182  
   183  	if !reflect.DeepEqual(mn.Path, []string{"root", "consul"}) {
   184  		t.Fatalf("bad: %#v", mn.Path)
   185  	}
   186  
   187  	actual = strings.TrimSpace(mn.Graph.String())
   188  	expected = strings.TrimSpace(testTerraformGraphModulesConsulStr)
   189  	if actual != expected {
   190  		t.Fatalf("bad:\n\n%s", actual)
   191  	}
   192  }
   193  
   194  func TestGraph_moduleOrphan(t *testing.T) {
   195  	m := testModule(t, "graph-module-orphan")
   196  	state := &State{
   197  		Modules: []*ModuleState{
   198  			&ModuleState{
   199  				Path: []string{"root", "consul"},
   200  
   201  				Resources: map[string]*ResourceState{
   202  					"aws_instance.old": &ResourceState{
   203  						Type: "aws_instance",
   204  						Primary: &InstanceState{
   205  							ID: "foo",
   206  						},
   207  					},
   208  				},
   209  			},
   210  		},
   211  	}
   212  
   213  	g, err := Graph(&GraphOpts{Module: m, State: state})
   214  	if err != nil {
   215  		t.Fatalf("err: %s", err)
   216  	}
   217  
   218  	actual := strings.TrimSpace(g.String())
   219  	expected := strings.TrimSpace(testTerraformGraphModuleOrphanStr)
   220  	if actual != expected {
   221  		t.Fatalf("bad:\n\n%s", actual)
   222  	}
   223  
   224  	n := g.Noun("module.consul")
   225  	if n == nil {
   226  		t.Fatal("can't find noun")
   227  	}
   228  	mn := n.Meta.(*GraphNodeModule)
   229  
   230  	if !reflect.DeepEqual(mn.Path, []string{"root", "consul"}) {
   231  		t.Fatalf("bad: %#v", mn.Path)
   232  	}
   233  
   234  	actual = strings.TrimSpace(mn.Graph.String())
   235  	expected = strings.TrimSpace(testTerraformGraphModuleOrphanConsulStr)
   236  	if actual != expected {
   237  		t.Fatalf("bad:\n\n%s", actual)
   238  	}
   239  }
   240  
   241  func TestGraph_providerPrune(t *testing.T) {
   242  	m := testModule(t, "graph-provider-prune")
   243  
   244  	g, err := Graph(&GraphOpts{Module: m})
   245  	if err != nil {
   246  		t.Fatalf("err: %s", err)
   247  	}
   248  
   249  	actual := strings.TrimSpace(g.String())
   250  	expected := strings.TrimSpace(testTerraformGraphProviderPruneStr)
   251  	if actual != expected {
   252  		t.Fatalf("bad:\n\n%s", actual)
   253  	}
   254  }
   255  
   256  func TestGraph_state(t *testing.T) {
   257  	m := testModule(t, "graph-basic")
   258  	state := &State{
   259  		Modules: []*ModuleState{
   260  			&ModuleState{
   261  				Path: rootModulePath,
   262  
   263  				Resources: map[string]*ResourceState{
   264  					"aws_instance.old": &ResourceState{
   265  						Type: "aws_instance",
   266  						Primary: &InstanceState{
   267  							ID: "foo",
   268  						},
   269  					},
   270  				},
   271  			},
   272  		},
   273  	}
   274  
   275  	g, err := Graph(&GraphOpts{Module: m, State: state})
   276  	if err != nil {
   277  		t.Fatalf("err: %s", err)
   278  	}
   279  
   280  	actual := strings.TrimSpace(g.String())
   281  	expected := strings.TrimSpace(testTerraformGraphStateStr)
   282  	if actual != expected {
   283  		t.Fatalf("bad:\n\n%s", actual)
   284  	}
   285  }
   286  
   287  func TestGraph_tainted(t *testing.T) {
   288  	m := testModule(t, "graph-tainted")
   289  	state := &State{
   290  		Modules: []*ModuleState{
   291  			&ModuleState{
   292  				Path: rootModulePath,
   293  
   294  				Resources: map[string]*ResourceState{
   295  					"aws_instance.web": &ResourceState{
   296  						Type: "aws_instance",
   297  						Primary: &InstanceState{
   298  							ID: "foo",
   299  						},
   300  						Tainted: []*InstanceState{
   301  							&InstanceState{
   302  								ID: "bar",
   303  							},
   304  						},
   305  					},
   306  				},
   307  			},
   308  		},
   309  	}
   310  
   311  	g, err := Graph(&GraphOpts{Module: m, State: state})
   312  	if err != nil {
   313  		t.Fatalf("err: %s", err)
   314  	}
   315  
   316  	actual := strings.TrimSpace(g.String())
   317  	expected := strings.TrimSpace(testTerraformGraphTaintedStr)
   318  	if actual != expected {
   319  		t.Fatalf("bad:\n\n%s", actual)
   320  	}
   321  }
   322  
   323  func TestGraph_taintedMulti(t *testing.T) {
   324  	m := testModule(t, "graph-tainted")
   325  	state := &State{
   326  		Modules: []*ModuleState{
   327  			&ModuleState{
   328  				Path: rootModulePath,
   329  
   330  				Resources: map[string]*ResourceState{
   331  					"aws_instance.web": &ResourceState{
   332  						Type: "aws_instance",
   333  						Primary: &InstanceState{
   334  							ID: "foo",
   335  						},
   336  						Tainted: []*InstanceState{
   337  							&InstanceState{
   338  								ID: "bar",
   339  							},
   340  							&InstanceState{
   341  								ID: "baz",
   342  							},
   343  						},
   344  					},
   345  				},
   346  			},
   347  		},
   348  	}
   349  
   350  	g, err := Graph(&GraphOpts{Module: m, State: state})
   351  	if err != nil {
   352  		t.Fatalf("err: %s", err)
   353  	}
   354  
   355  	actual := strings.TrimSpace(g.String())
   356  	expected := strings.TrimSpace(testTerraformGraphTaintedMultiStr)
   357  	if actual != expected {
   358  		t.Fatalf("bad:\n\n%s", actual)
   359  	}
   360  }
   361  
   362  func TestGraphFull(t *testing.T) {
   363  	rpAws := new(MockResourceProvider)
   364  	rpOS := new(MockResourceProvider)
   365  
   366  	rpAws.ResourcesReturn = []ResourceType{
   367  		ResourceType{Name: "aws_instance"},
   368  		ResourceType{Name: "aws_load_balancer"},
   369  		ResourceType{Name: "aws_security_group"},
   370  	}
   371  	rpOS.ResourcesReturn = []ResourceType{
   372  		ResourceType{Name: "openstack_floating_ip"},
   373  	}
   374  
   375  	ps := map[string]ResourceProviderFactory{
   376  		"aws":  testProviderFuncFixed(rpAws),
   377  		"open": testProviderFuncFixed(rpOS),
   378  	}
   379  
   380  	m := testModule(t, "graph-basic")
   381  	g, err := Graph(&GraphOpts{Module: m, Providers: ps})
   382  	if err != nil {
   383  		t.Fatalf("err: %s", err)
   384  	}
   385  
   386  	// A helper to help get us the provider for a resource.
   387  	graphProvider := func(n string) ResourceProvider {
   388  		return g.Noun(n).Meta.(*GraphNodeResource).Resource.Provider
   389  	}
   390  
   391  	// Test a couple
   392  	if graphProvider("aws_instance.web") != rpAws {
   393  		t.Fatalf("bad: %#v", graphProvider("aws_instance.web"))
   394  	}
   395  	if graphProvider("openstack_floating_ip.random") != rpOS {
   396  		t.Fatalf("bad: %#v", graphProvider("openstack_floating_ip.random"))
   397  	}
   398  
   399  	// Test that all providers have been set
   400  	for _, n := range g.Nouns {
   401  		switch m := n.Meta.(type) {
   402  		case *GraphNodeResource:
   403  			if m.Resource.Provider == nil {
   404  				t.Fatalf("bad: %#v", m)
   405  			}
   406  		case *GraphNodeResourceProvider:
   407  			if len(m.Provider.Providers) == 0 {
   408  				t.Fatalf("bad: %#v", m)
   409  			}
   410  		default:
   411  			continue
   412  		}
   413  	}
   414  }
   415  
   416  func TestGraphProvisioners(t *testing.T) {
   417  	rpAws := new(MockResourceProvider)
   418  	provShell := new(MockResourceProvisioner)
   419  	provWinRM := new(MockResourceProvisioner)
   420  
   421  	rpAws.ResourcesReturn = []ResourceType{
   422  		ResourceType{Name: "aws_instance"},
   423  		ResourceType{Name: "aws_load_balancer"},
   424  		ResourceType{Name: "aws_security_group"},
   425  	}
   426  
   427  	ps := map[string]ResourceProvisionerFactory{
   428  		"shell": testProvisionerFuncFixed(provShell),
   429  		"winrm": testProvisionerFuncFixed(provWinRM),
   430  	}
   431  
   432  	pf := map[string]ResourceProviderFactory{
   433  		"aws": testProviderFuncFixed(rpAws),
   434  	}
   435  
   436  	m := testModule(t, "graph-provisioners")
   437  	g, err := Graph(&GraphOpts{Module: m, Providers: pf, Provisioners: ps})
   438  	if err != nil {
   439  		t.Fatalf("err: %s", err)
   440  	}
   441  
   442  	// A helper to help get us the provider for a resource.
   443  	graphProvisioner := func(n string, idx int) *ResourceProvisionerConfig {
   444  		return g.Noun(n).Meta.(*GraphNodeResource).Resource.Provisioners[idx]
   445  	}
   446  
   447  	// A helper to verify depedencies
   448  	depends := func(a, b string) bool {
   449  		aNoun := g.Noun(a)
   450  		bNoun := g.Noun(b)
   451  		for _, dep := range aNoun.Deps {
   452  			if dep.Source == aNoun && dep.Target == bNoun {
   453  				return true
   454  			}
   455  		}
   456  		return false
   457  	}
   458  
   459  	// Test a couple
   460  	prov := graphProvisioner("aws_instance.web", 0)
   461  	if prov.Provisioner != provWinRM {
   462  		t.Fatalf("bad: %#v", prov)
   463  	}
   464  	if prov.RawConfig.Config()["cmd"] != "echo foo" {
   465  		t.Fatalf("bad: %#v", prov)
   466  	}
   467  
   468  	prov = graphProvisioner("aws_instance.web", 1)
   469  	if prov.Provisioner != provWinRM {
   470  		t.Fatalf("bad: %#v", prov)
   471  	}
   472  	if prov.RawConfig.Config()["cmd"] != "echo bar" {
   473  		t.Fatalf("bad: %#v", prov)
   474  	}
   475  
   476  	prov = graphProvisioner("aws_load_balancer.weblb", 0)
   477  	if prov.Provisioner != provShell {
   478  		t.Fatalf("bad: %#v", prov)
   479  	}
   480  	if prov.RawConfig.Config()["cmd"] != "add ${aws_instance.web.id}" {
   481  		t.Fatalf("bad: %#v", prov)
   482  	}
   483  	if prov.ConnInfo == nil || len(prov.ConnInfo.Raw) != 2 {
   484  		t.Fatalf("bad: %#v", prov)
   485  	}
   486  
   487  	// Check that the variable dependency is handled
   488  	if !depends("aws_load_balancer.weblb", "aws_instance.web") {
   489  		t.Fatalf("missing dependency from provisioner variable")
   490  	}
   491  
   492  	// Check that the connection variable dependency is handled
   493  	if !depends("aws_load_balancer.weblb", "aws_security_group.firewall") {
   494  		t.Fatalf("missing dependency from provisioner connection")
   495  	}
   496  }
   497  
   498  func TestGraphAddDiff(t *testing.T) {
   499  	m := testModule(t, "graph-diff")
   500  	diff := &Diff{
   501  		Modules: []*ModuleDiff{
   502  			&ModuleDiff{
   503  				Path: rootModulePath,
   504  				Resources: map[string]*InstanceDiff{
   505  					"aws_instance.foo": &InstanceDiff{
   506  						Attributes: map[string]*ResourceAttrDiff{
   507  							"foo": &ResourceAttrDiff{
   508  								New: "bar",
   509  							},
   510  						},
   511  					},
   512  				},
   513  			},
   514  		},
   515  	}
   516  
   517  	g, err := Graph(&GraphOpts{Module: m, Diff: diff})
   518  	if err != nil {
   519  		t.Fatalf("err: %s", err)
   520  	}
   521  
   522  	actual := strings.TrimSpace(g.String())
   523  	expected := strings.TrimSpace(testTerraformGraphDiffStr)
   524  	if actual != expected {
   525  		t.Fatalf("bad:\n\n%s", actual)
   526  	}
   527  
   528  	/*
   529  		TODO: test this somewhere
   530  		// Verify that the state has been added
   531  		n := g.Noun("aws_instance.foo")
   532  		rn := n.Meta.(*GraphNodeResource)
   533  
   534  		expected2 := diff.RootModule().Resources["aws_instance.foo"]
   535  		actual2 := rn.Resource.Diff
   536  		if !reflect.DeepEqual(actual2, expected2) {
   537  			t.Fatalf("bad: %#v", actual2)
   538  		}
   539  	*/
   540  }
   541  
   542  func TestGraphAddDiff_destroy(t *testing.T) {
   543  	m := testModule(t, "graph-diff-destroy")
   544  	diff := &Diff{
   545  		Modules: []*ModuleDiff{
   546  			&ModuleDiff{
   547  				Path: rootModulePath,
   548  				Resources: map[string]*InstanceDiff{
   549  					"aws_instance.foo": &InstanceDiff{
   550  						Destroy: true,
   551  					},
   552  					"aws_instance.bar": &InstanceDiff{
   553  						Destroy: true,
   554  					},
   555  				},
   556  			},
   557  		},
   558  	}
   559  	state := &State{
   560  		Modules: []*ModuleState{
   561  			&ModuleState{
   562  				Path: rootModulePath,
   563  				Resources: map[string]*ResourceState{
   564  					"aws_instance.foo": &ResourceState{
   565  						Type: "aws_instance",
   566  						Primary: &InstanceState{
   567  							ID: "foo",
   568  						},
   569  					},
   570  
   571  					"aws_instance.bar": &ResourceState{
   572  						Type:         "aws_instance",
   573  						Dependencies: []string{"foo"},
   574  						Primary: &InstanceState{
   575  							ID: "bar",
   576  						},
   577  					},
   578  				},
   579  			},
   580  		},
   581  	}
   582  
   583  	diffHash := checksumStruct(t, diff)
   584  
   585  	g, err := Graph(&GraphOpts{
   586  		Module: m,
   587  		Diff:   diff,
   588  		State:  state,
   589  	})
   590  	if err != nil {
   591  		t.Fatalf("err: %s", err)
   592  	}
   593  
   594  	actual := strings.TrimSpace(g.String())
   595  	expected := strings.TrimSpace(testTerraformGraphDiffDestroyStr)
   596  	if actual != expected {
   597  		t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actual, expected)
   598  	}
   599  
   600  	// Verify that the state has been added
   601  	n := g.Noun("aws_instance.foo (destroy)")
   602  	rn := n.Meta.(*GraphNodeResource)
   603  
   604  	expected2 := &InstanceDiff{Destroy: true}
   605  	actual2 := rn.Resource.Diff
   606  	if !reflect.DeepEqual(actual2, expected2) {
   607  		t.Fatalf("bad: %#v", actual2)
   608  	}
   609  
   610  	// Verify that our original structure has not been modified
   611  	diffHash2 := checksumStruct(t, diff)
   612  	if diffHash != diffHash2 {
   613  		t.Fatal("diff has been modified")
   614  	}
   615  }
   616  
   617  func TestGraphAddDiff_destroy_counts(t *testing.T) {
   618  	m := testModule(t, "graph-count")
   619  	diff := &Diff{
   620  		Modules: []*ModuleDiff{
   621  			&ModuleDiff{
   622  				Path: rootModulePath,
   623  				Resources: map[string]*InstanceDiff{
   624  					"aws_instance.web.0": &InstanceDiff{
   625  						Destroy: true,
   626  					},
   627  					"aws_instance.web.1": &InstanceDiff{
   628  						Destroy: true,
   629  					},
   630  					"aws_instance.web.2": &InstanceDiff{
   631  						Destroy: true,
   632  					},
   633  					"aws_load_balancer.weblb": &InstanceDiff{
   634  						Destroy: true,
   635  					},
   636  				},
   637  			},
   638  		},
   639  	}
   640  	state := &State{
   641  		Modules: []*ModuleState{
   642  			&ModuleState{
   643  				Path: rootModulePath,
   644  				Resources: map[string]*ResourceState{
   645  					"aws_instance.web.0": &ResourceState{
   646  						Type: "aws_instance",
   647  						Primary: &InstanceState{
   648  							ID: "foo",
   649  						},
   650  					},
   651  					"aws_instance.web.1": &ResourceState{
   652  						Type: "aws_instance",
   653  						Primary: &InstanceState{
   654  							ID: "foo",
   655  						},
   656  					},
   657  					"aws_instance.web.2": &ResourceState{
   658  						Type: "aws_instance",
   659  						Primary: &InstanceState{
   660  							ID: "foo",
   661  						},
   662  					},
   663  					"aws_load_balancer.weblb": &ResourceState{
   664  						Type:         "aws_load_balancer",
   665  						Dependencies: []string{"aws_instance.web.0", "aws_instance.web.1", "aws_instance.web.2"},
   666  						Primary: &InstanceState{
   667  							ID: "bar",
   668  						},
   669  					},
   670  				},
   671  			},
   672  		},
   673  	}
   674  
   675  	diffHash := checksumStruct(t, diff)
   676  
   677  	g, err := Graph(&GraphOpts{
   678  		Module: m,
   679  		Diff:   diff,
   680  		State:  state,
   681  	})
   682  	if err != nil {
   683  		t.Fatalf("err: %s", err)
   684  	}
   685  
   686  	actual := strings.TrimSpace(g.String())
   687  	expected := strings.TrimSpace(testTerraformGraphDiffDestroyCountsStr)
   688  	if actual != expected {
   689  		t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actual, expected)
   690  	}
   691  
   692  	// Verify that the state has been added
   693  	n := g.Noun("aws_instance.web (destroy)")
   694  	rn := n.Meta.(*GraphNodeResource)
   695  
   696  	if rn.ExpandMode != ResourceExpandDestroy {
   697  		t.Fatalf("bad: %#v", rn)
   698  	}
   699  
   700  	// Verify that our original structure has not been modified
   701  	diffHash2 := checksumStruct(t, diff)
   702  	if diffHash != diffHash2 {
   703  		t.Fatal("diff has been modified")
   704  	}
   705  }
   706  
   707  func TestGraphAddDiff_module(t *testing.T) {
   708  	m := testModule(t, "graph-diff-module")
   709  	diff := &Diff{
   710  		Modules: []*ModuleDiff{
   711  			&ModuleDiff{
   712  				Path: rootModulePath,
   713  				Resources: map[string]*InstanceDiff{
   714  					"aws_instance.foo": &InstanceDiff{
   715  						Destroy: true,
   716  					},
   717  				},
   718  			},
   719  		},
   720  	}
   721  
   722  	g, err := Graph(&GraphOpts{Module: m, Diff: diff})
   723  	if err != nil {
   724  		t.Fatalf("err: %s", err)
   725  	}
   726  
   727  	actual := strings.TrimSpace(g.String())
   728  	expected := strings.TrimSpace(testTerraformGraphDiffModuleStr)
   729  	if actual != expected {
   730  		t.Fatalf("bad:\n\n%s", actual)
   731  	}
   732  }
   733  
   734  func TestGraphAddDiff_createBeforeDestroy(t *testing.T) {
   735  	m := testModule(t, "graph-diff-create-before")
   736  	diff := &Diff{
   737  		Modules: []*ModuleDiff{
   738  			&ModuleDiff{
   739  				Path: rootModulePath,
   740  				Resources: map[string]*InstanceDiff{
   741  					"aws_instance.bar": &InstanceDiff{
   742  						Destroy: true,
   743  						Attributes: map[string]*ResourceAttrDiff{
   744  							"ami": &ResourceAttrDiff{
   745  								Old:         "abc",
   746  								New:         "xyz",
   747  								RequiresNew: true,
   748  							},
   749  						},
   750  					},
   751  				},
   752  			},
   753  		},
   754  	}
   755  	state := &State{
   756  		Modules: []*ModuleState{
   757  			&ModuleState{
   758  				Path: rootModulePath,
   759  				Resources: map[string]*ResourceState{
   760  					"aws_instance.bar": &ResourceState{
   761  						Type: "aws_instance",
   762  						Primary: &InstanceState{
   763  							ID: "bar",
   764  							Attributes: map[string]string{
   765  								"ami": "abc",
   766  							},
   767  						},
   768  					},
   769  				},
   770  			},
   771  		},
   772  	}
   773  
   774  	diffHash := checksumStruct(t, diff)
   775  
   776  	g, err := Graph(&GraphOpts{
   777  		Module: m,
   778  		Diff:   diff,
   779  		State:  state,
   780  	})
   781  	if err != nil {
   782  		t.Fatalf("err: %s", err)
   783  	}
   784  
   785  	actual := strings.TrimSpace(g.String())
   786  	expected := strings.TrimSpace(testTerraformGraphDiffCreateBeforeDestroyStr)
   787  	if actual != expected {
   788  		t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actual, expected)
   789  	}
   790  
   791  	// Verify the flags are set
   792  	r := g.Noun("aws_instance.bar")
   793  	if r.Meta.(*GraphNodeResource).Resource.Flags&FlagReplacePrimary == 0 {
   794  		t.Fatalf("missing FlagReplacePrimary")
   795  	}
   796  
   797  	r = g.Noun("aws_instance.bar (destroy)")
   798  	if r.Meta.(*GraphNodeResource).Resource.Flags&FlagDeposed == 0 {
   799  		t.Fatalf("missing FlagDeposed")
   800  	}
   801  
   802  	// Verify that our original structure has not been modified
   803  	diffHash2 := checksumStruct(t, diff)
   804  	if diffHash != diffHash2 {
   805  		t.Fatal("diff has been modified")
   806  	}
   807  }
   808  
   809  func TestGraphAddDiff_moduleDestroy(t *testing.T) {
   810  	m := testModule(t, "graph-diff-module")
   811  	diff := &Diff{
   812  		Modules: []*ModuleDiff{
   813  			&ModuleDiff{
   814  				Path: rootModulePath,
   815  				Resources: map[string]*InstanceDiff{
   816  					"aws_instance.foo": &InstanceDiff{
   817  						Destroy: true,
   818  					},
   819  				},
   820  			},
   821  			&ModuleDiff{
   822  				Path: []string{"root", "child"},
   823  				Resources: map[string]*InstanceDiff{
   824  					"aws_instance.foo": &InstanceDiff{
   825  						Destroy: true,
   826  					},
   827  				},
   828  			},
   829  		},
   830  	}
   831  
   832  	g, err := Graph(&GraphOpts{Module: m, Diff: diff})
   833  	if err != nil {
   834  		t.Fatalf("err: %s", err)
   835  	}
   836  
   837  	actual := strings.TrimSpace(g.String())
   838  	expected := strings.TrimSpace(testTerraformGraphDiffModuleStr)
   839  	if actual != expected {
   840  		t.Fatalf("bad:\n\n%s", actual)
   841  	}
   842  }
   843  
   844  func TestGraphEncodeDependencies(t *testing.T) {
   845  	m := testModule(t, "graph-basic")
   846  
   847  	g, err := Graph(&GraphOpts{Module: m})
   848  	if err != nil {
   849  		t.Fatalf("err: %s", err)
   850  	}
   851  
   852  	// This should encode the dependency information into the state
   853  	graphEncodeDependencies(g)
   854  
   855  	web := g.Noun("aws_instance.web").Meta.(*GraphNodeResource).Resource
   856  	if len(web.Dependencies) != 1 || web.Dependencies[0] != "aws_security_group.firewall" {
   857  		t.Fatalf("bad: %#v", web)
   858  	}
   859  
   860  	weblb := g.Noun("aws_load_balancer.weblb").Meta.(*GraphNodeResource).Resource
   861  	if len(weblb.Dependencies) != 1 || weblb.Dependencies[0] != "aws_instance.web" {
   862  		t.Fatalf("bad: %#v", weblb)
   863  	}
   864  }
   865  
   866  func TestGraphEncodeDependencies_count(t *testing.T) {
   867  	m := testModule(t, "graph-count")
   868  	state := &State{
   869  		Modules: []*ModuleState{
   870  			&ModuleState{
   871  				Path: rootModulePath,
   872  				Resources: map[string]*ResourceState{
   873  					"aws_instance.web.0": &ResourceState{
   874  						Type: "aws_instance",
   875  						Primary: &InstanceState{
   876  							ID: "foo",
   877  						},
   878  					},
   879  					"aws_load_balancer.weblb": &ResourceState{
   880  						Type: "aws_load_balancer",
   881  						Primary: &InstanceState{
   882  							ID: "foo",
   883  						},
   884  					},
   885  				},
   886  			},
   887  		},
   888  	}
   889  
   890  	g, err := Graph(&GraphOpts{Module: m, State: state})
   891  	if err != nil {
   892  		t.Fatalf("err: %s", err)
   893  	}
   894  
   895  	// This should encode the dependency information into the state
   896  	graphEncodeDependencies(g)
   897  
   898  	web := g.Noun("aws_instance.web").Meta.(*GraphNodeResource).Resource
   899  	if len(web.Dependencies) != 0 {
   900  		t.Fatalf("bad: %#v", web)
   901  	}
   902  
   903  	weblb := g.Noun("aws_load_balancer.weblb").Meta.(*GraphNodeResource).Resource
   904  	if len(weblb.Dependencies) != 1 {
   905  		t.Fatalf("bad: %#v", weblb)
   906  	}
   907  }
   908  
   909  func TestGraphEncodeDependencies_module(t *testing.T) {
   910  	m := testModule(t, "graph-modules")
   911  
   912  	g, err := Graph(&GraphOpts{Module: m})
   913  	if err != nil {
   914  		t.Fatalf("err: %s", err)
   915  	}
   916  
   917  	// This should encode the dependency information into the state
   918  	graphEncodeDependencies(g)
   919  
   920  	web := g.Noun("aws_instance.web").Meta.(*GraphNodeResource).Resource
   921  	sort.Strings(web.Dependencies)
   922  	if len(web.Dependencies) != 2 {
   923  		t.Fatalf("bad: %#v", web)
   924  	}
   925  	if web.Dependencies[0] != "aws_security_group.firewall" {
   926  		t.Fatalf("bad: %#v", web)
   927  	}
   928  	if web.Dependencies[1] != "module.consul" {
   929  		t.Fatalf("bad: %#v", web)
   930  	}
   931  }
   932  
   933  func TestGraph_orphan_dependencies(t *testing.T) {
   934  	m := testModule(t, "graph-count")
   935  	state := &State{
   936  		Modules: []*ModuleState{
   937  			&ModuleState{
   938  				Path: rootModulePath,
   939  
   940  				Resources: map[string]*ResourceState{
   941  					"aws_instance.web.0": &ResourceState{
   942  						Type: "aws_instance",
   943  						Primary: &InstanceState{
   944  							ID: "foo",
   945  						},
   946  					},
   947  					"aws_instance.web.1": &ResourceState{
   948  						Type: "aws_instance",
   949  						Primary: &InstanceState{
   950  							ID: "foo",
   951  						},
   952  					},
   953  					"aws_load_balancer.old": &ResourceState{
   954  						Type: "aws_load_balancer",
   955  						Primary: &InstanceState{
   956  							ID: "foo",
   957  						},
   958  						Dependencies: []string{
   959  							"aws_instance.web.0",
   960  							"aws_instance.web.1",
   961  							"aws_instance.web.2",
   962  						},
   963  					},
   964  				},
   965  			},
   966  		},
   967  	}
   968  
   969  	g, err := Graph(&GraphOpts{Module: m, State: state})
   970  	if err != nil {
   971  		t.Fatalf("err: %s", err)
   972  	}
   973  
   974  	actual := strings.TrimSpace(g.String())
   975  	expected := strings.TrimSpace(testTerraformGraphCountOrphanStr)
   976  	if actual != expected {
   977  		t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected)
   978  	}
   979  }
   980  
   981  func TestGraph_orphanDependenciesModules(t *testing.T) {
   982  	m := testModule(t, "graph-modules")
   983  	state := &State{
   984  		Modules: []*ModuleState{
   985  			&ModuleState{
   986  				Path: rootModulePath,
   987  
   988  				Resources: map[string]*ResourceState{
   989  					"aws_instance.foo": &ResourceState{
   990  						Type: "aws_instance",
   991  						Primary: &InstanceState{
   992  							ID: "foo",
   993  						},
   994  						Dependencies: []string{
   995  							"module.consul",
   996  						},
   997  					},
   998  				},
   999  			},
  1000  		},
  1001  	}
  1002  
  1003  	g, err := Graph(&GraphOpts{Module: m, State: state})
  1004  	if err != nil {
  1005  		t.Fatalf("err: %s", err)
  1006  	}
  1007  
  1008  	actual := strings.TrimSpace(g.String())
  1009  	expected := strings.TrimSpace(testTerraformGraphOrphanModuleDepsStr)
  1010  	if actual != expected {
  1011  		t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected)
  1012  	}
  1013  }
  1014  
  1015  func TestGraphNodeResourceExpand(t *testing.T) {
  1016  	m := testModule(t, "graph-resource-expand")
  1017  
  1018  	g, err := Graph(&GraphOpts{Module: m})
  1019  	if err != nil {
  1020  		t.Fatalf("err: %s", err)
  1021  	}
  1022  
  1023  	// Get the resource we care about expanding
  1024  	n := g.Noun("aws_instance.web")
  1025  	if n == nil {
  1026  		t.Fatal("could not find")
  1027  	}
  1028  	rn := n.Meta.(*GraphNodeResource)
  1029  
  1030  	g, err = rn.Expand()
  1031  	if err != nil {
  1032  		t.Fatalf("err: %s", err)
  1033  	}
  1034  
  1035  	actual := strings.TrimSpace(g.String())
  1036  	expected := strings.TrimSpace(testTerraformGraphResourceExpandStr)
  1037  	if actual != expected {
  1038  		t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected)
  1039  	}
  1040  }
  1041  
  1042  func TestGraphNodeResourceExpand_provDeps(t *testing.T) {
  1043  	m := testModule(t, "graph-resource-expand-prov-deps")
  1044  	provs := map[string]ResourceProvisionerFactory{
  1045  		"remote-exec": func() (ResourceProvisioner, error) {
  1046  			return new(MockResourceProvisioner), nil
  1047  		},
  1048  	}
  1049  
  1050  	g, err := Graph(&GraphOpts{Module: m, Provisioners: provs})
  1051  	if err != nil {
  1052  		t.Fatalf("err: %s", err)
  1053  	}
  1054  
  1055  	// Get the resource we care about expanding
  1056  	n := g.Noun("aws_instance.web")
  1057  	if n == nil {
  1058  		t.Fatal("could not find")
  1059  	}
  1060  	rn := n.Meta.(*GraphNodeResource)
  1061  
  1062  	g, err = rn.Expand()
  1063  	if err != nil {
  1064  		t.Fatalf("err: %s", err)
  1065  	}
  1066  
  1067  	actual := strings.TrimSpace(g.String())
  1068  	expected := strings.TrimSpace(testTerraformGraphResourceExpandProvDepsStr)
  1069  	if actual != expected {
  1070  		t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected)
  1071  	}
  1072  }
  1073  
  1074  const testTerraformGraphStr = `
  1075  root: root
  1076  aws_instance.web
  1077    aws_instance.web -> aws_security_group.firewall
  1078    aws_instance.web -> provider.aws
  1079  aws_load_balancer.weblb
  1080    aws_load_balancer.weblb -> aws_instance.web
  1081    aws_load_balancer.weblb -> provider.aws
  1082  aws_security_group.firewall
  1083    aws_security_group.firewall -> provider.aws
  1084  openstack_floating_ip.random
  1085  provider.aws
  1086    provider.aws -> openstack_floating_ip.random
  1087  root
  1088    root -> aws_instance.web
  1089    root -> aws_load_balancer.weblb
  1090    root -> aws_security_group.firewall
  1091    root -> openstack_floating_ip.random
  1092  `
  1093  
  1094  const testTerraformGraphCountStr = `
  1095  root: root
  1096  aws_instance.web
  1097  aws_load_balancer.weblb
  1098    aws_load_balancer.weblb -> aws_instance.web
  1099  root
  1100    root -> aws_instance.web
  1101    root -> aws_load_balancer.weblb
  1102  `
  1103  
  1104  const testTerraformGraphCountTaintedStr = `
  1105  root: root
  1106  aws_instance.web
  1107    aws_instance.web -> aws_instance.web.0 (tainted #1)
  1108  aws_instance.web.0 (tainted #1)
  1109  aws_load_balancer.weblb
  1110    aws_load_balancer.weblb -> aws_instance.web
  1111  root
  1112    root -> aws_instance.web
  1113    root -> aws_instance.web.0 (tainted #1)
  1114    root -> aws_load_balancer.weblb
  1115  `
  1116  
  1117  const testTerraformGraphCountVarResourceStr = `
  1118  root: root
  1119  aws_instance.foo
  1120  aws_instance.web
  1121    aws_instance.web -> aws_instance.foo
  1122  aws_load_balancer.weblb
  1123    aws_load_balancer.weblb -> aws_instance.web
  1124  root
  1125    root -> aws_instance.foo
  1126    root -> aws_instance.web
  1127    root -> aws_load_balancer.weblb
  1128  `
  1129  
  1130  const testTerraformGraphDependsStr = `
  1131  root: root
  1132  aws_instance.db
  1133    aws_instance.db -> aws_instance.web
  1134  aws_instance.web
  1135  root
  1136    root -> aws_instance.db
  1137    root -> aws_instance.web
  1138  `
  1139  
  1140  const testTerraformGraphDependsCountStr = `
  1141  root: root
  1142  aws_instance.db
  1143    aws_instance.db -> aws_instance.web
  1144  aws_instance.web
  1145  root
  1146    root -> aws_instance.db
  1147    root -> aws_instance.web
  1148  `
  1149  
  1150  const testTerraformGraphDependsOrphanStr = `
  1151  root: root
  1152  aws_instance.db
  1153    aws_instance.db -> aws_instance.web
  1154  aws_instance.old
  1155  aws_instance.web
  1156  root
  1157    root -> aws_instance.db
  1158    root -> aws_instance.old
  1159    root -> aws_instance.web
  1160  `
  1161  
  1162  const testTerraformGraphDiffStr = `
  1163  root: root
  1164  aws_instance.foo
  1165  root
  1166    root -> aws_instance.foo
  1167  `
  1168  
  1169  const testTerraformGraphDiffDestroyStr = `
  1170  root: root
  1171  aws_instance.bar
  1172    aws_instance.bar -> aws_instance.bar (destroy)
  1173    aws_instance.bar -> aws_instance.foo
  1174    aws_instance.bar -> provider.aws
  1175  aws_instance.bar (destroy)
  1176    aws_instance.bar (destroy) -> provider.aws
  1177  aws_instance.foo
  1178    aws_instance.foo -> aws_instance.foo (destroy)
  1179    aws_instance.foo -> provider.aws
  1180  aws_instance.foo (destroy)
  1181    aws_instance.foo (destroy) -> aws_instance.bar (destroy)
  1182    aws_instance.foo (destroy) -> provider.aws
  1183  provider.aws
  1184  root
  1185    root -> aws_instance.bar
  1186    root -> aws_instance.foo
  1187  `
  1188  
  1189  const testTerraformGraphDiffDestroyCountsStr = `
  1190  root: root
  1191  aws_instance.web
  1192    aws_instance.web -> aws_instance.web (destroy)
  1193  aws_instance.web (destroy)
  1194    aws_instance.web (destroy) -> aws_load_balancer.weblb (destroy)
  1195  aws_load_balancer.weblb
  1196    aws_load_balancer.weblb -> aws_instance.web
  1197    aws_load_balancer.weblb -> aws_load_balancer.weblb (destroy)
  1198  aws_load_balancer.weblb (destroy)
  1199  root
  1200    root -> aws_instance.web
  1201    root -> aws_load_balancer.weblb
  1202  `
  1203  
  1204  const testTerraformGraphDiffModuleStr = `
  1205  root: root
  1206  aws_instance.foo
  1207    aws_instance.foo -> aws_instance.foo (destroy)
  1208    aws_instance.foo -> module.child
  1209  aws_instance.foo (destroy)
  1210  module.child
  1211    module.child -> aws_instance.foo (destroy)
  1212  root
  1213    root -> aws_instance.foo
  1214    root -> module.child
  1215  `
  1216  
  1217  const testTerraformGraphModulesStr = `
  1218  root: root
  1219  aws_instance.web
  1220    aws_instance.web -> aws_security_group.firewall
  1221    aws_instance.web -> module.consul
  1222    aws_instance.web -> provider.aws
  1223  aws_security_group.firewall
  1224    aws_security_group.firewall -> provider.aws
  1225  module.consul
  1226    module.consul -> aws_security_group.firewall
  1227    module.consul -> provider.aws
  1228  provider.aws
  1229  root
  1230    root -> aws_instance.web
  1231    root -> aws_security_group.firewall
  1232    root -> module.consul
  1233  `
  1234  
  1235  const testTerraformGraphModulesConsulStr = `
  1236  root: root
  1237  aws_instance.server
  1238    aws_instance.server -> provider.aws
  1239  provider.aws
  1240  root
  1241    root -> aws_instance.server
  1242  `
  1243  
  1244  const testTerraformGraphModuleOrphanStr = `
  1245  root: root
  1246  aws_instance.web
  1247    aws_instance.web -> aws_security_group.firewall
  1248    aws_instance.web -> provider.aws
  1249  aws_security_group.firewall
  1250    aws_security_group.firewall -> provider.aws
  1251  module.consul
  1252    module.consul -> provider.aws
  1253  provider.aws
  1254  root
  1255    root -> aws_instance.web
  1256    root -> aws_security_group.firewall
  1257    root -> module.consul
  1258  `
  1259  
  1260  const testTerraformGraphModuleOrphanConsulStr = `
  1261  root: root
  1262  aws_instance.old
  1263    aws_instance.old -> provider.aws
  1264  provider.aws
  1265  root
  1266    root -> aws_instance.old
  1267  `
  1268  
  1269  const testTerraformGraphProviderPruneStr = `
  1270  root: root
  1271  aws_load_balancer.weblb
  1272    aws_load_balancer.weblb -> provider.aws
  1273  provider.aws
  1274  root
  1275    root -> aws_load_balancer.weblb`
  1276  
  1277  const testTerraformGraphDiffCreateBeforeDestroyStr = `
  1278  root: root
  1279  aws_instance.bar
  1280    aws_instance.bar -> provider.aws
  1281  aws_instance.bar (destroy)
  1282    aws_instance.bar (destroy) -> aws_instance.bar
  1283    aws_instance.bar (destroy) -> provider.aws
  1284  provider.aws
  1285  root
  1286    root -> aws_instance.bar
  1287    root -> aws_instance.bar (destroy)`
  1288  
  1289  const testTerraformGraphStateStr = `
  1290  root: root
  1291  aws_instance.old
  1292    aws_instance.old -> provider.aws
  1293  aws_instance.web
  1294    aws_instance.web -> aws_security_group.firewall
  1295    aws_instance.web -> provider.aws
  1296  aws_load_balancer.weblb
  1297    aws_load_balancer.weblb -> aws_instance.web
  1298    aws_load_balancer.weblb -> provider.aws
  1299  aws_security_group.firewall
  1300    aws_security_group.firewall -> provider.aws
  1301  openstack_floating_ip.random
  1302  provider.aws
  1303    provider.aws -> openstack_floating_ip.random
  1304  root
  1305    root -> aws_instance.old
  1306    root -> aws_instance.web
  1307    root -> aws_load_balancer.weblb
  1308    root -> aws_security_group.firewall
  1309    root -> openstack_floating_ip.random
  1310  `
  1311  
  1312  const testTerraformGraphTaintedStr = `
  1313  root: root
  1314  aws_instance.web
  1315    aws_instance.web -> aws_instance.web (tainted #1)
  1316    aws_instance.web -> aws_security_group.firewall
  1317    aws_instance.web -> provider.aws
  1318  aws_instance.web (tainted #1)
  1319    aws_instance.web (tainted #1) -> provider.aws
  1320  aws_security_group.firewall
  1321    aws_security_group.firewall -> provider.aws
  1322  provider.aws
  1323  root
  1324    root -> aws_instance.web
  1325    root -> aws_instance.web (tainted #1)
  1326    root -> aws_security_group.firewall
  1327  `
  1328  
  1329  const testTerraformGraphTaintedMultiStr = `
  1330  root: root
  1331  aws_instance.web
  1332    aws_instance.web -> aws_instance.web (tainted #1)
  1333    aws_instance.web -> aws_instance.web (tainted #2)
  1334    aws_instance.web -> aws_security_group.firewall
  1335    aws_instance.web -> provider.aws
  1336  aws_instance.web (tainted #1)
  1337    aws_instance.web (tainted #1) -> provider.aws
  1338  aws_instance.web (tainted #2)
  1339    aws_instance.web (tainted #2) -> provider.aws
  1340  aws_security_group.firewall
  1341    aws_security_group.firewall -> provider.aws
  1342  provider.aws
  1343  root
  1344    root -> aws_instance.web
  1345    root -> aws_instance.web (tainted #1)
  1346    root -> aws_instance.web (tainted #2)
  1347    root -> aws_security_group.firewall
  1348  `
  1349  
  1350  const testTerraformGraphCountOrphanStr = `
  1351  root: root
  1352  aws_instance.web
  1353  aws_load_balancer.old
  1354    aws_load_balancer.old -> aws_instance.web
  1355  aws_load_balancer.weblb
  1356    aws_load_balancer.weblb -> aws_instance.web
  1357  root
  1358    root -> aws_instance.web
  1359    root -> aws_load_balancer.old
  1360    root -> aws_load_balancer.weblb
  1361  `
  1362  
  1363  const testTerraformGraphOrphanModuleDepsStr = `
  1364  root: root
  1365  aws_instance.foo
  1366    aws_instance.foo -> module.consul
  1367    aws_instance.foo -> provider.aws
  1368  aws_instance.web
  1369    aws_instance.web -> aws_security_group.firewall
  1370    aws_instance.web -> module.consul
  1371    aws_instance.web -> provider.aws
  1372  aws_security_group.firewall
  1373    aws_security_group.firewall -> provider.aws
  1374  module.consul
  1375    module.consul -> aws_security_group.firewall
  1376    module.consul -> provider.aws
  1377  provider.aws
  1378  root
  1379    root -> aws_instance.foo
  1380    root -> aws_instance.web
  1381    root -> aws_security_group.firewall
  1382    root -> module.consul
  1383  `
  1384  
  1385  const testTerraformGraphResourceExpandStr = `
  1386  root: root
  1387  aws_instance.web.0
  1388  aws_instance.web.1
  1389  aws_instance.web.2
  1390  root
  1391    root -> aws_instance.web.0
  1392    root -> aws_instance.web.1
  1393    root -> aws_instance.web.2
  1394  `
  1395  
  1396  const testTerraformGraphResourceExpandProvDepsStr = `
  1397  root: root
  1398  aws_instance.web.0
  1399  aws_instance.web.1
  1400    aws_instance.web.1 -> aws_instance.web.0
  1401  aws_instance.web.2
  1402    aws_instance.web.2 -> aws_instance.web.0
  1403  root
  1404    root -> aws_instance.web.0
  1405    root -> aws_instance.web.1
  1406    root -> aws_instance.web.2
  1407  `