github.com/arvindram03/terraform@v0.3.7-0.20150212015210-408f838db36d/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  		Remote: &RemoteState{
   181  			Type: "http",
   182  			Config: map[string]string{
   183  				"url": "http://my-cool-server.com/",
   184  			},
   185  		},
   186  		Modules: []*ModuleState{
   187  			&ModuleState{
   188  				Path: rootModulePath,
   189  				Dependencies: []string{
   190  					"aws_instance.bar",
   191  				},
   192  				Resources: map[string]*ResourceState{
   193  					"foo": &ResourceState{
   194  						Primary: &InstanceState{
   195  							ID: "bar",
   196  							Ephemeral: EphemeralState{
   197  								ConnInfo: map[string]string{
   198  									"type":     "ssh",
   199  									"user":     "root",
   200  									"password": "supersecret",
   201  								},
   202  							},
   203  						},
   204  					},
   205  				},
   206  			},
   207  		},
   208  	}
   209  
   210  	// Checksum before the write
   211  	chksum := checksumStruct(t, state)
   212  
   213  	buf := new(bytes.Buffer)
   214  	if err := WriteState(state, buf); err != nil {
   215  		t.Fatalf("err: %s", err)
   216  	}
   217  
   218  	// Verify that the version and serial are set
   219  	if state.Version != StateVersion {
   220  		t.Fatalf("bad version number: %d", state.Version)
   221  	}
   222  
   223  	// Verify the serial number is incremented
   224  	if state.Serial != 10 {
   225  		t.Fatalf("bad serial: %d", state.Serial)
   226  	}
   227  
   228  	// Remove the changes or the checksum will fail
   229  	state.Version = 0
   230  	state.Serial = 9
   231  
   232  	// Checksum after the write
   233  	chksumAfter := checksumStruct(t, state)
   234  	if chksumAfter != chksum {
   235  		t.Fatalf("structure changed during serialization!")
   236  	}
   237  
   238  	actual, err := ReadState(buf)
   239  	if err != nil {
   240  		t.Fatalf("err: %s", err)
   241  	}
   242  
   243  	// Verify the changes came through
   244  	state.Version = StateVersion
   245  	state.Serial = 10
   246  
   247  	// ReadState should not restore sensitive information!
   248  	mod := state.RootModule()
   249  	mod.Resources["foo"].Primary.Ephemeral = EphemeralState{}
   250  
   251  	if !reflect.DeepEqual(actual, state) {
   252  		t.Fatalf("bad: %#v", actual)
   253  	}
   254  }
   255  
   256  func TestReadStateNewVersion(t *testing.T) {
   257  	type out struct {
   258  		Version int
   259  	}
   260  
   261  	buf, err := json.Marshal(&out{StateVersion + 1})
   262  	if err != nil {
   263  		t.Fatalf("err: %v", err)
   264  	}
   265  
   266  	s, err := ReadState(bytes.NewReader(buf))
   267  	if s != nil {
   268  		t.Fatalf("unexpected: %#v", s)
   269  	}
   270  	if !strings.Contains(err.Error(), "not supported") {
   271  		t.Fatalf("err: %v", err)
   272  	}
   273  }
   274  
   275  func TestUpgradeV1State(t *testing.T) {
   276  	old := &StateV1{
   277  		Outputs: map[string]string{
   278  			"ip": "127.0.0.1",
   279  		},
   280  		Resources: map[string]*ResourceStateV1{
   281  			"foo": &ResourceStateV1{
   282  				Type: "test_resource",
   283  				ID:   "bar",
   284  				Attributes: map[string]string{
   285  					"key": "val",
   286  				},
   287  			},
   288  			"bar": &ResourceStateV1{
   289  				Type: "test_resource",
   290  				ID:   "1234",
   291  				Attributes: map[string]string{
   292  					"a": "b",
   293  				},
   294  			},
   295  		},
   296  		Tainted: map[string]struct{}{
   297  			"bar": struct{}{},
   298  		},
   299  	}
   300  	state, err := upgradeV1State(old)
   301  	if err != nil {
   302  		t.Fatalf("err: %v", err)
   303  	}
   304  
   305  	if len(state.Modules) != 1 {
   306  		t.Fatalf("should only have root module: %#v", state.Modules)
   307  	}
   308  	root := state.RootModule()
   309  
   310  	if len(root.Outputs) != 1 {
   311  		t.Fatalf("bad outputs: %v", root.Outputs)
   312  	}
   313  	if root.Outputs["ip"] != "127.0.0.1" {
   314  		t.Fatalf("bad outputs: %v", root.Outputs)
   315  	}
   316  
   317  	if len(root.Resources) != 2 {
   318  		t.Fatalf("bad resources: %v", root.Resources)
   319  	}
   320  
   321  	foo := root.Resources["foo"]
   322  	if foo.Type != "test_resource" {
   323  		t.Fatalf("bad: %#v", foo)
   324  	}
   325  	if foo.Primary == nil || foo.Primary.ID != "bar" ||
   326  		foo.Primary.Attributes["key"] != "val" {
   327  		t.Fatalf("bad: %#v", foo)
   328  	}
   329  	if len(foo.Tainted) > 0 {
   330  		t.Fatalf("bad: %#v", foo)
   331  	}
   332  
   333  	bar := root.Resources["bar"]
   334  	if bar.Type != "test_resource" {
   335  		t.Fatalf("bad: %#v", bar)
   336  	}
   337  	if bar.Primary != nil {
   338  		t.Fatalf("bad: %#v", bar)
   339  	}
   340  	if len(bar.Tainted) != 1 {
   341  		t.Fatalf("bad: %#v", bar)
   342  	}
   343  	bt := bar.Tainted[0]
   344  	if bt.ID != "1234" || bt.Attributes["a"] != "b" {
   345  		t.Fatalf("bad: %#v", bt)
   346  	}
   347  }