github.com/hobbeswalsh/terraform@v0.3.7-0.20150619183303-ad17cf55a0fa/command/push_test.go (about) 1 package command 2 3 import ( 4 "archive/tar" 5 "bytes" 6 "compress/gzip" 7 "io" 8 "os" 9 "reflect" 10 "sort" 11 "testing" 12 13 "github.com/hashicorp/terraform/terraform" 14 "github.com/mitchellh/cli" 15 ) 16 17 func TestPush_good(t *testing.T) { 18 tmp, cwd := testCwd(t) 19 defer testFixCwd(t, tmp, cwd) 20 21 // Create remote state file, this should be pulled 22 conf, srv := testRemoteState(t, testState(), 200) 23 defer srv.Close() 24 25 // Persist local remote state 26 s := terraform.NewState() 27 s.Serial = 5 28 s.Remote = conf 29 testStateFileRemote(t, s) 30 31 // Path where the archive will be "uploaded" to 32 archivePath := testTempFile(t) 33 defer os.Remove(archivePath) 34 35 client := &mockPushClient{File: archivePath} 36 ui := new(cli.MockUi) 37 c := &PushCommand{ 38 Meta: Meta{ 39 ContextOpts: testCtxConfig(testProvider()), 40 Ui: ui, 41 }, 42 43 client: client, 44 } 45 46 args := []string{ 47 "-vcs=false", 48 testFixturePath("push"), 49 } 50 if code := c.Run(args); code != 0 { 51 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 52 } 53 54 actual := testArchiveStr(t, archivePath) 55 expected := []string{ 56 ".terraform/", 57 ".terraform/terraform.tfstate", 58 "main.tf", 59 } 60 if !reflect.DeepEqual(actual, expected) { 61 t.Fatalf("bad: %#v", actual) 62 } 63 64 variables := make(map[string]string) 65 if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) { 66 t.Fatalf("bad: %#v", client.UpsertOptions) 67 } 68 69 if client.UpsertOptions.Name != "foo" { 70 t.Fatalf("bad: %#v", client.UpsertOptions) 71 } 72 } 73 74 func TestPush_input(t *testing.T) { 75 tmp, cwd := testCwd(t) 76 defer testFixCwd(t, tmp, cwd) 77 78 // Create remote state file, this should be pulled 79 conf, srv := testRemoteState(t, testState(), 200) 80 defer srv.Close() 81 82 // Persist local remote state 83 s := terraform.NewState() 84 s.Serial = 5 85 s.Remote = conf 86 testStateFileRemote(t, s) 87 88 // Path where the archive will be "uploaded" to 89 archivePath := testTempFile(t) 90 defer os.Remove(archivePath) 91 92 client := &mockPushClient{File: archivePath} 93 ui := new(cli.MockUi) 94 c := &PushCommand{ 95 Meta: Meta{ 96 ContextOpts: testCtxConfig(testProvider()), 97 Ui: ui, 98 }, 99 100 client: client, 101 } 102 103 // Disable test mode so input would be asked and setup the 104 // input reader/writers. 105 test = false 106 defer func() { test = true }() 107 defaultInputReader = bytes.NewBufferString("foo\n") 108 defaultInputWriter = new(bytes.Buffer) 109 110 args := []string{ 111 "-vcs=false", 112 testFixturePath("push-input"), 113 } 114 if code := c.Run(args); code != 0 { 115 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 116 } 117 118 variables := map[string]string{ 119 "foo": "foo", 120 } 121 if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) { 122 t.Fatalf("bad: %#v", client.UpsertOptions) 123 } 124 } 125 126 func TestPush_inputPartial(t *testing.T) { 127 tmp, cwd := testCwd(t) 128 defer testFixCwd(t, tmp, cwd) 129 130 // Create remote state file, this should be pulled 131 conf, srv := testRemoteState(t, testState(), 200) 132 defer srv.Close() 133 134 // Persist local remote state 135 s := terraform.NewState() 136 s.Serial = 5 137 s.Remote = conf 138 testStateFileRemote(t, s) 139 140 // Path where the archive will be "uploaded" to 141 archivePath := testTempFile(t) 142 defer os.Remove(archivePath) 143 144 client := &mockPushClient{ 145 File: archivePath, 146 GetResult: map[string]string{"foo": "bar"}, 147 } 148 ui := new(cli.MockUi) 149 c := &PushCommand{ 150 Meta: Meta{ 151 ContextOpts: testCtxConfig(testProvider()), 152 Ui: ui, 153 }, 154 155 client: client, 156 } 157 158 // Disable test mode so input would be asked and setup the 159 // input reader/writers. 160 test = false 161 defer func() { test = true }() 162 defaultInputReader = bytes.NewBufferString("foo\n") 163 defaultInputWriter = new(bytes.Buffer) 164 165 args := []string{ 166 "-vcs=false", 167 testFixturePath("push-input-partial"), 168 } 169 if code := c.Run(args); code != 0 { 170 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 171 } 172 173 variables := map[string]string{ 174 "foo": "bar", 175 "bar": "foo", 176 } 177 if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) { 178 t.Fatalf("bad: %#v", client.UpsertOptions) 179 } 180 } 181 182 func TestPush_inputTfvars(t *testing.T) { 183 // Disable test mode so input would be asked and setup the 184 // input reader/writers. 185 test = false 186 defer func() { test = true }() 187 defaultInputReader = bytes.NewBufferString("nope\n") 188 defaultInputWriter = new(bytes.Buffer) 189 190 tmp, cwd := testCwd(t) 191 defer testFixCwd(t, tmp, cwd) 192 193 // Create remote state file, this should be pulled 194 conf, srv := testRemoteState(t, testState(), 200) 195 defer srv.Close() 196 197 // Persist local remote state 198 s := terraform.NewState() 199 s.Serial = 5 200 s.Remote = conf 201 testStateFileRemote(t, s) 202 203 // Path where the archive will be "uploaded" to 204 archivePath := testTempFile(t) 205 defer os.Remove(archivePath) 206 207 client := &mockPushClient{File: archivePath} 208 // Provided vars should override existing ones 209 client.GetResult = map[string]string{ 210 "foo": "old", 211 } 212 ui := new(cli.MockUi) 213 c := &PushCommand{ 214 Meta: Meta{ 215 ContextOpts: testCtxConfig(testProvider()), 216 Ui: ui, 217 }, 218 219 client: client, 220 } 221 222 path := testFixturePath("push-tfvars") 223 args := []string{ 224 "-var-file", path + "/terraform.tfvars", 225 "-vcs=false", 226 path, 227 } 228 if code := c.Run(args); code != 0 { 229 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 230 } 231 232 actual := testArchiveStr(t, archivePath) 233 expected := []string{ 234 ".terraform/", 235 ".terraform/terraform.tfstate", 236 "main.tf", 237 "terraform.tfvars", 238 } 239 if !reflect.DeepEqual(actual, expected) { 240 t.Fatalf("bad: %#v", actual) 241 } 242 243 if client.UpsertOptions.Name != "foo" { 244 t.Fatalf("bad: %#v", client.UpsertOptions) 245 } 246 247 variables := map[string]string{ 248 "foo": "bar", 249 "bar": "foo", 250 } 251 if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) { 252 t.Fatalf("bad: %#v", client.UpsertOptions) 253 } 254 } 255 256 func TestPush_name(t *testing.T) { 257 tmp, cwd := testCwd(t) 258 defer testFixCwd(t, tmp, cwd) 259 260 // Create remote state file, this should be pulled 261 conf, srv := testRemoteState(t, testState(), 200) 262 defer srv.Close() 263 264 // Persist local remote state 265 s := terraform.NewState() 266 s.Serial = 5 267 s.Remote = conf 268 testStateFileRemote(t, s) 269 270 // Path where the archive will be "uploaded" to 271 archivePath := testTempFile(t) 272 defer os.Remove(archivePath) 273 274 client := &mockPushClient{File: archivePath} 275 ui := new(cli.MockUi) 276 c := &PushCommand{ 277 Meta: Meta{ 278 ContextOpts: testCtxConfig(testProvider()), 279 Ui: ui, 280 }, 281 282 client: client, 283 } 284 285 args := []string{ 286 "-name", "bar", 287 "-vcs=false", 288 testFixturePath("push"), 289 } 290 if code := c.Run(args); code != 0 { 291 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 292 } 293 294 if client.UpsertOptions.Name != "bar" { 295 t.Fatalf("bad: %#v", client.UpsertOptions) 296 } 297 } 298 299 func TestPush_noState(t *testing.T) { 300 tmp, cwd := testCwd(t) 301 defer testFixCwd(t, tmp, cwd) 302 303 ui := new(cli.MockUi) 304 c := &PushCommand{ 305 Meta: Meta{ 306 ContextOpts: testCtxConfig(testProvider()), 307 Ui: ui, 308 }, 309 } 310 311 args := []string{} 312 if code := c.Run(args); code != 1 { 313 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 314 } 315 } 316 317 func TestPush_noRemoteState(t *testing.T) { 318 state := &terraform.State{ 319 Modules: []*terraform.ModuleState{ 320 &terraform.ModuleState{ 321 Path: []string{"root"}, 322 Resources: map[string]*terraform.ResourceState{ 323 "test_instance.foo": &terraform.ResourceState{ 324 Type: "test_instance", 325 Primary: &terraform.InstanceState{ 326 ID: "bar", 327 }, 328 }, 329 }, 330 }, 331 }, 332 } 333 statePath := testStateFile(t, state) 334 335 ui := new(cli.MockUi) 336 c := &PushCommand{ 337 Meta: Meta{ 338 Ui: ui, 339 }, 340 } 341 342 args := []string{ 343 "-state", statePath, 344 } 345 if code := c.Run(args); code != 1 { 346 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 347 } 348 } 349 350 func TestPush_plan(t *testing.T) { 351 tmp, cwd := testCwd(t) 352 defer testFixCwd(t, tmp, cwd) 353 354 // Create remote state file, this should be pulled 355 conf, srv := testRemoteState(t, testState(), 200) 356 defer srv.Close() 357 358 // Persist local remote state 359 s := terraform.NewState() 360 s.Serial = 5 361 s.Remote = conf 362 testStateFileRemote(t, s) 363 364 // Create a plan 365 planPath := testPlanFile(t, &terraform.Plan{ 366 Module: testModule(t, "apply"), 367 }) 368 369 ui := new(cli.MockUi) 370 c := &PushCommand{ 371 Meta: Meta{ 372 ContextOpts: testCtxConfig(testProvider()), 373 Ui: ui, 374 }, 375 } 376 377 args := []string{planPath} 378 if code := c.Run(args); code != 1 { 379 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 380 } 381 } 382 383 func testArchiveStr(t *testing.T, path string) []string { 384 f, err := os.Open(path) 385 if err != nil { 386 t.Fatalf("err: %s", err) 387 } 388 defer f.Close() 389 390 // Ungzip 391 gzipR, err := gzip.NewReader(f) 392 if err != nil { 393 t.Fatalf("err: %s", err) 394 } 395 396 // Accumulator 397 result := make([]string, 0, 10) 398 399 // Untar 400 tarR := tar.NewReader(gzipR) 401 for { 402 header, err := tarR.Next() 403 if err == io.EOF { 404 break 405 } 406 if err != nil { 407 t.Fatalf("err: %s", err) 408 } 409 410 result = append(result, header.Name) 411 } 412 413 sort.Strings(result) 414 return result 415 }