github.com/maheshbr/terraform@v0.3.1-0.20141020033300-deec7194a3ea/terraform/state_test.go (about)

     1  package terraform
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"reflect"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/terraform/config"
    11  )
    12  
    13  func TestStateAddModule(t *testing.T) {
    14  	cases := []struct {
    15  		In  [][]string
    16  		Out [][]string
    17  	}{
    18  		{
    19  			[][]string{
    20  				[]string{"root"},
    21  				[]string{"root", "child"},
    22  			},
    23  			[][]string{
    24  				[]string{"root"},
    25  				[]string{"root", "child"},
    26  			},
    27  		},
    28  
    29  		{
    30  			[][]string{
    31  				[]string{"root", "foo", "bar"},
    32  				[]string{"root", "foo"},
    33  				[]string{"root"},
    34  				[]string{"root", "bar"},
    35  			},
    36  			[][]string{
    37  				[]string{"root"},
    38  				[]string{"root", "bar"},
    39  				[]string{"root", "foo"},
    40  				[]string{"root", "foo", "bar"},
    41  			},
    42  		},
    43  	}
    44  
    45  	for _, tc := range cases {
    46  		s := new(State)
    47  		for _, p := range tc.In {
    48  			s.AddModule(p)
    49  		}
    50  
    51  		actual := make([][]string, 0, len(tc.In))
    52  		for _, m := range s.Modules {
    53  			actual = append(actual, m.Path)
    54  		}
    55  
    56  		if !reflect.DeepEqual(actual, tc.Out) {
    57  			t.Fatalf("In: %#v\n\nOut: %#v", tc.In, actual)
    58  		}
    59  	}
    60  }
    61  
    62  func TestInstanceState_MergeDiff(t *testing.T) {
    63  	is := InstanceState{
    64  		ID: "foo",
    65  		Attributes: map[string]string{
    66  			"foo":  "bar",
    67  			"port": "8000",
    68  		},
    69  	}
    70  
    71  	diff := &InstanceDiff{
    72  		Attributes: map[string]*ResourceAttrDiff{
    73  			"foo": &ResourceAttrDiff{
    74  				Old: "bar",
    75  				New: "baz",
    76  			},
    77  			"bar": &ResourceAttrDiff{
    78  				Old: "",
    79  				New: "foo",
    80  			},
    81  			"baz": &ResourceAttrDiff{
    82  				Old:         "",
    83  				New:         "foo",
    84  				NewComputed: true,
    85  			},
    86  			"port": &ResourceAttrDiff{
    87  				NewRemoved: true,
    88  			},
    89  		},
    90  	}
    91  
    92  	is2 := is.MergeDiff(diff)
    93  
    94  	expected := map[string]string{
    95  		"foo": "baz",
    96  		"bar": "foo",
    97  		"baz": config.UnknownVariableValue,
    98  	}
    99  
   100  	if !reflect.DeepEqual(expected, is2.Attributes) {
   101  		t.Fatalf("bad: %#v", is2.Attributes)
   102  	}
   103  }
   104  
   105  func TestInstanceState_MergeDiff_nil(t *testing.T) {
   106  	var is *InstanceState = nil
   107  
   108  	diff := &InstanceDiff{
   109  		Attributes: map[string]*ResourceAttrDiff{
   110  			"foo": &ResourceAttrDiff{
   111  				Old: "",
   112  				New: "baz",
   113  			},
   114  		},
   115  	}
   116  
   117  	is2 := is.MergeDiff(diff)
   118  
   119  	expected := map[string]string{
   120  		"foo": "baz",
   121  	}
   122  
   123  	if !reflect.DeepEqual(expected, is2.Attributes) {
   124  		t.Fatalf("bad: %#v", is2.Attributes)
   125  	}
   126  }
   127  
   128  func TestInstanceState_MergeDiff_nilDiff(t *testing.T) {
   129  	is := InstanceState{
   130  		ID: "foo",
   131  		Attributes: map[string]string{
   132  			"foo": "bar",
   133  		},
   134  	}
   135  
   136  	is2 := is.MergeDiff(nil)
   137  
   138  	expected := map[string]string{
   139  		"foo": "bar",
   140  	}
   141  
   142  	if !reflect.DeepEqual(expected, is2.Attributes) {
   143  		t.Fatalf("bad: %#v", is2.Attributes)
   144  	}
   145  }
   146  
   147  func TestReadUpgradeState(t *testing.T) {
   148  	state := &StateV1{
   149  		Resources: map[string]*ResourceStateV1{
   150  			"foo": &ResourceStateV1{
   151  				ID: "bar",
   152  			},
   153  		},
   154  	}
   155  	buf := new(bytes.Buffer)
   156  	if err := testWriteStateV1(state, buf); err != nil {
   157  		t.Fatalf("err: %s", err)
   158  	}
   159  
   160  	// ReadState should transparently detect the old
   161  	// version and upgrade up so the latest.
   162  	actual, err := ReadState(buf)
   163  	if err != nil {
   164  		t.Fatalf("err: %s", err)
   165  	}
   166  
   167  	upgraded, err := upgradeV1State(state)
   168  	if err != nil {
   169  		t.Fatalf("err: %s", err)
   170  	}
   171  
   172  	if !reflect.DeepEqual(actual, upgraded) {
   173  		t.Fatalf("bad: %#v", actual)
   174  	}
   175  }
   176  
   177  func TestReadWriteState(t *testing.T) {
   178  	state := &State{
   179  		Serial: 9,
   180  		Modules: []*ModuleState{
   181  			&ModuleState{
   182  				Path: rootModulePath,
   183  				Resources: map[string]*ResourceState{
   184  					"foo": &ResourceState{
   185  						Primary: &InstanceState{
   186  							ID: "bar",
   187  							Ephemeral: EphemeralState{
   188  								ConnInfo: map[string]string{
   189  									"type":     "ssh",
   190  									"user":     "root",
   191  									"password": "supersecret",
   192  								},
   193  							},
   194  						},
   195  					},
   196  				},
   197  			},
   198  		},
   199  	}
   200  
   201  	// Checksum before the write
   202  	chksum := checksumStruct(t, state)
   203  
   204  	buf := new(bytes.Buffer)
   205  	if err := WriteState(state, buf); err != nil {
   206  		t.Fatalf("err: %s", err)
   207  	}
   208  
   209  	// Verify that the version and serial are set
   210  	if state.Version != textStateVersion {
   211  		t.Fatalf("bad version number: %d", state.Version)
   212  	}
   213  
   214  	// Verify the serial number is incremented
   215  	if state.Serial != 10 {
   216  		t.Fatalf("bad serial: %d", state.Serial)
   217  	}
   218  
   219  	// Remove the changes or the checksum will fail
   220  	state.Version = 0
   221  	state.Serial = 9
   222  
   223  	// Checksum after the write
   224  	chksumAfter := checksumStruct(t, state)
   225  	if chksumAfter != chksum {
   226  		t.Fatalf("structure changed during serialization!")
   227  	}
   228  
   229  	actual, err := ReadState(buf)
   230  	if err != nil {
   231  		t.Fatalf("err: %s", err)
   232  	}
   233  
   234  	// Verify the changes came through
   235  	state.Version = textStateVersion
   236  	state.Serial = 10
   237  
   238  	// ReadState should not restore sensitive information!
   239  	mod := state.RootModule()
   240  	mod.Resources["foo"].Primary.Ephemeral = EphemeralState{}
   241  
   242  	if !reflect.DeepEqual(actual, state) {
   243  		t.Fatalf("bad: %#v", actual)
   244  	}
   245  }
   246  
   247  func TestReadStateNewVersion(t *testing.T) {
   248  	type out struct {
   249  		Version int
   250  	}
   251  
   252  	buf, err := json.Marshal(&out{textStateVersion + 1})
   253  	if err != nil {
   254  		t.Fatalf("err: %v", err)
   255  	}
   256  
   257  	s, err := ReadState(bytes.NewReader(buf))
   258  	if s != nil {
   259  		t.Fatalf("unexpected: %#v", s)
   260  	}
   261  	if !strings.Contains(err.Error(), "not supported") {
   262  		t.Fatalf("err: %v", err)
   263  	}
   264  }
   265  
   266  func TestUpgradeV1State(t *testing.T) {
   267  	old := &StateV1{
   268  		Outputs: map[string]string{
   269  			"ip": "127.0.0.1",
   270  		},
   271  		Resources: map[string]*ResourceStateV1{
   272  			"foo": &ResourceStateV1{
   273  				Type: "test_resource",
   274  				ID:   "bar",
   275  				Attributes: map[string]string{
   276  					"key": "val",
   277  				},
   278  			},
   279  			"bar": &ResourceStateV1{
   280  				Type: "test_resource",
   281  				ID:   "1234",
   282  				Attributes: map[string]string{
   283  					"a": "b",
   284  				},
   285  			},
   286  		},
   287  		Tainted: map[string]struct{}{
   288  			"bar": struct{}{},
   289  		},
   290  	}
   291  	state, err := upgradeV1State(old)
   292  	if err != nil {
   293  		t.Fatalf("err: %v", err)
   294  	}
   295  
   296  	if len(state.Modules) != 1 {
   297  		t.Fatalf("should only have root module: %#v", state.Modules)
   298  	}
   299  	root := state.RootModule()
   300  
   301  	if len(root.Outputs) != 1 {
   302  		t.Fatalf("bad outputs: %v", root.Outputs)
   303  	}
   304  	if root.Outputs["ip"] != "127.0.0.1" {
   305  		t.Fatalf("bad outputs: %v", root.Outputs)
   306  	}
   307  
   308  	if len(root.Resources) != 2 {
   309  		t.Fatalf("bad resources: %v", root.Resources)
   310  	}
   311  
   312  	foo := root.Resources["foo"]
   313  	if foo.Type != "test_resource" {
   314  		t.Fatalf("bad: %#v", foo)
   315  	}
   316  	if foo.Primary == nil || foo.Primary.ID != "bar" ||
   317  		foo.Primary.Attributes["key"] != "val" {
   318  		t.Fatalf("bad: %#v", foo)
   319  	}
   320  	if len(foo.Tainted) > 0 {
   321  		t.Fatalf("bad: %#v", foo)
   322  	}
   323  
   324  	bar := root.Resources["bar"]
   325  	if bar.Type != "test_resource" {
   326  		t.Fatalf("bad: %#v", bar)
   327  	}
   328  	if bar.Primary != nil {
   329  		t.Fatalf("bad: %#v", bar)
   330  	}
   331  	if len(bar.Tainted) != 1 {
   332  		t.Fatalf("bad: %#v", bar)
   333  	}
   334  	bt := bar.Tainted[0]
   335  	if bt.ID != "1234" || bt.Attributes["a"] != "b" {
   336  		t.Fatalf("bad: %#v", bt)
   337  	}
   338  }