github.com/rmenn/terraform@v0.3.8-0.20150225065417-fc84b3a78802/terraform/diff_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"testing"
     7  )
     8  
     9  func TestDiffEmpty(t *testing.T) {
    10  	diff := new(Diff)
    11  	if !diff.Empty() {
    12  		t.Fatal("should be empty")
    13  	}
    14  
    15  	mod := diff.AddModule(rootModulePath)
    16  	mod.Resources["nodeA"] = &InstanceDiff{
    17  		Attributes: map[string]*ResourceAttrDiff{
    18  			"foo": &ResourceAttrDiff{
    19  				Old: "foo",
    20  				New: "bar",
    21  			},
    22  		},
    23  	}
    24  
    25  	if diff.Empty() {
    26  		t.Fatal("should not be empty")
    27  	}
    28  }
    29  
    30  func TestModuleDiff_ChangeType(t *testing.T) {
    31  	cases := []struct {
    32  		Diff   *ModuleDiff
    33  		Result DiffChangeType
    34  	}{
    35  		{
    36  			&ModuleDiff{},
    37  			DiffNone,
    38  		},
    39  		{
    40  			&ModuleDiff{
    41  				Resources: map[string]*InstanceDiff{
    42  					"foo": &InstanceDiff{Destroy: true},
    43  				},
    44  			},
    45  			DiffDestroy,
    46  		},
    47  		{
    48  			&ModuleDiff{
    49  				Resources: map[string]*InstanceDiff{
    50  					"foo": &InstanceDiff{
    51  						Attributes: map[string]*ResourceAttrDiff{
    52  							"foo": &ResourceAttrDiff{
    53  								Old: "",
    54  								New: "bar",
    55  							},
    56  						},
    57  					},
    58  				},
    59  			},
    60  			DiffUpdate,
    61  		},
    62  		{
    63  			&ModuleDiff{
    64  				Resources: map[string]*InstanceDiff{
    65  					"foo": &InstanceDiff{
    66  						Attributes: map[string]*ResourceAttrDiff{
    67  							"foo": &ResourceAttrDiff{
    68  								Old:         "",
    69  								New:         "bar",
    70  								RequiresNew: true,
    71  							},
    72  						},
    73  					},
    74  				},
    75  			},
    76  			DiffCreate,
    77  		},
    78  		{
    79  			&ModuleDiff{
    80  				Resources: map[string]*InstanceDiff{
    81  					"foo": &InstanceDiff{
    82  						Destroy: true,
    83  						Attributes: map[string]*ResourceAttrDiff{
    84  							"foo": &ResourceAttrDiff{
    85  								Old:         "",
    86  								New:         "bar",
    87  								RequiresNew: true,
    88  							},
    89  						},
    90  					},
    91  				},
    92  			},
    93  			DiffUpdate,
    94  		},
    95  	}
    96  
    97  	for i, tc := range cases {
    98  		actual := tc.Diff.ChangeType()
    99  		if actual != tc.Result {
   100  			t.Fatalf("%d: %#v", i, actual)
   101  		}
   102  	}
   103  }
   104  
   105  func TestModuleDiff_Empty(t *testing.T) {
   106  	diff := new(ModuleDiff)
   107  	if !diff.Empty() {
   108  		t.Fatal("should be empty")
   109  	}
   110  
   111  	diff.Resources = map[string]*InstanceDiff{
   112  		"nodeA": &InstanceDiff{},
   113  	}
   114  
   115  	if !diff.Empty() {
   116  		t.Fatal("should be empty")
   117  	}
   118  
   119  	diff.Resources["nodeA"].Attributes = map[string]*ResourceAttrDiff{
   120  		"foo": &ResourceAttrDiff{
   121  			Old: "foo",
   122  			New: "bar",
   123  		},
   124  	}
   125  
   126  	if diff.Empty() {
   127  		t.Fatal("should not be empty")
   128  	}
   129  
   130  	diff.Resources["nodeA"].Attributes = nil
   131  	diff.Resources["nodeA"].Destroy = true
   132  
   133  	if diff.Empty() {
   134  		t.Fatal("should not be empty")
   135  	}
   136  }
   137  
   138  func TestModuleDiff_String(t *testing.T) {
   139  	diff := &ModuleDiff{
   140  		Resources: map[string]*InstanceDiff{
   141  			"nodeA": &InstanceDiff{
   142  				Attributes: map[string]*ResourceAttrDiff{
   143  					"foo": &ResourceAttrDiff{
   144  						Old: "foo",
   145  						New: "bar",
   146  					},
   147  					"bar": &ResourceAttrDiff{
   148  						Old:         "foo",
   149  						NewComputed: true,
   150  					},
   151  					"longfoo": &ResourceAttrDiff{
   152  						Old:         "foo",
   153  						New:         "bar",
   154  						RequiresNew: true,
   155  					},
   156  				},
   157  			},
   158  		},
   159  	}
   160  
   161  	actual := strings.TrimSpace(diff.String())
   162  	expected := strings.TrimSpace(moduleDiffStrBasic)
   163  	if actual != expected {
   164  		t.Fatalf("bad:\n%s", actual)
   165  	}
   166  }
   167  
   168  func TestInstanceDiff_ChangeType(t *testing.T) {
   169  	cases := []struct {
   170  		Diff   *InstanceDiff
   171  		Result DiffChangeType
   172  	}{
   173  		{
   174  			&InstanceDiff{},
   175  			DiffNone,
   176  		},
   177  		{
   178  			&InstanceDiff{Destroy: true},
   179  			DiffDestroy,
   180  		},
   181  		{
   182  			&InstanceDiff{
   183  				Attributes: map[string]*ResourceAttrDiff{
   184  					"foo": &ResourceAttrDiff{
   185  						Old: "",
   186  						New: "bar",
   187  					},
   188  				},
   189  			},
   190  			DiffUpdate,
   191  		},
   192  		{
   193  			&InstanceDiff{
   194  				Attributes: map[string]*ResourceAttrDiff{
   195  					"foo": &ResourceAttrDiff{
   196  						Old:         "",
   197  						New:         "bar",
   198  						RequiresNew: true,
   199  					},
   200  				},
   201  			},
   202  			DiffCreate,
   203  		},
   204  		{
   205  			&InstanceDiff{
   206  				Destroy: true,
   207  				Attributes: map[string]*ResourceAttrDiff{
   208  					"foo": &ResourceAttrDiff{
   209  						Old:         "",
   210  						New:         "bar",
   211  						RequiresNew: true,
   212  					},
   213  				},
   214  			},
   215  			DiffDestroyCreate,
   216  		},
   217  		{
   218  			&InstanceDiff{
   219  				DestroyTainted: true,
   220  				Attributes: map[string]*ResourceAttrDiff{
   221  					"foo": &ResourceAttrDiff{
   222  						Old:         "",
   223  						New:         "bar",
   224  						RequiresNew: true,
   225  					},
   226  				},
   227  			},
   228  			DiffDestroyCreate,
   229  		},
   230  	}
   231  
   232  	for i, tc := range cases {
   233  		actual := tc.Diff.ChangeType()
   234  		if actual != tc.Result {
   235  			t.Fatalf("%d: %#v", i, actual)
   236  		}
   237  	}
   238  }
   239  
   240  func TestInstanceDiff_Empty(t *testing.T) {
   241  	var rd *InstanceDiff
   242  
   243  	if !rd.Empty() {
   244  		t.Fatal("should be empty")
   245  	}
   246  
   247  	rd = new(InstanceDiff)
   248  
   249  	if !rd.Empty() {
   250  		t.Fatal("should be empty")
   251  	}
   252  
   253  	rd = &InstanceDiff{Destroy: true}
   254  
   255  	if rd.Empty() {
   256  		t.Fatal("should not be empty")
   257  	}
   258  
   259  	rd = &InstanceDiff{
   260  		Attributes: map[string]*ResourceAttrDiff{
   261  			"foo": &ResourceAttrDiff{
   262  				New: "bar",
   263  			},
   264  		},
   265  	}
   266  
   267  	if rd.Empty() {
   268  		t.Fatal("should not be empty")
   269  	}
   270  }
   271  
   272  func TestModuleDiff_Instances(t *testing.T) {
   273  	yesDiff := &InstanceDiff{Destroy: true}
   274  	noDiff := &InstanceDiff{Destroy: true, DestroyTainted: true}
   275  
   276  	cases := []struct {
   277  		Diff   *ModuleDiff
   278  		Id     string
   279  		Result []*InstanceDiff
   280  	}{
   281  		{
   282  			&ModuleDiff{
   283  				Resources: map[string]*InstanceDiff{
   284  					"foo": yesDiff,
   285  					"bar": noDiff,
   286  				},
   287  			},
   288  			"foo",
   289  			[]*InstanceDiff{
   290  				yesDiff,
   291  			},
   292  		},
   293  
   294  		{
   295  			&ModuleDiff{
   296  				Resources: map[string]*InstanceDiff{
   297  					"foo":   yesDiff,
   298  					"foo.0": yesDiff,
   299  					"bar":   noDiff,
   300  				},
   301  			},
   302  			"foo",
   303  			[]*InstanceDiff{
   304  				yesDiff,
   305  				yesDiff,
   306  			},
   307  		},
   308  
   309  		{
   310  			&ModuleDiff{
   311  				Resources: map[string]*InstanceDiff{
   312  					"foo":     yesDiff,
   313  					"foo.0":   yesDiff,
   314  					"foo_bar": noDiff,
   315  					"bar":     noDiff,
   316  				},
   317  			},
   318  			"foo",
   319  			[]*InstanceDiff{
   320  				yesDiff,
   321  				yesDiff,
   322  			},
   323  		},
   324  	}
   325  
   326  	for i, tc := range cases {
   327  		actual := tc.Diff.Instances(tc.Id)
   328  		if !reflect.DeepEqual(actual, tc.Result) {
   329  			t.Fatalf("%d: %#v", i, actual)
   330  		}
   331  	}
   332  }
   333  
   334  func TestInstanceDiff_RequiresNew(t *testing.T) {
   335  	rd := &InstanceDiff{
   336  		Attributes: map[string]*ResourceAttrDiff{
   337  			"foo": &ResourceAttrDiff{},
   338  		},
   339  	}
   340  
   341  	if rd.RequiresNew() {
   342  		t.Fatal("should not require new")
   343  	}
   344  
   345  	rd.Attributes["foo"].RequiresNew = true
   346  
   347  	if !rd.RequiresNew() {
   348  		t.Fatal("should require new")
   349  	}
   350  }
   351  
   352  func TestInstanceDiff_RequiresNew_nil(t *testing.T) {
   353  	var rd *InstanceDiff
   354  
   355  	if rd.RequiresNew() {
   356  		t.Fatal("should not require new")
   357  	}
   358  }
   359  
   360  func TestInstanceDiffSame(t *testing.T) {
   361  	cases := []struct {
   362  		One, Two *InstanceDiff
   363  		Same     bool
   364  	}{
   365  		{
   366  			&InstanceDiff{},
   367  			&InstanceDiff{},
   368  			true,
   369  		},
   370  
   371  		{
   372  			nil,
   373  			nil,
   374  			true,
   375  		},
   376  
   377  		{
   378  			&InstanceDiff{Destroy: false},
   379  			&InstanceDiff{Destroy: true},
   380  			false,
   381  		},
   382  
   383  		{
   384  			&InstanceDiff{Destroy: true},
   385  			&InstanceDiff{Destroy: true},
   386  			true,
   387  		},
   388  
   389  		{
   390  			&InstanceDiff{
   391  				Attributes: map[string]*ResourceAttrDiff{
   392  					"foo": &ResourceAttrDiff{},
   393  				},
   394  			},
   395  			&InstanceDiff{
   396  				Attributes: map[string]*ResourceAttrDiff{
   397  					"foo": &ResourceAttrDiff{},
   398  				},
   399  			},
   400  			true,
   401  		},
   402  
   403  		{
   404  			&InstanceDiff{
   405  				Attributes: map[string]*ResourceAttrDiff{
   406  					"bar": &ResourceAttrDiff{},
   407  				},
   408  			},
   409  			&InstanceDiff{
   410  				Attributes: map[string]*ResourceAttrDiff{
   411  					"foo": &ResourceAttrDiff{},
   412  				},
   413  			},
   414  			false,
   415  		},
   416  
   417  		// Extra attributes
   418  		{
   419  			&InstanceDiff{
   420  				Attributes: map[string]*ResourceAttrDiff{
   421  					"foo": &ResourceAttrDiff{},
   422  				},
   423  			},
   424  			&InstanceDiff{
   425  				Attributes: map[string]*ResourceAttrDiff{
   426  					"foo": &ResourceAttrDiff{},
   427  					"bar": &ResourceAttrDiff{},
   428  				},
   429  			},
   430  			false,
   431  		},
   432  
   433  		{
   434  			&InstanceDiff{
   435  				Attributes: map[string]*ResourceAttrDiff{
   436  					"foo": &ResourceAttrDiff{RequiresNew: true},
   437  				},
   438  			},
   439  			&InstanceDiff{
   440  				Attributes: map[string]*ResourceAttrDiff{
   441  					"foo": &ResourceAttrDiff{RequiresNew: false},
   442  				},
   443  			},
   444  			false,
   445  		},
   446  
   447  		{
   448  			&InstanceDiff{
   449  				Attributes: map[string]*ResourceAttrDiff{
   450  					"foo.#": &ResourceAttrDiff{NewComputed: true},
   451  				},
   452  			},
   453  			&InstanceDiff{
   454  				Attributes: map[string]*ResourceAttrDiff{
   455  					"foo.#": &ResourceAttrDiff{
   456  						Old: "0",
   457  						New: "1",
   458  					},
   459  					"foo.0": &ResourceAttrDiff{
   460  						Old: "",
   461  						New: "12",
   462  					},
   463  				},
   464  			},
   465  			true,
   466  		},
   467  
   468  		{
   469  			&InstanceDiff{
   470  				Attributes: map[string]*ResourceAttrDiff{
   471  					"foo.#": &ResourceAttrDiff{
   472  						Old: "0",
   473  						New: "1",
   474  					},
   475  					"foo.~35964334.bar": &ResourceAttrDiff{
   476  						Old: "",
   477  						New: "${var.foo}",
   478  					},
   479  				},
   480  			},
   481  			&InstanceDiff{
   482  				Attributes: map[string]*ResourceAttrDiff{
   483  					"foo.#": &ResourceAttrDiff{
   484  						Old: "0",
   485  						New: "1",
   486  					},
   487  					"foo.87654323.bar": &ResourceAttrDiff{
   488  						Old: "",
   489  						New: "12",
   490  					},
   491  				},
   492  			},
   493  			true,
   494  		},
   495  
   496  		{
   497  			&InstanceDiff{
   498  				Attributes: map[string]*ResourceAttrDiff{
   499  					"foo.#": &ResourceAttrDiff{
   500  						Old:         "0",
   501  						NewComputed: true,
   502  					},
   503  				},
   504  			},
   505  			&InstanceDiff{
   506  				Attributes: map[string]*ResourceAttrDiff{},
   507  			},
   508  			true,
   509  		},
   510  	}
   511  
   512  	for i, tc := range cases {
   513  		actual := tc.One.Same(tc.Two)
   514  		if actual != tc.Same {
   515  			t.Fatalf("%d:\n\n%#v\n\n%#v", i, tc.One, tc.Two)
   516  		}
   517  	}
   518  }
   519  
   520  const moduleDiffStrBasic = `
   521  CREATE: nodeA
   522    bar:     "foo" => "<computed>"
   523    foo:     "foo" => "bar"
   524    longfoo: "foo" => "bar" (forces new resource)
   525  `