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 }