github.com/jnehlt/terraform@v0.11.12-beta1/terraform/graph_builder_apply_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"testing"
     7  )
     8  
     9  func TestApplyGraphBuilder_impl(t *testing.T) {
    10  	var _ GraphBuilder = new(ApplyGraphBuilder)
    11  }
    12  
    13  func TestApplyGraphBuilder(t *testing.T) {
    14  	diff := &Diff{
    15  		Modules: []*ModuleDiff{
    16  			&ModuleDiff{
    17  				Path: []string{"root"},
    18  				Resources: map[string]*InstanceDiff{
    19  					// Verify noop doesn't show up in graph
    20  					"aws_instance.noop": &InstanceDiff{},
    21  
    22  					"aws_instance.create": &InstanceDiff{
    23  						Attributes: map[string]*ResourceAttrDiff{
    24  							"name": &ResourceAttrDiff{
    25  								Old: "",
    26  								New: "foo",
    27  							},
    28  						},
    29  					},
    30  
    31  					"aws_instance.other": &InstanceDiff{
    32  						Attributes: map[string]*ResourceAttrDiff{
    33  							"name": &ResourceAttrDiff{
    34  								Old: "",
    35  								New: "foo",
    36  							},
    37  						},
    38  					},
    39  				},
    40  			},
    41  
    42  			&ModuleDiff{
    43  				Path: []string{"root", "child"},
    44  				Resources: map[string]*InstanceDiff{
    45  					"aws_instance.create": &InstanceDiff{
    46  						Attributes: map[string]*ResourceAttrDiff{
    47  							"name": &ResourceAttrDiff{
    48  								Old: "",
    49  								New: "foo",
    50  							},
    51  						},
    52  					},
    53  
    54  					"aws_instance.other": &InstanceDiff{
    55  						Attributes: map[string]*ResourceAttrDiff{
    56  							"name": &ResourceAttrDiff{
    57  								Old: "",
    58  								New: "foo",
    59  							},
    60  						},
    61  					},
    62  				},
    63  			},
    64  		},
    65  	}
    66  
    67  	b := &ApplyGraphBuilder{
    68  		Module:        testModule(t, "graph-builder-apply-basic"),
    69  		Diff:          diff,
    70  		Providers:     []string{"aws"},
    71  		Provisioners:  []string{"exec"},
    72  		DisableReduce: true,
    73  	}
    74  
    75  	g, err := b.Build(RootModulePath)
    76  	if err != nil {
    77  		t.Fatalf("err: %s", err)
    78  	}
    79  
    80  	if !reflect.DeepEqual(g.Path, RootModulePath) {
    81  		t.Fatalf("bad: %#v", g.Path)
    82  	}
    83  
    84  	actual := strings.TrimSpace(g.String())
    85  	expected := strings.TrimSpace(testApplyGraphBuilderStr)
    86  	if actual != expected {
    87  		t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
    88  	}
    89  }
    90  
    91  // This tests the ordering of two resources where a non-CBD depends
    92  // on a CBD. GH-11349.
    93  func TestApplyGraphBuilder_depCbd(t *testing.T) {
    94  	diff := &Diff{
    95  		Modules: []*ModuleDiff{
    96  			&ModuleDiff{
    97  				Path: []string{"root"},
    98  				Resources: map[string]*InstanceDiff{"aws_instance.A": &InstanceDiff{Destroy: true,
    99  					Attributes: map[string]*ResourceAttrDiff{
   100  						"name": &ResourceAttrDiff{
   101  							Old:         "",
   102  							New:         "foo",
   103  							RequiresNew: true,
   104  						},
   105  					},
   106  				},
   107  
   108  					"aws_instance.B": &InstanceDiff{
   109  						Attributes: map[string]*ResourceAttrDiff{
   110  							"name": &ResourceAttrDiff{
   111  								Old: "",
   112  								New: "foo",
   113  							},
   114  						},
   115  					},
   116  				},
   117  			},
   118  		},
   119  	}
   120  
   121  	b := &ApplyGraphBuilder{
   122  		Module:        testModule(t, "graph-builder-apply-dep-cbd"),
   123  		Diff:          diff,
   124  		Providers:     []string{"aws"},
   125  		Provisioners:  []string{"exec"},
   126  		DisableReduce: true,
   127  	}
   128  
   129  	g, err := b.Build(RootModulePath)
   130  	if err != nil {
   131  		t.Fatalf("err: %s", err)
   132  	}
   133  	t.Logf("Graph: %s", g.String())
   134  
   135  	if !reflect.DeepEqual(g.Path, RootModulePath) {
   136  		t.Fatalf("bad: %#v", g.Path)
   137  	}
   138  
   139  	// Create A, Modify B, Destroy A
   140  
   141  	testGraphHappensBefore(
   142  		t, g,
   143  		"aws_instance.A",
   144  		"aws_instance.A (destroy)")
   145  	testGraphHappensBefore(
   146  		t, g,
   147  		"aws_instance.A",
   148  		"aws_instance.B")
   149  	testGraphHappensBefore(
   150  		t, g,
   151  		"aws_instance.B",
   152  		"aws_instance.A (destroy)")
   153  }
   154  
   155  // This tests the ordering of two resources that are both CBD that
   156  // require destroy/create.
   157  func TestApplyGraphBuilder_doubleCBD(t *testing.T) {
   158  	diff := &Diff{
   159  		Modules: []*ModuleDiff{
   160  			&ModuleDiff{
   161  				Path: []string{"root"},
   162  				Resources: map[string]*InstanceDiff{
   163  					"aws_instance.A": &InstanceDiff{
   164  						Destroy: true,
   165  						Attributes: map[string]*ResourceAttrDiff{
   166  							"name": &ResourceAttrDiff{
   167  								Old: "",
   168  								New: "foo",
   169  							},
   170  						},
   171  					},
   172  
   173  					"aws_instance.B": &InstanceDiff{
   174  						Destroy: true,
   175  						Attributes: map[string]*ResourceAttrDiff{
   176  							"name": &ResourceAttrDiff{
   177  								Old: "",
   178  								New: "foo",
   179  							},
   180  						},
   181  					},
   182  				},
   183  			},
   184  		},
   185  	}
   186  
   187  	b := &ApplyGraphBuilder{
   188  		Module:        testModule(t, "graph-builder-apply-double-cbd"),
   189  		Diff:          diff,
   190  		Providers:     []string{"aws"},
   191  		Provisioners:  []string{"exec"},
   192  		DisableReduce: true,
   193  	}
   194  
   195  	g, err := b.Build(RootModulePath)
   196  	if err != nil {
   197  		t.Fatalf("err: %s", err)
   198  	}
   199  
   200  	if !reflect.DeepEqual(g.Path, RootModulePath) {
   201  		t.Fatalf("bad: %#v", g.Path)
   202  	}
   203  
   204  	actual := strings.TrimSpace(g.String())
   205  	expected := strings.TrimSpace(testApplyGraphBuilderDoubleCBDStr)
   206  	if actual != expected {
   207  		t.Fatalf("bad: %s", actual)
   208  	}
   209  }
   210  
   211  // This tests the ordering of two resources being destroyed that depend
   212  // on each other from only state. GH-11749
   213  func TestApplyGraphBuilder_destroyStateOnly(t *testing.T) {
   214  	diff := &Diff{
   215  		Modules: []*ModuleDiff{
   216  			&ModuleDiff{
   217  				Path: []string{"root", "child"},
   218  				Resources: map[string]*InstanceDiff{
   219  					"aws_instance.A": &InstanceDiff{
   220  						Destroy: true,
   221  					},
   222  
   223  					"aws_instance.B": &InstanceDiff{
   224  						Destroy: true,
   225  					},
   226  				},
   227  			},
   228  		},
   229  	}
   230  
   231  	state := &State{
   232  		Modules: []*ModuleState{
   233  			&ModuleState{
   234  				Path: []string{"root", "child"},
   235  				Resources: map[string]*ResourceState{
   236  					"aws_instance.A": &ResourceState{
   237  						Type: "aws_instance",
   238  						Primary: &InstanceState{
   239  							ID:         "foo",
   240  							Attributes: map[string]string{},
   241  						},
   242  					},
   243  
   244  					"aws_instance.B": &ResourceState{
   245  						Type: "aws_instance",
   246  						Primary: &InstanceState{
   247  							ID:         "bar",
   248  							Attributes: map[string]string{},
   249  						},
   250  						Dependencies: []string{"aws_instance.A"},
   251  					},
   252  				},
   253  			},
   254  		},
   255  	}
   256  
   257  	b := &ApplyGraphBuilder{
   258  		Module:        testModule(t, "empty"),
   259  		Diff:          diff,
   260  		State:         state,
   261  		Providers:     []string{"aws"},
   262  		DisableReduce: true,
   263  	}
   264  
   265  	g, err := b.Build(RootModulePath)
   266  	if err != nil {
   267  		t.Fatalf("err: %s", err)
   268  	}
   269  	t.Logf("Graph: %s", g.String())
   270  
   271  	if !reflect.DeepEqual(g.Path, RootModulePath) {
   272  		t.Fatalf("bad: %#v", g.Path)
   273  	}
   274  
   275  	testGraphHappensBefore(
   276  		t, g,
   277  		"module.child.aws_instance.B (destroy)",
   278  		"module.child.aws_instance.A (destroy)")
   279  }
   280  
   281  // This tests the ordering of destroying a single count of a resource.
   282  func TestApplyGraphBuilder_destroyCount(t *testing.T) {
   283  	diff := &Diff{
   284  		Modules: []*ModuleDiff{
   285  			&ModuleDiff{
   286  				Path: []string{"root"},
   287  				Resources: map[string]*InstanceDiff{
   288  					"aws_instance.A.1": &InstanceDiff{
   289  						Destroy: true,
   290  					},
   291  
   292  					"aws_instance.B": &InstanceDiff{
   293  						Attributes: map[string]*ResourceAttrDiff{
   294  							"name": &ResourceAttrDiff{
   295  								Old: "",
   296  								New: "foo",
   297  							},
   298  						},
   299  					},
   300  				},
   301  			},
   302  		},
   303  	}
   304  
   305  	b := &ApplyGraphBuilder{
   306  		Module:        testModule(t, "graph-builder-apply-count"),
   307  		Diff:          diff,
   308  		Providers:     []string{"aws"},
   309  		Provisioners:  []string{"exec"},
   310  		DisableReduce: true,
   311  	}
   312  
   313  	g, err := b.Build(RootModulePath)
   314  	if err != nil {
   315  		t.Fatalf("err: %s", err)
   316  	}
   317  
   318  	if !reflect.DeepEqual(g.Path, RootModulePath) {
   319  		t.Fatalf("bad: %#v", g.Path)
   320  	}
   321  
   322  	actual := strings.TrimSpace(g.String())
   323  	expected := strings.TrimSpace(testApplyGraphBuilderDestroyCountStr)
   324  	if actual != expected {
   325  		t.Fatalf("bad: %s", actual)
   326  	}
   327  }
   328  
   329  func TestApplyGraphBuilder_moduleDestroy(t *testing.T) {
   330  	diff := &Diff{
   331  		Modules: []*ModuleDiff{
   332  			&ModuleDiff{
   333  				Path: []string{"root", "A"},
   334  				Resources: map[string]*InstanceDiff{
   335  					"null_resource.foo": &InstanceDiff{
   336  						Destroy: true,
   337  					},
   338  				},
   339  			},
   340  
   341  			&ModuleDiff{
   342  				Path: []string{"root", "B"},
   343  				Resources: map[string]*InstanceDiff{
   344  					"null_resource.foo": &InstanceDiff{
   345  						Destroy: true,
   346  					},
   347  				},
   348  			},
   349  		},
   350  	}
   351  
   352  	b := &ApplyGraphBuilder{
   353  		Module:    testModule(t, "graph-builder-apply-module-destroy"),
   354  		Diff:      diff,
   355  		Providers: []string{"null"},
   356  	}
   357  
   358  	g, err := b.Build(RootModulePath)
   359  	if err != nil {
   360  		t.Fatalf("err: %s", err)
   361  	}
   362  
   363  	testGraphHappensBefore(
   364  		t, g,
   365  		"module.B.null_resource.foo (destroy)",
   366  		"module.A.null_resource.foo (destroy)")
   367  }
   368  
   369  func TestApplyGraphBuilder_provisioner(t *testing.T) {
   370  	diff := &Diff{
   371  		Modules: []*ModuleDiff{
   372  			&ModuleDiff{
   373  				Path: []string{"root"},
   374  				Resources: map[string]*InstanceDiff{
   375  					"null_resource.foo": &InstanceDiff{
   376  						Attributes: map[string]*ResourceAttrDiff{
   377  							"name": &ResourceAttrDiff{
   378  								Old: "",
   379  								New: "foo",
   380  							},
   381  						},
   382  					},
   383  				},
   384  			},
   385  		},
   386  	}
   387  
   388  	b := &ApplyGraphBuilder{
   389  		Module:       testModule(t, "graph-builder-apply-provisioner"),
   390  		Diff:         diff,
   391  		Providers:    []string{"null"},
   392  		Provisioners: []string{"local"},
   393  	}
   394  
   395  	g, err := b.Build(RootModulePath)
   396  	if err != nil {
   397  		t.Fatalf("err: %s", err)
   398  	}
   399  
   400  	testGraphContains(t, g, "provisioner.local")
   401  	testGraphHappensBefore(
   402  		t, g,
   403  		"provisioner.local",
   404  		"null_resource.foo")
   405  }
   406  
   407  func TestApplyGraphBuilder_provisionerDestroy(t *testing.T) {
   408  	diff := &Diff{
   409  		Modules: []*ModuleDiff{
   410  			&ModuleDiff{
   411  				Path: []string{"root"},
   412  				Resources: map[string]*InstanceDiff{
   413  					"null_resource.foo": &InstanceDiff{
   414  						Destroy: true,
   415  					},
   416  				},
   417  			},
   418  		},
   419  	}
   420  
   421  	b := &ApplyGraphBuilder{
   422  		Destroy:      true,
   423  		Module:       testModule(t, "graph-builder-apply-provisioner"),
   424  		Diff:         diff,
   425  		Providers:    []string{"null"},
   426  		Provisioners: []string{"local"},
   427  	}
   428  
   429  	g, err := b.Build(RootModulePath)
   430  	if err != nil {
   431  		t.Fatalf("err: %s", err)
   432  	}
   433  
   434  	testGraphContains(t, g, "provisioner.local")
   435  	testGraphHappensBefore(
   436  		t, g,
   437  		"provisioner.local",
   438  		"null_resource.foo (destroy)")
   439  }
   440  
   441  func TestApplyGraphBuilder_targetModule(t *testing.T) {
   442  	diff := &Diff{
   443  		Modules: []*ModuleDiff{
   444  			&ModuleDiff{
   445  				Path: []string{"root"},
   446  				Resources: map[string]*InstanceDiff{
   447  					"null_resource.foo": &InstanceDiff{
   448  						Attributes: map[string]*ResourceAttrDiff{
   449  							"name": &ResourceAttrDiff{
   450  								Old: "",
   451  								New: "foo",
   452  							},
   453  						},
   454  					},
   455  				},
   456  			},
   457  
   458  			&ModuleDiff{
   459  				Path: []string{"root", "child2"},
   460  				Resources: map[string]*InstanceDiff{
   461  					"null_resource.foo": &InstanceDiff{
   462  						Attributes: map[string]*ResourceAttrDiff{
   463  							"name": &ResourceAttrDiff{
   464  								Old: "",
   465  								New: "foo",
   466  							},
   467  						},
   468  					},
   469  				},
   470  			},
   471  		},
   472  	}
   473  
   474  	b := &ApplyGraphBuilder{
   475  		Module:    testModule(t, "graph-builder-apply-target-module"),
   476  		Diff:      diff,
   477  		Providers: []string{"null"},
   478  		Targets:   []string{"module.child2"},
   479  	}
   480  
   481  	g, err := b.Build(RootModulePath)
   482  	if err != nil {
   483  		t.Fatalf("err: %s", err)
   484  	}
   485  
   486  	testGraphNotContains(t, g, "module.child1.output.instance_id")
   487  }
   488  
   489  const testApplyGraphBuilderStr = `
   490  aws_instance.create
   491    provider.aws
   492  aws_instance.other
   493    aws_instance.create
   494    provider.aws
   495  meta.count-boundary (count boundary fixup)
   496    aws_instance.create
   497    aws_instance.other
   498    module.child.aws_instance.create
   499    module.child.aws_instance.other
   500    module.child.provisioner.exec
   501    provider.aws
   502  module.child.aws_instance.create
   503    module.child.provisioner.exec
   504    provider.aws
   505  module.child.aws_instance.other
   506    module.child.aws_instance.create
   507    provider.aws
   508  module.child.provisioner.exec
   509  provider.aws
   510  provider.aws (close)
   511    aws_instance.create
   512    aws_instance.other
   513    module.child.aws_instance.create
   514    module.child.aws_instance.other
   515    provider.aws
   516  provisioner.exec (close)
   517    module.child.aws_instance.create
   518  root
   519    meta.count-boundary (count boundary fixup)
   520    provider.aws (close)
   521    provisioner.exec (close)
   522  `
   523  
   524  const testApplyGraphBuilderDoubleCBDStr = `
   525  aws_instance.A
   526    provider.aws
   527  aws_instance.A (destroy)
   528    aws_instance.A
   529    aws_instance.B
   530    aws_instance.B (destroy)
   531    provider.aws
   532  aws_instance.B
   533    aws_instance.A
   534    provider.aws
   535  aws_instance.B (destroy)
   536    aws_instance.B
   537    provider.aws
   538  meta.count-boundary (count boundary fixup)
   539    aws_instance.A
   540    aws_instance.A (destroy)
   541    aws_instance.B
   542    aws_instance.B (destroy)
   543    provider.aws
   544  provider.aws
   545  provider.aws (close)
   546    aws_instance.A
   547    aws_instance.A (destroy)
   548    aws_instance.B
   549    aws_instance.B (destroy)
   550    provider.aws
   551  root
   552    meta.count-boundary (count boundary fixup)
   553    provider.aws (close)
   554  `
   555  
   556  const testApplyGraphBuilderDestroyCountStr = `
   557  aws_instance.A[1] (destroy)
   558    provider.aws
   559  aws_instance.B
   560    aws_instance.A[1] (destroy)
   561    provider.aws
   562  meta.count-boundary (count boundary fixup)
   563    aws_instance.A[1] (destroy)
   564    aws_instance.B
   565    provider.aws
   566  provider.aws
   567  provider.aws (close)
   568    aws_instance.A[1] (destroy)
   569    aws_instance.B
   570    provider.aws
   571  root
   572    meta.count-boundary (count boundary fixup)
   573    provider.aws (close)
   574  `