github.com/paybyphone/terraform@v0.9.5-0.20170613192930-9706042ddd51/terraform/graph_builder_apply_test.go (about) 1 package terraform 2 3 import ( 4 "reflect" 5 "strings" 6 "testing" 7 ) 8 9 func TestApplyGraphBuilder_impl(t *testing.T) { 10 var _ GraphBuilder = new(ApplyGraphBuilder) 11 } 12 13 func TestApplyGraphBuilder(t *testing.T) { 14 diff := &Diff{ 15 Modules: []*ModuleDiff{ 16 &ModuleDiff{ 17 Path: []string{"root"}, 18 Resources: map[string]*InstanceDiff{ 19 // Verify noop doesn't show up in graph 20 "aws_instance.noop": &InstanceDiff{}, 21 22 "aws_instance.create": &InstanceDiff{ 23 Attributes: map[string]*ResourceAttrDiff{ 24 "name": &ResourceAttrDiff{ 25 Old: "", 26 New: "foo", 27 }, 28 }, 29 }, 30 31 "aws_instance.other": &InstanceDiff{ 32 Attributes: map[string]*ResourceAttrDiff{ 33 "name": &ResourceAttrDiff{ 34 Old: "", 35 New: "foo", 36 }, 37 }, 38 }, 39 }, 40 }, 41 42 &ModuleDiff{ 43 Path: []string{"root", "child"}, 44 Resources: map[string]*InstanceDiff{ 45 "aws_instance.create": &InstanceDiff{ 46 Attributes: map[string]*ResourceAttrDiff{ 47 "name": &ResourceAttrDiff{ 48 Old: "", 49 New: "foo", 50 }, 51 }, 52 }, 53 54 "aws_instance.other": &InstanceDiff{ 55 Attributes: map[string]*ResourceAttrDiff{ 56 "name": &ResourceAttrDiff{ 57 Old: "", 58 New: "foo", 59 }, 60 }, 61 }, 62 }, 63 }, 64 }, 65 } 66 67 b := &ApplyGraphBuilder{ 68 Module: testModule(t, "graph-builder-apply-basic"), 69 Diff: diff, 70 Providers: []string{"aws"}, 71 Provisioners: []string{"exec"}, 72 DisableReduce: true, 73 } 74 75 g, err := b.Build(RootModulePath) 76 if err != nil { 77 t.Fatalf("err: %s", err) 78 } 79 80 if !reflect.DeepEqual(g.Path, RootModulePath) { 81 t.Fatalf("bad: %#v", g.Path) 82 } 83 84 actual := strings.TrimSpace(g.String()) 85 expected := strings.TrimSpace(testApplyGraphBuilderStr) 86 if actual != expected { 87 t.Fatalf("bad: %s", actual) 88 } 89 } 90 91 // This tests the ordering of two resources where a non-CBD depends 92 // on a CBD. GH-11349. 93 func TestApplyGraphBuilder_depCbd(t *testing.T) { 94 diff := &Diff{ 95 Modules: []*ModuleDiff{ 96 &ModuleDiff{ 97 Path: []string{"root"}, 98 Resources: map[string]*InstanceDiff{"aws_instance.A": &InstanceDiff{Destroy: true, 99 Attributes: map[string]*ResourceAttrDiff{ 100 "name": &ResourceAttrDiff{ 101 Old: "", 102 New: "foo", 103 RequiresNew: true, 104 }, 105 }, 106 }, 107 108 "aws_instance.B": &InstanceDiff{ 109 Attributes: map[string]*ResourceAttrDiff{ 110 "name": &ResourceAttrDiff{ 111 Old: "", 112 New: "foo", 113 }, 114 }, 115 }, 116 }, 117 }, 118 }, 119 } 120 121 b := &ApplyGraphBuilder{ 122 Module: testModule(t, "graph-builder-apply-dep-cbd"), 123 Diff: diff, 124 Providers: []string{"aws"}, 125 Provisioners: []string{"exec"}, 126 DisableReduce: true, 127 } 128 129 g, err := b.Build(RootModulePath) 130 if err != nil { 131 t.Fatalf("err: %s", err) 132 } 133 t.Logf("Graph: %s", g.String()) 134 135 if !reflect.DeepEqual(g.Path, RootModulePath) { 136 t.Fatalf("bad: %#v", g.Path) 137 } 138 139 // Create A, Modify B, Destroy A 140 141 testGraphHappensBefore( 142 t, g, 143 "aws_instance.A", 144 "aws_instance.A (destroy)") 145 testGraphHappensBefore( 146 t, g, 147 "aws_instance.A", 148 "aws_instance.B") 149 testGraphHappensBefore( 150 t, g, 151 "aws_instance.B", 152 "aws_instance.A (destroy)") 153 } 154 155 // This tests the ordering of two resources that are both CBD that 156 // require destroy/create. 157 func TestApplyGraphBuilder_doubleCBD(t *testing.T) { 158 diff := &Diff{ 159 Modules: []*ModuleDiff{ 160 &ModuleDiff{ 161 Path: []string{"root"}, 162 Resources: map[string]*InstanceDiff{ 163 "aws_instance.A": &InstanceDiff{ 164 Destroy: true, 165 Attributes: map[string]*ResourceAttrDiff{ 166 "name": &ResourceAttrDiff{ 167 Old: "", 168 New: "foo", 169 }, 170 }, 171 }, 172 173 "aws_instance.B": &InstanceDiff{ 174 Destroy: true, 175 Attributes: map[string]*ResourceAttrDiff{ 176 "name": &ResourceAttrDiff{ 177 Old: "", 178 New: "foo", 179 }, 180 }, 181 }, 182 }, 183 }, 184 }, 185 } 186 187 b := &ApplyGraphBuilder{ 188 Module: testModule(t, "graph-builder-apply-double-cbd"), 189 Diff: diff, 190 Providers: []string{"aws"}, 191 Provisioners: []string{"exec"}, 192 DisableReduce: true, 193 } 194 195 g, err := b.Build(RootModulePath) 196 if err != nil { 197 t.Fatalf("err: %s", err) 198 } 199 200 if !reflect.DeepEqual(g.Path, RootModulePath) { 201 t.Fatalf("bad: %#v", g.Path) 202 } 203 204 actual := strings.TrimSpace(g.String()) 205 expected := strings.TrimSpace(testApplyGraphBuilderDoubleCBDStr) 206 if actual != expected { 207 t.Fatalf("bad: %s", actual) 208 } 209 } 210 211 // This tests the ordering of two resources being destroyed that depend 212 // on each other from only state. GH-11749 213 func TestApplyGraphBuilder_destroyStateOnly(t *testing.T) { 214 diff := &Diff{ 215 Modules: []*ModuleDiff{ 216 &ModuleDiff{ 217 Path: []string{"root", "child"}, 218 Resources: map[string]*InstanceDiff{ 219 "aws_instance.A": &InstanceDiff{ 220 Destroy: true, 221 }, 222 223 "aws_instance.B": &InstanceDiff{ 224 Destroy: true, 225 }, 226 }, 227 }, 228 }, 229 } 230 231 state := &State{ 232 Modules: []*ModuleState{ 233 &ModuleState{ 234 Path: []string{"root", "child"}, 235 Resources: map[string]*ResourceState{ 236 "aws_instance.A": &ResourceState{ 237 Type: "aws_instance", 238 Primary: &InstanceState{ 239 ID: "foo", 240 Attributes: map[string]string{}, 241 }, 242 }, 243 244 "aws_instance.B": &ResourceState{ 245 Type: "aws_instance", 246 Primary: &InstanceState{ 247 ID: "bar", 248 Attributes: map[string]string{}, 249 }, 250 Dependencies: []string{"aws_instance.A"}, 251 }, 252 }, 253 }, 254 }, 255 } 256 257 b := &ApplyGraphBuilder{ 258 Module: testModule(t, "empty"), 259 Diff: diff, 260 State: state, 261 Providers: []string{"aws"}, 262 DisableReduce: true, 263 } 264 265 g, err := b.Build(RootModulePath) 266 if err != nil { 267 t.Fatalf("err: %s", err) 268 } 269 t.Logf("Graph: %s", g.String()) 270 271 if !reflect.DeepEqual(g.Path, RootModulePath) { 272 t.Fatalf("bad: %#v", g.Path) 273 } 274 275 testGraphHappensBefore( 276 t, g, 277 "module.child.aws_instance.B (destroy)", 278 "module.child.aws_instance.A (destroy)") 279 } 280 281 // This tests the ordering of destroying a single count of a resource. 282 func TestApplyGraphBuilder_destroyCount(t *testing.T) { 283 diff := &Diff{ 284 Modules: []*ModuleDiff{ 285 &ModuleDiff{ 286 Path: []string{"root"}, 287 Resources: map[string]*InstanceDiff{ 288 "aws_instance.A.1": &InstanceDiff{ 289 Destroy: true, 290 }, 291 292 "aws_instance.B": &InstanceDiff{ 293 Attributes: map[string]*ResourceAttrDiff{ 294 "name": &ResourceAttrDiff{ 295 Old: "", 296 New: "foo", 297 }, 298 }, 299 }, 300 }, 301 }, 302 }, 303 } 304 305 b := &ApplyGraphBuilder{ 306 Module: testModule(t, "graph-builder-apply-count"), 307 Diff: diff, 308 Providers: []string{"aws"}, 309 Provisioners: []string{"exec"}, 310 DisableReduce: true, 311 } 312 313 g, err := b.Build(RootModulePath) 314 if err != nil { 315 t.Fatalf("err: %s", err) 316 } 317 318 if !reflect.DeepEqual(g.Path, RootModulePath) { 319 t.Fatalf("bad: %#v", g.Path) 320 } 321 322 actual := strings.TrimSpace(g.String()) 323 expected := strings.TrimSpace(testApplyGraphBuilderDestroyCountStr) 324 if actual != expected { 325 t.Fatalf("bad: %s", actual) 326 } 327 } 328 329 func TestApplyGraphBuilder_moduleDestroy(t *testing.T) { 330 diff := &Diff{ 331 Modules: []*ModuleDiff{ 332 &ModuleDiff{ 333 Path: []string{"root", "A"}, 334 Resources: map[string]*InstanceDiff{ 335 "null_resource.foo": &InstanceDiff{ 336 Destroy: true, 337 }, 338 }, 339 }, 340 341 &ModuleDiff{ 342 Path: []string{"root", "B"}, 343 Resources: map[string]*InstanceDiff{ 344 "null_resource.foo": &InstanceDiff{ 345 Destroy: true, 346 }, 347 }, 348 }, 349 }, 350 } 351 352 b := &ApplyGraphBuilder{ 353 Module: testModule(t, "graph-builder-apply-module-destroy"), 354 Diff: diff, 355 Providers: []string{"null"}, 356 } 357 358 g, err := b.Build(RootModulePath) 359 if err != nil { 360 t.Fatalf("err: %s", err) 361 } 362 363 testGraphHappensBefore( 364 t, g, 365 "module.B.null_resource.foo (destroy)", 366 "module.A.null_resource.foo (destroy)") 367 } 368 369 func TestApplyGraphBuilder_provisioner(t *testing.T) { 370 diff := &Diff{ 371 Modules: []*ModuleDiff{ 372 &ModuleDiff{ 373 Path: []string{"root"}, 374 Resources: map[string]*InstanceDiff{ 375 "null_resource.foo": &InstanceDiff{ 376 Attributes: map[string]*ResourceAttrDiff{ 377 "name": &ResourceAttrDiff{ 378 Old: "", 379 New: "foo", 380 }, 381 }, 382 }, 383 }, 384 }, 385 }, 386 } 387 388 b := &ApplyGraphBuilder{ 389 Module: testModule(t, "graph-builder-apply-provisioner"), 390 Diff: diff, 391 Providers: []string{"null"}, 392 Provisioners: []string{"local"}, 393 } 394 395 g, err := b.Build(RootModulePath) 396 if err != nil { 397 t.Fatalf("err: %s", err) 398 } 399 400 testGraphContains(t, g, "provisioner.local") 401 testGraphHappensBefore( 402 t, g, 403 "provisioner.local", 404 "null_resource.foo") 405 } 406 407 func TestApplyGraphBuilder_provisionerDestroy(t *testing.T) { 408 diff := &Diff{ 409 Modules: []*ModuleDiff{ 410 &ModuleDiff{ 411 Path: []string{"root"}, 412 Resources: map[string]*InstanceDiff{ 413 "null_resource.foo": &InstanceDiff{ 414 Destroy: true, 415 }, 416 }, 417 }, 418 }, 419 } 420 421 b := &ApplyGraphBuilder{ 422 Destroy: true, 423 Module: testModule(t, "graph-builder-apply-provisioner"), 424 Diff: diff, 425 Providers: []string{"null"}, 426 Provisioners: []string{"local"}, 427 } 428 429 g, err := b.Build(RootModulePath) 430 if err != nil { 431 t.Fatalf("err: %s", err) 432 } 433 434 testGraphContains(t, g, "provisioner.local") 435 testGraphHappensBefore( 436 t, g, 437 "provisioner.local", 438 "null_resource.foo (destroy)") 439 } 440 441 func TestApplyGraphBuilder_targetModule(t *testing.T) { 442 diff := &Diff{ 443 Modules: []*ModuleDiff{ 444 &ModuleDiff{ 445 Path: []string{"root"}, 446 Resources: map[string]*InstanceDiff{ 447 "null_resource.foo": &InstanceDiff{ 448 Attributes: map[string]*ResourceAttrDiff{ 449 "name": &ResourceAttrDiff{ 450 Old: "", 451 New: "foo", 452 }, 453 }, 454 }, 455 }, 456 }, 457 458 &ModuleDiff{ 459 Path: []string{"root", "child2"}, 460 Resources: map[string]*InstanceDiff{ 461 "null_resource.foo": &InstanceDiff{ 462 Attributes: map[string]*ResourceAttrDiff{ 463 "name": &ResourceAttrDiff{ 464 Old: "", 465 New: "foo", 466 }, 467 }, 468 }, 469 }, 470 }, 471 }, 472 } 473 474 b := &ApplyGraphBuilder{ 475 Module: testModule(t, "graph-builder-apply-target-module"), 476 Diff: diff, 477 Providers: []string{"null"}, 478 Targets: []string{"module.child2"}, 479 } 480 481 g, err := b.Build(RootModulePath) 482 if err != nil { 483 t.Fatalf("err: %s", err) 484 } 485 486 testGraphNotContains(t, g, "module.child1.output.instance_id") 487 } 488 489 const testApplyGraphBuilderStr = ` 490 aws_instance.create 491 provider.aws 492 aws_instance.other 493 aws_instance.create 494 provider.aws 495 meta.count-boundary (count boundary fixup) 496 aws_instance.create 497 aws_instance.other 498 module.child.aws_instance.create 499 module.child.aws_instance.other 500 module.child.provider.aws 501 module.child.provisioner.exec 502 provider.aws 503 module.child.aws_instance.create 504 module.child.provider.aws 505 module.child.provisioner.exec 506 module.child.aws_instance.other 507 module.child.aws_instance.create 508 module.child.provider.aws 509 module.child.provider.aws 510 provider.aws 511 module.child.provisioner.exec 512 provider.aws 513 provider.aws (close) 514 aws_instance.create 515 aws_instance.other 516 module.child.aws_instance.create 517 module.child.aws_instance.other 518 provider.aws 519 provisioner.exec (close) 520 module.child.aws_instance.create 521 root 522 meta.count-boundary (count boundary fixup) 523 provider.aws (close) 524 provisioner.exec (close) 525 ` 526 527 const testApplyGraphBuilderDoubleCBDStr = ` 528 aws_instance.A 529 provider.aws 530 aws_instance.A (destroy) 531 aws_instance.A 532 aws_instance.B 533 aws_instance.B (destroy) 534 provider.aws 535 aws_instance.B 536 aws_instance.A 537 provider.aws 538 aws_instance.B (destroy) 539 aws_instance.B 540 provider.aws 541 meta.count-boundary (count boundary fixup) 542 aws_instance.A 543 aws_instance.A (destroy) 544 aws_instance.B 545 aws_instance.B (destroy) 546 provider.aws 547 provider.aws 548 provider.aws (close) 549 aws_instance.A 550 aws_instance.A (destroy) 551 aws_instance.B 552 aws_instance.B (destroy) 553 provider.aws 554 root 555 meta.count-boundary (count boundary fixup) 556 provider.aws (close) 557 ` 558 559 const testApplyGraphBuilderDestroyCountStr = ` 560 aws_instance.A[1] (destroy) 561 provider.aws 562 aws_instance.B 563 aws_instance.A[1] (destroy) 564 provider.aws 565 meta.count-boundary (count boundary fixup) 566 aws_instance.A[1] (destroy) 567 aws_instance.B 568 provider.aws 569 provider.aws 570 provider.aws (close) 571 aws_instance.A[1] (destroy) 572 aws_instance.B 573 provider.aws 574 root 575 meta.count-boundary (count boundary fixup) 576 provider.aws (close) 577 `