github.com/alexissmirnov/terraform@v0.4.3-0.20150423153700-1ef9731a2f14/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 ui := new(cli.MockUi) 209 c := &PushCommand{ 210 Meta: Meta{ 211 ContextOpts: testCtxConfig(testProvider()), 212 Ui: ui, 213 }, 214 215 client: client, 216 } 217 218 path := testFixturePath("push-tfvars") 219 args := []string{ 220 "-var-file", path + "/terraform.tfvars", 221 "-vcs=false", 222 path, 223 } 224 if code := c.Run(args); code != 0 { 225 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 226 } 227 228 actual := testArchiveStr(t, archivePath) 229 expected := []string{ 230 ".terraform/", 231 ".terraform/terraform.tfstate", 232 "main.tf", 233 "terraform.tfvars", 234 } 235 if !reflect.DeepEqual(actual, expected) { 236 t.Fatalf("bad: %#v", actual) 237 } 238 239 if client.UpsertOptions.Name != "foo" { 240 t.Fatalf("bad: %#v", client.UpsertOptions) 241 } 242 243 variables := map[string]string{ 244 "foo": "bar", 245 "bar": "foo", 246 } 247 if !reflect.DeepEqual(client.UpsertOptions.Variables, variables) { 248 t.Fatalf("bad: %#v", client.UpsertOptions) 249 } 250 } 251 252 func TestPush_name(t *testing.T) { 253 tmp, cwd := testCwd(t) 254 defer testFixCwd(t, tmp, cwd) 255 256 // Create remote state file, this should be pulled 257 conf, srv := testRemoteState(t, testState(), 200) 258 defer srv.Close() 259 260 // Persist local remote state 261 s := terraform.NewState() 262 s.Serial = 5 263 s.Remote = conf 264 testStateFileRemote(t, s) 265 266 // Path where the archive will be "uploaded" to 267 archivePath := testTempFile(t) 268 defer os.Remove(archivePath) 269 270 client := &mockPushClient{File: archivePath} 271 ui := new(cli.MockUi) 272 c := &PushCommand{ 273 Meta: Meta{ 274 ContextOpts: testCtxConfig(testProvider()), 275 Ui: ui, 276 }, 277 278 client: client, 279 } 280 281 args := []string{ 282 "-name", "bar", 283 "-vcs=false", 284 testFixturePath("push"), 285 } 286 if code := c.Run(args); code != 0 { 287 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 288 } 289 290 if client.UpsertOptions.Name != "bar" { 291 t.Fatalf("bad: %#v", client.UpsertOptions) 292 } 293 } 294 295 func TestPush_noState(t *testing.T) { 296 tmp, cwd := testCwd(t) 297 defer testFixCwd(t, tmp, cwd) 298 299 ui := new(cli.MockUi) 300 c := &PushCommand{ 301 Meta: Meta{ 302 ContextOpts: testCtxConfig(testProvider()), 303 Ui: ui, 304 }, 305 } 306 307 args := []string{} 308 if code := c.Run(args); code != 1 { 309 t.Fatalf("bad: \n%s", ui.ErrorWriter.String()) 310 } 311 } 312 313 func TestPush_noRemoteState(t *testing.T) { 314 state := &terraform.State{ 315 Modules: []*terraform.ModuleState{ 316 &terraform.ModuleState{ 317 Path: []string{"root"}, 318 Resources: map[string]*terraform.ResourceState{ 319 "test_instance.foo": &terraform.ResourceState{ 320 Type: "test_instance", 321 Primary: &terraform.InstanceState{ 322 ID: "bar", 323 }, 324 }, 325 }, 326 }, 327 }, 328 } 329 statePath := testStateFile(t, state) 330 331 ui := new(cli.MockUi) 332 c := &PushCommand{ 333 Meta: Meta{ 334 Ui: ui, 335 }, 336 } 337 338 args := []string{ 339 "-state", statePath, 340 } 341 if code := c.Run(args); code != 1 { 342 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 343 } 344 } 345 346 func TestPush_plan(t *testing.T) { 347 tmp, cwd := testCwd(t) 348 defer testFixCwd(t, tmp, cwd) 349 350 // Create remote state file, this should be pulled 351 conf, srv := testRemoteState(t, testState(), 200) 352 defer srv.Close() 353 354 // Persist local remote state 355 s := terraform.NewState() 356 s.Serial = 5 357 s.Remote = conf 358 testStateFileRemote(t, s) 359 360 // Create a plan 361 planPath := testPlanFile(t, &terraform.Plan{ 362 Module: testModule(t, "apply"), 363 }) 364 365 ui := new(cli.MockUi) 366 c := &PushCommand{ 367 Meta: Meta{ 368 ContextOpts: testCtxConfig(testProvider()), 369 Ui: ui, 370 }, 371 } 372 373 args := []string{planPath} 374 if code := c.Run(args); code != 1 { 375 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 376 } 377 } 378 379 func testArchiveStr(t *testing.T, path string) []string { 380 f, err := os.Open(path) 381 if err != nil { 382 t.Fatalf("err: %s", err) 383 } 384 defer f.Close() 385 386 // Ungzip 387 gzipR, err := gzip.NewReader(f) 388 if err != nil { 389 t.Fatalf("err: %s", err) 390 } 391 392 // Accumulator 393 result := make([]string, 0, 10) 394 395 // Untar 396 tarR := tar.NewReader(gzipR) 397 for { 398 header, err := tarR.Next() 399 if err == io.EOF { 400 break 401 } 402 if err != nil { 403 t.Fatalf("err: %s", err) 404 } 405 406 result = append(result, header.Name) 407 } 408 409 sort.Strings(result) 410 return result 411 }