github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/model/lifecycle_test.go (about) 1 package model 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/evergreen-ci/evergreen" 8 "github.com/evergreen-ci/evergreen/db" 9 "github.com/evergreen-ci/evergreen/model/build" 10 "github.com/evergreen-ci/evergreen/model/task" 11 "github.com/evergreen-ci/evergreen/model/version" 12 "github.com/evergreen-ci/evergreen/testutil" 13 . "github.com/smartystreets/goconvey/convey" 14 ) 15 16 func init() { 17 db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(testutil.TestConfig())) 18 } 19 20 func taskIdInSlice(tasks []task.Task, id string) bool { 21 for _, task := range tasks { 22 if task.Id == id { 23 return true 24 } 25 } 26 return false 27 } 28 29 func TestBuildSetPriority(t *testing.T) { 30 31 Convey("With a build", t, func() { 32 33 testutil.HandleTestingErr(db.ClearCollections(build.Collection, task.Collection), t, 34 "Error clearing test collection") 35 36 b := &build.Build{ 37 Id: "build", 38 } 39 So(b.Insert(), ShouldBeNil) 40 41 taskOne := &task.Task{Id: "taskOne", BuildId: b.Id} 42 So(taskOne.Insert(), ShouldBeNil) 43 44 taskTwo := &task.Task{Id: "taskTwo", BuildId: b.Id} 45 So(taskTwo.Insert(), ShouldBeNil) 46 47 taskThree := &task.Task{Id: "taskThree", BuildId: b.Id} 48 So(taskThree.Insert(), ShouldBeNil) 49 50 Convey("setting its priority should update the priority"+ 51 " of all its tasks in the database", func() { 52 53 So(SetBuildPriority(b.Id, 42), ShouldBeNil) 54 55 tasks, err := task.Find(task.ByBuildId(b.Id)) 56 So(err, ShouldBeNil) 57 So(len(tasks), ShouldEqual, 3) 58 So(tasks[0].Priority, ShouldEqual, 42) 59 So(tasks[1].Priority, ShouldEqual, 42) 60 So(tasks[2].Priority, ShouldEqual, 42) 61 }) 62 63 }) 64 65 } 66 67 func TestBuildRestart(t *testing.T) { 68 Convey("Restarting a build", t, func() { 69 70 testutil.HandleTestingErr(db.ClearCollections(build.Collection, task.Collection), t, 71 "Error clearing test collection") 72 b := &build.Build{ 73 Id: "build", 74 Tasks: []build.TaskCache{ 75 { 76 Id: "task1", 77 Status: evergreen.TaskSucceeded, 78 Activated: true, 79 }, 80 { 81 Id: "task2", 82 Status: evergreen.TaskDispatched, 83 Activated: true, 84 }, 85 { 86 Id: "task3", 87 Status: evergreen.TaskDispatched, 88 Activated: true, 89 }, 90 { 91 Id: "task4", 92 Status: evergreen.TaskDispatched, 93 Activated: true, 94 }, 95 }, 96 } 97 So(b.Insert(), ShouldBeNil) 98 99 Convey("with task abort should update the status of"+ 100 " non in-progress tasks and abort in-progress ones", func() { 101 102 taskOne := &task.Task{ 103 Id: "task1", 104 DisplayName: "task1", 105 BuildId: b.Id, 106 Status: evergreen.TaskSucceeded, 107 } 108 So(taskOne.Insert(), ShouldBeNil) 109 110 taskTwo := &task.Task{ 111 Id: "task2", 112 DisplayName: "task2", 113 BuildId: b.Id, 114 Status: evergreen.TaskDispatched, 115 } 116 So(taskTwo.Insert(), ShouldBeNil) 117 118 So(RestartBuild(b.Id, []string{"task1", "task2"}, true, evergreen.DefaultTaskActivator), ShouldBeNil) 119 b, err := build.FindOne(build.ById(b.Id)) 120 So(err, ShouldBeNil) 121 So(b.Status, ShouldEqual, evergreen.BuildCreated) 122 So(b.Activated, ShouldEqual, true) 123 So(b.Tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) 124 So(b.Tasks[1].Status, ShouldEqual, evergreen.TaskDispatched) 125 So(b.Tasks[0].Activated, ShouldEqual, true) 126 So(b.Tasks[1].Activated, ShouldEqual, true) 127 taskOne, err = task.FindOne(task.ById("task1")) 128 So(err, ShouldBeNil) 129 So(taskOne.Status, ShouldEqual, evergreen.TaskUndispatched) 130 taskTwo, err = task.FindOne(task.ById("task2")) 131 So(err, ShouldBeNil) 132 So(taskTwo.Aborted, ShouldEqual, true) 133 }) 134 135 Convey("without task abort should update the status"+ 136 " of only those build tasks not in-progress", func() { 137 138 taskThree := &task.Task{ 139 Id: "task3", 140 DisplayName: "task3", 141 BuildId: b.Id, 142 Status: evergreen.TaskSucceeded, 143 } 144 So(taskThree.Insert(), ShouldBeNil) 145 146 taskFour := &task.Task{ 147 Id: "task4", 148 DisplayName: "task4", 149 BuildId: b.Id, 150 Status: evergreen.TaskDispatched, 151 } 152 So(taskFour.Insert(), ShouldBeNil) 153 154 So(RestartBuild(b.Id, []string{"task3", "task4"}, false, evergreen.DefaultTaskActivator), ShouldBeNil) 155 b, err := build.FindOne(build.ById(b.Id)) 156 So(err, ShouldBeNil) 157 So(err, ShouldBeNil) 158 So(b.Status, ShouldEqual, evergreen.BuildCreated) 159 So(b.Activated, ShouldEqual, true) 160 So(b.Tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) 161 So(b.Tasks[3].Status, ShouldEqual, evergreen.TaskDispatched) 162 So(b.Tasks[2].Activated, ShouldEqual, true) 163 So(b.Tasks[3].Activated, ShouldEqual, true) 164 taskThree, err = task.FindOne(task.ById("task3")) 165 So(err, ShouldBeNil) 166 So(taskThree.Status, ShouldEqual, evergreen.TaskUndispatched) 167 taskFour, err = task.FindOne(task.ById("task4")) 168 So(err, ShouldBeNil) 169 So(taskFour.Aborted, ShouldEqual, false) 170 So(taskFour.Status, ShouldEqual, evergreen.TaskDispatched) 171 }) 172 173 }) 174 } 175 176 func TestBuildMarkAborted(t *testing.T) { 177 Convey("With a build", t, func() { 178 179 testutil.HandleTestingErr(db.ClearCollections(build.Collection, task.Collection, version.Collection), t, 180 "Error clearing test collection") 181 182 v := &version.Version{ 183 Id: "v", 184 BuildVariants: []version.BuildStatus{ 185 { 186 BuildVariant: "bv", 187 Activated: true, 188 }, 189 }, 190 } 191 192 So(v.Insert(), ShouldBeNil) 193 194 b := &build.Build{ 195 Id: "build", 196 Activated: true, 197 BuildVariant: "bv", 198 Version: "v", 199 } 200 So(b.Insert(), ShouldBeNil) 201 202 Convey("when marking it as aborted", func() { 203 204 Convey("it should be deactivated", func() { 205 So(AbortBuild(b.Id, evergreen.DefaultTaskActivator), ShouldBeNil) 206 b, err := build.FindOne(build.ById(b.Id)) 207 So(err, ShouldBeNil) 208 So(b.Activated, ShouldBeFalse) 209 }) 210 211 Convey("all abortable tasks for it should be aborted", func() { 212 213 // insert two abortable tasks and one non-abortable task 214 // for the correct build, and one abortable task for 215 // a different build 216 217 abortableOne := &task.Task{ 218 Id: "abortableOne", 219 BuildId: b.Id, 220 Status: evergreen.TaskStarted, 221 } 222 So(abortableOne.Insert(), ShouldBeNil) 223 224 abortableTwo := &task.Task{ 225 Id: "abortableTwo", 226 BuildId: b.Id, 227 Status: evergreen.TaskDispatched, 228 } 229 So(abortableTwo.Insert(), ShouldBeNil) 230 231 notAbortable := &task.Task{ 232 Id: "notAbortable", 233 BuildId: b.Id, 234 Status: evergreen.TaskSucceeded, 235 } 236 So(notAbortable.Insert(), ShouldBeNil) 237 238 wrongBuildId := &task.Task{ 239 Id: "wrongBuildId", 240 BuildId: "blech", 241 Status: evergreen.TaskStarted, 242 } 243 So(wrongBuildId.Insert(), ShouldBeNil) 244 245 // aborting the build should mark only the two abortable tasks 246 // with the correct build id as aborted 247 248 So(AbortBuild(b.Id, evergreen.DefaultTaskActivator), ShouldBeNil) 249 250 abortedTasks, err := task.Find(task.ByAborted(true)) 251 So(err, ShouldBeNil) 252 So(len(abortedTasks), ShouldEqual, 2) 253 So(taskIdInSlice(abortedTasks, abortableOne.Id), ShouldBeTrue) 254 So(taskIdInSlice(abortedTasks, abortableTwo.Id), ShouldBeTrue) 255 }) 256 }) 257 }) 258 } 259 260 func TestBuildSetActivated(t *testing.T) { 261 Convey("With a build", t, func() { 262 263 testutil.HandleTestingErr(db.ClearCollections(build.Collection, task.Collection), t, 264 "Error clearing test collection") 265 266 Convey("when changing the activated status of the build to true", func() { 267 Convey("the activated status of the build and all undispatched"+ 268 " tasks that are part of it should be set", func() { 269 270 user := "differentUser" 271 272 b := &build.Build{ 273 Id: "build", 274 Activated: true, 275 BuildVariant: "bv", 276 } 277 So(b.Insert(), ShouldBeNil) 278 279 // insert three tasks, with only one of them undispatched and 280 // belonging to the correct build 281 282 wrongBuildId := &task.Task{ 283 Id: "wrongBuildId", 284 BuildId: "blech", 285 Status: evergreen.TaskUndispatched, 286 Activated: true, 287 } 288 So(wrongBuildId.Insert(), ShouldBeNil) 289 290 wrongStatus := &task.Task{ 291 Id: "wrongStatus", 292 BuildId: b.Id, 293 Status: evergreen.TaskDispatched, 294 Activated: true, 295 } 296 So(wrongStatus.Insert(), ShouldBeNil) 297 298 matching := &task.Task{ 299 Id: "matching", 300 BuildId: b.Id, 301 Status: evergreen.TaskUndispatched, 302 Activated: true, 303 } 304 305 So(matching.Insert(), ShouldBeNil) 306 307 differentUser := &task.Task{ 308 Id: "differentUser", 309 BuildId: b.Id, 310 Status: evergreen.TaskUndispatched, 311 Activated: true, 312 ActivatedBy: user, 313 } 314 315 So(differentUser.Insert(), ShouldBeNil) 316 317 So(SetBuildActivation(b.Id, false, evergreen.DefaultTaskActivator), ShouldBeNil) 318 // the build should have been updated in the db 319 b, err := build.FindOne(build.ById(b.Id)) 320 So(err, ShouldBeNil) 321 So(b.Activated, ShouldBeFalse) 322 So(b.ActivatedBy, ShouldEqual, evergreen.DefaultTaskActivator) 323 324 // only the matching task should have been updated that has not been set by a user 325 deactivatedTasks, err := task.Find(task.ByActivation(false)) 326 So(err, ShouldBeNil) 327 So(len(deactivatedTasks), ShouldEqual, 1) 328 So(deactivatedTasks[0].Id, ShouldEqual, matching.Id) 329 330 // task with the different user activating should be activated with that user 331 differentUserTask, err := task.FindOne(task.ById(differentUser.Id)) 332 So(err, ShouldBeNil) 333 So(differentUserTask.Activated, ShouldBeTrue) 334 So(differentUserTask.ActivatedBy, ShouldEqual, user) 335 336 }) 337 338 Convey("all of the undispatched task caches within the build"+ 339 " should be updated, both in memory and in the"+ 340 " database", func() { 341 342 b := &build.Build{ 343 Id: "build", 344 Activated: true, 345 BuildVariant: "foo", 346 Tasks: []build.TaskCache{ 347 { 348 Id: "tc1", 349 Status: evergreen.TaskUndispatched, 350 Activated: true, 351 }, 352 { 353 Id: "tc2", 354 Status: evergreen.TaskDispatched, 355 Activated: true, 356 }, 357 { 358 Id: "tc3", 359 Status: evergreen.TaskUndispatched, 360 Activated: true, 361 }, 362 { 363 Id: "tc4", 364 Status: evergreen.TaskUndispatched, 365 Activated: true, 366 }, 367 }, 368 } 369 So(b.Insert(), ShouldBeNil) 370 371 t1 := &task.Task{Id: "tc1", DisplayName: "tc1", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true} 372 t2 := &task.Task{Id: "tc2", DisplayName: "tc2", BuildId: b.Id, Status: evergreen.TaskDispatched, Activated: true} 373 t3 := &task.Task{Id: "tc3", DisplayName: "tc3", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true} 374 t4 := &task.Task{Id: "tc4", DisplayName: "tc4", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true, ActivatedBy: "anotherUser"} 375 So(t1.Insert(), ShouldBeNil) 376 So(t2.Insert(), ShouldBeNil) 377 So(t3.Insert(), ShouldBeNil) 378 So(t4.Insert(), ShouldBeNil) 379 380 So(SetBuildActivation(b.Id, false, evergreen.DefaultTaskActivator), ShouldBeNil) 381 // refresh from the database and check again 382 b, err := build.FindOne(build.ById(b.Id)) 383 So(err, ShouldBeNil) 384 So(b.Activated, ShouldBeFalse) 385 So(b.Tasks[0].Activated, ShouldBeFalse) 386 So(b.Tasks[1].Activated, ShouldBeTrue) 387 So(b.Tasks[2].Activated, ShouldBeFalse) 388 So(b.Tasks[3].Activated, ShouldBeTrue) 389 }) 390 391 Convey("if a build is activated by a user it should not be able to be deactivated by evergreen", func() { 392 user := "differentUser" 393 394 b := &build.Build{ 395 Id: "anotherBuild", 396 Activated: true, 397 BuildVariant: "bv", 398 } 399 400 So(b.Insert(), ShouldBeNil) 401 402 matching := &task.Task{ 403 Id: "matching", 404 BuildId: b.Id, 405 Status: evergreen.TaskUndispatched, 406 Activated: false, 407 } 408 So(matching.Insert(), ShouldBeNil) 409 410 matching2 := &task.Task{ 411 Id: "matching2", 412 BuildId: b.Id, 413 Status: evergreen.TaskUndispatched, 414 Activated: false, 415 } 416 So(matching2.Insert(), ShouldBeNil) 417 418 // have a user set the build activation to true 419 So(SetBuildActivation(b.Id, true, user), ShouldBeNil) 420 421 // task with the different user activating should be activated with that user 422 task1, err := task.FindOne(task.ById(matching.Id)) 423 So(err, ShouldBeNil) 424 So(task1.Activated, ShouldBeTrue) 425 So(task1.ActivatedBy, ShouldEqual, user) 426 427 // task with the different user activating should be activated with that user 428 task2, err := task.FindOne(task.ById(matching2.Id)) 429 So(err, ShouldBeNil) 430 So(task2.Activated, ShouldBeTrue) 431 So(task2.ActivatedBy, ShouldEqual, user) 432 433 // refresh from the database and check again 434 b, err = build.FindOne(build.ById(b.Id)) 435 So(err, ShouldBeNil) 436 So(b.Activated, ShouldBeTrue) 437 So(b.ActivatedBy, ShouldEqual, user) 438 439 // deactivate the task from evergreen and nothing should be deactivated. 440 So(SetBuildActivation(b.Id, false, evergreen.DefaultTaskActivator), ShouldBeNil) 441 442 // refresh from the database and check again 443 b, err = build.FindOne(build.ById(b.Id)) 444 So(err, ShouldBeNil) 445 So(b.Activated, ShouldBeTrue) 446 So(b.ActivatedBy, ShouldEqual, user) 447 448 // task with the different user activating should be activated with that user 449 task1, err = task.FindOne(task.ById(matching.Id)) 450 So(err, ShouldBeNil) 451 So(task1.Activated, ShouldBeTrue) 452 So(task1.ActivatedBy, ShouldEqual, user) 453 454 // task with the different user activating should be activated with that user 455 task2, err = task.FindOne(task.ById(matching2.Id)) 456 So(err, ShouldBeNil) 457 So(task2.Activated, ShouldBeTrue) 458 So(task2.ActivatedBy, ShouldEqual, user) 459 460 }) 461 }) 462 463 }) 464 } 465 466 func TestBuildMarkStarted(t *testing.T) { 467 468 Convey("With a build", t, func() { 469 470 testutil.HandleTestingErr(db.Clear(build.Collection), t, "Error clearing"+ 471 " '%v' collection", build.Collection) 472 473 b := &build.Build{ 474 Id: "build", 475 Status: evergreen.BuildCreated, 476 } 477 So(b.Insert(), ShouldBeNil) 478 479 Convey("marking it as started should update the status and"+ 480 " start time, both in memory and in the database", func() { 481 482 startTime := time.Now() 483 So(build.TryMarkStarted(b.Id, startTime), ShouldBeNil) 484 485 // refresh from db and check again 486 b, err := build.FindOne(build.ById(b.Id)) 487 So(err, ShouldBeNil) 488 So(b.Status, ShouldEqual, evergreen.BuildStarted) 489 So(b.StartTime.Round(time.Second).Equal( 490 startTime.Round(time.Second)), ShouldBeTrue) 491 }) 492 }) 493 } 494 495 func TestBuildMarkFinished(t *testing.T) { 496 497 Convey("With a build", t, func() { 498 499 testutil.HandleTestingErr(db.Clear(build.Collection), t, "Error clearing"+ 500 " '%v' collection", build.Collection) 501 502 startTime := time.Now() 503 b := &build.Build{ 504 Id: "build", 505 StartTime: startTime, 506 } 507 So(b.Insert(), ShouldBeNil) 508 509 Convey("marking it as finished should update the status,"+ 510 " finish time, and duration, both in memory and in the"+ 511 " database", func() { 512 513 finishTime := time.Now() 514 So(b.MarkFinished(evergreen.BuildSucceeded, finishTime), ShouldBeNil) 515 So(b.Status, ShouldEqual, evergreen.BuildSucceeded) 516 So(b.FinishTime.Equal(finishTime), ShouldBeTrue) 517 So(b.TimeTaken, ShouldEqual, finishTime.Sub(startTime)) 518 519 // refresh from db and check again 520 521 b, err := build.FindOne(build.ById(b.Id)) 522 So(err, ShouldBeNil) 523 So(b.Status, ShouldEqual, evergreen.BuildSucceeded) 524 So(b.FinishTime.Round(time.Second).Equal( 525 finishTime.Round(time.Second)), ShouldBeTrue) 526 So(b.TimeTaken, ShouldEqual, finishTime.Sub(startTime)) 527 }) 528 }) 529 } 530 531 func TestCreateBuildFromVersion(t *testing.T) { 532 533 Convey("When creating a build from a version", t, func() { 534 535 testutil.HandleTestingErr(db.ClearCollections(build.Collection, task.Collection), t, 536 "Error clearing test collection") 537 538 // the mock build variant we'll be using. runs all three tasks 539 buildVar1 := BuildVariant{ 540 Name: "buildVar", 541 DisplayName: "Build Variant", 542 Tasks: []BuildVariantTask{ 543 {Name: "taskA"}, {Name: "taskB"}, {Name: "taskC"}, {Name: "taskD"}, 544 }, 545 } 546 buildVar2 := BuildVariant{ 547 Name: "buildVar2", 548 DisplayName: "Build Variant 2", 549 Tasks: []BuildVariantTask{ 550 {Name: "taskA"}, {Name: "taskB"}, {Name: "taskC"}, {Name: "taskE"}, 551 }, 552 } 553 buildVar3 := BuildVariant{ 554 Name: "buildVar3", 555 DisplayName: "Build Variant 3", 556 Tasks: []BuildVariantTask{ 557 { 558 // wait for the first BV's taskA to complete 559 Name: "taskA", 560 DependsOn: []TaskDependency{{Name: "taskA", Variant: "buildVar"}}, 561 }, 562 }, 563 } 564 565 project := &Project{ 566 Tasks: []ProjectTask{ 567 { 568 Name: "taskA", 569 Priority: 5, 570 Tags: []string{"tag1", "tag2"}, 571 DependsOn: []TaskDependency{}, 572 }, 573 { 574 Name: "taskB", 575 Tags: []string{"tag1", "tag2"}, 576 DependsOn: []TaskDependency{{Name: "taskA", Variant: "buildVar"}}, 577 }, 578 { 579 Name: "taskC", 580 Tags: []string{"tag1", "tag2"}, 581 DependsOn: []TaskDependency{ 582 {Name: "taskA"}, 583 {Name: "taskB"}, 584 }, 585 }, 586 { 587 Name: "taskD", 588 Tags: []string{"tag1", "tag2"}, 589 DependsOn: []TaskDependency{{Name: AllDependencies}}, 590 }, 591 { 592 Name: "taskE", 593 Tags: []string{"tag1", "tag2"}, 594 DependsOn: []TaskDependency{ 595 { 596 Name: AllDependencies, 597 Variant: AllVariants, 598 }, 599 }, 600 }, 601 }, 602 BuildVariants: []BuildVariant{buildVar1, buildVar2, buildVar3}, 603 } 604 605 // the mock version we'll be using 606 v := &version.Version{ 607 Id: "versionId", 608 CreateTime: time.Now(), 609 Revision: "foobar", 610 RevisionOrderNumber: 500, 611 Requester: evergreen.RepotrackerVersionRequester, 612 BuildVariants: []version.BuildStatus{ 613 { 614 BuildVariant: buildVar1.Name, 615 Activated: false, 616 }, 617 { 618 BuildVariant: buildVar2.Name, 619 Activated: false, 620 }, 621 { 622 BuildVariant: buildVar3.Name, 623 Activated: false, 624 }, 625 }, 626 } 627 628 tt := NewTaskIdTable(project, v) 629 630 Convey("the task id table should be well-formed", func() { 631 So(tt.GetId("buildVar", "taskA"), ShouldNotEqual, "") 632 So(tt.GetId("buildVar", "taskB"), ShouldNotEqual, "") 633 So(tt.GetId("buildVar", "taskC"), ShouldNotEqual, "") 634 So(tt.GetId("buildVar", "taskD"), ShouldNotEqual, "") 635 So(tt.GetId("buildVar2", "taskA"), ShouldNotEqual, "") 636 So(tt.GetId("buildVar2", "taskB"), ShouldNotEqual, "") 637 So(tt.GetId("buildVar2", "taskC"), ShouldNotEqual, "") 638 So(tt.GetId("buildVar2", "taskE"), ShouldNotEqual, "") 639 So(tt.GetId("buildVar3", "taskA"), ShouldNotEqual, "") 640 641 Convey(`and incorrect GetId() calls should return ""`, func() { 642 So(tt.GetId("buildVar", "taskF"), ShouldEqual, "") 643 So(tt.GetId("buildVar2", "taskD"), ShouldEqual, "") 644 So(tt.GetId("buildVar7", "taskA"), ShouldEqual, "") 645 }) 646 }) 647 648 Convey("if a non-existent build variant is passed in, an error should be returned", func() { 649 650 buildId, err := CreateBuildFromVersion(project, v, tt, "blecch", false, []string{}) 651 So(err, ShouldNotBeNil) 652 So(buildId, ShouldEqual, "") 653 654 }) 655 656 Convey("if no task names are passed in to be used, all of the default"+ 657 " tasks for the build variant should be created", func() { 658 659 buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) 660 So(err, ShouldBeNil) 661 So(buildId, ShouldNotEqual, "") 662 buildId2, err := CreateBuildFromVersion(project, v, tt, buildVar2.Name, false, nil) 663 So(err, ShouldBeNil) 664 So(buildId2, ShouldNotEqual, "") 665 666 // find the tasks, make sure they were all created 667 tasks, err := task.Find(task.All) 668 So(err, ShouldBeNil) 669 So(len(tasks), ShouldEqual, 8) 670 So(len(tasks[0].Tags), ShouldEqual, 2) 671 672 }) 673 674 Convey("if a non-empty list of task names is passed in, only the"+ 675 " specified tasks should be created", func() { 676 677 buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, 678 []string{"taskA", "taskB"}) 679 So(err, ShouldBeNil) 680 So(buildId, ShouldNotEqual, "") 681 682 // find the tasks, make sure they were all created 683 tasks, err := task.Find(task.All) 684 So(err, ShouldBeNil) 685 So(len(tasks), ShouldEqual, 2) 686 687 }) 688 689 Convey("the build should contain task caches that correspond exactly"+ 690 " to the tasks created", func() { 691 692 buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) 693 So(err, ShouldBeNil) 694 So(buildId, ShouldNotEqual, "") 695 696 // find the tasks, make sure they were all created 697 tasks, err := task.Find(task.All) 698 So(err, ShouldBeNil) 699 So(len(tasks), ShouldEqual, 4) 700 701 // find the build from the db 702 b, err := build.FindOne(build.ById(buildId)) 703 So(err, ShouldBeNil) 704 So(len(b.Tasks), ShouldEqual, 4) 705 706 // make sure the task caches are correct. they should also appear 707 // in the same order that they appear in the project file 708 So(b.Tasks[0].Id, ShouldNotEqual, "") 709 So(b.Tasks[0].DisplayName, ShouldEqual, "taskA") 710 So(b.Tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) 711 So(b.Tasks[1].Id, ShouldNotEqual, "") 712 So(b.Tasks[1].DisplayName, ShouldEqual, "taskB") 713 So(b.Tasks[1].Status, ShouldEqual, evergreen.TaskUndispatched) 714 So(b.Tasks[2].Id, ShouldNotEqual, "") 715 So(b.Tasks[2].DisplayName, ShouldEqual, "taskC") 716 So(b.Tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) 717 So(b.Tasks[3].Id, ShouldNotEqual, "") 718 So(b.Tasks[3].DisplayName, ShouldEqual, "taskD") 719 So(b.Tasks[3].Status, ShouldEqual, evergreen.TaskUndispatched) 720 721 }) 722 723 Convey("all of the tasks created should have the dependencies"+ 724 "and priorities specified in the project", func() { 725 726 buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) 727 So(err, ShouldBeNil) 728 So(buildId, ShouldNotEqual, "") 729 buildId2, err := CreateBuildFromVersion(project, v, tt, buildVar2.Name, false, nil) 730 So(err, ShouldBeNil) 731 So(buildId2, ShouldNotEqual, "") 732 buildId3, err := CreateBuildFromVersion(project, v, tt, buildVar3.Name, false, nil) 733 So(err, ShouldBeNil) 734 So(buildId3, ShouldNotEqual, "") 735 736 // find the tasks, make sure they were all created 737 tasks, err := task.Find(task.All.Sort([]string{task.DisplayNameKey, task.BuildVariantKey})) 738 So(err, ShouldBeNil) 739 So(len(tasks), ShouldEqual, 9) 740 741 // taskA 742 So(len(tasks[0].DependsOn), ShouldEqual, 0) 743 So(len(tasks[1].DependsOn), ShouldEqual, 0) 744 So(len(tasks[2].DependsOn), ShouldEqual, 1) 745 So(tasks[0].Priority, ShouldEqual, 5) 746 So(tasks[1].Priority, ShouldEqual, 5) 747 So(tasks[2].DependsOn, ShouldResemble, 748 []task.Dependency{{tasks[0].Id, evergreen.TaskSucceeded}}) 749 750 // taskB 751 So(tasks[3].DependsOn, ShouldResemble, 752 []task.Dependency{{tasks[0].Id, evergreen.TaskSucceeded}}) 753 So(tasks[4].DependsOn, ShouldResemble, 754 []task.Dependency{{tasks[0].Id, evergreen.TaskSucceeded}}) //cross-variant 755 So(tasks[3].Priority, ShouldEqual, 0) 756 So(tasks[4].Priority, ShouldEqual, 0) //default priority 757 758 // taskC 759 So(tasks[5].DependsOn, ShouldResemble, 760 []task.Dependency{ 761 {tasks[0].Id, evergreen.TaskSucceeded}, 762 {tasks[3].Id, evergreen.TaskSucceeded}}) 763 So(tasks[6].DependsOn, ShouldResemble, 764 []task.Dependency{ 765 {tasks[1].Id, evergreen.TaskSucceeded}, 766 {tasks[4].Id, evergreen.TaskSucceeded}}) 767 So(tasks[7].DependsOn, ShouldResemble, 768 []task.Dependency{ 769 {tasks[0].Id, evergreen.TaskSucceeded}, 770 {tasks[3].Id, evergreen.TaskSucceeded}, 771 {tasks[5].Id, evergreen.TaskSucceeded}}) 772 So(tasks[8].DisplayName, ShouldEqual, "taskE") 773 So(len(tasks[8].DependsOn), ShouldEqual, 8) 774 }) 775 776 Convey("all of the build's essential fields should be set"+ 777 " correctly", func() { 778 779 buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) 780 So(err, ShouldBeNil) 781 So(buildId, ShouldNotEqual, "") 782 783 // find the build from the db 784 b, err := build.FindOne(build.ById(buildId)) 785 So(err, ShouldBeNil) 786 787 // verify all the fields are set appropriately 788 So(len(b.Tasks), ShouldEqual, 4) 789 So(b.CreateTime.Truncate(time.Second), ShouldResemble, 790 v.CreateTime.Truncate(time.Second)) 791 So(b.PushTime.Truncate(time.Second), ShouldResemble, 792 v.CreateTime.Truncate(time.Second)) 793 So(b.Activated, ShouldEqual, v.BuildVariants[0].Activated) 794 So(b.Project, ShouldEqual, project.Identifier) 795 So(b.Revision, ShouldEqual, v.Revision) 796 So(b.Status, ShouldEqual, evergreen.BuildCreated) 797 So(b.BuildVariant, ShouldEqual, buildVar1.Name) 798 So(b.Version, ShouldEqual, v.Id) 799 So(b.DisplayName, ShouldEqual, buildVar1.DisplayName) 800 So(b.RevisionOrderNumber, ShouldEqual, v.RevisionOrderNumber) 801 So(b.Requester, ShouldEqual, v.Requester) 802 803 }) 804 805 Convey("all of the tasks' essential fields should be set"+ 806 " correctly", func() { 807 808 buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) 809 So(err, ShouldBeNil) 810 So(buildId, ShouldNotEqual, "") 811 812 // find the build from the db 813 b, err := build.FindOne(build.ById(buildId)) 814 So(err, ShouldBeNil) 815 816 // find the tasks, make sure they were all created 817 tasks, err := task.Find(task.All.Sort([]string{task.DisplayNameKey})) 818 So(err, ShouldBeNil) 819 So(len(tasks), ShouldEqual, 4) 820 821 So(tasks[0].Id, ShouldNotEqual, "") 822 So(tasks[0].Secret, ShouldNotEqual, "") 823 So(tasks[0].DisplayName, ShouldEqual, "taskA") 824 So(tasks[0].BuildId, ShouldEqual, buildId) 825 So(tasks[0].DistroId, ShouldEqual, "") 826 So(tasks[0].BuildVariant, ShouldEqual, buildVar1.Name) 827 So(tasks[0].CreateTime.Truncate(time.Second), ShouldResemble, 828 b.CreateTime.Truncate(time.Second)) 829 So(tasks[0].PushTime.Truncate(time.Second), ShouldResemble, 830 b.PushTime.Truncate(time.Second)) 831 So(tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) 832 So(tasks[0].Activated, ShouldEqual, b.Activated) 833 So(tasks[0].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) 834 So(tasks[0].Requester, ShouldEqual, b.Requester) 835 So(tasks[0].Version, ShouldEqual, v.Id) 836 So(tasks[0].Revision, ShouldEqual, v.Revision) 837 So(tasks[0].Project, ShouldEqual, project.Identifier) 838 839 So(tasks[1].Id, ShouldNotEqual, "") 840 So(tasks[1].Secret, ShouldNotEqual, "") 841 So(tasks[1].DisplayName, ShouldEqual, "taskB") 842 So(tasks[1].BuildId, ShouldEqual, buildId) 843 So(tasks[1].DistroId, ShouldEqual, "") 844 So(tasks[1].BuildVariant, ShouldEqual, buildVar1.Name) 845 So(tasks[1].CreateTime.Truncate(time.Second), ShouldResemble, 846 b.CreateTime.Truncate(time.Second)) 847 So(tasks[1].PushTime.Truncate(time.Second), ShouldResemble, 848 b.PushTime.Truncate(time.Second)) 849 So(tasks[1].Status, ShouldEqual, evergreen.TaskUndispatched) 850 So(tasks[1].Activated, ShouldEqual, b.Activated) 851 So(tasks[1].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) 852 So(tasks[1].Requester, ShouldEqual, b.Requester) 853 So(tasks[1].Version, ShouldEqual, v.Id) 854 So(tasks[1].Revision, ShouldEqual, v.Revision) 855 So(tasks[1].Project, ShouldEqual, project.Identifier) 856 857 So(tasks[2].Id, ShouldNotEqual, "") 858 So(tasks[2].Secret, ShouldNotEqual, "") 859 So(tasks[2].DisplayName, ShouldEqual, "taskC") 860 So(tasks[2].BuildId, ShouldEqual, buildId) 861 So(tasks[2].DistroId, ShouldEqual, "") 862 So(tasks[2].BuildVariant, ShouldEqual, buildVar1.Name) 863 So(tasks[2].CreateTime.Truncate(time.Second), ShouldResemble, 864 b.CreateTime.Truncate(time.Second)) 865 So(tasks[2].PushTime.Truncate(time.Second), ShouldResemble, 866 b.PushTime.Truncate(time.Second)) 867 So(tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) 868 So(tasks[2].Activated, ShouldEqual, b.Activated) 869 So(tasks[2].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) 870 So(tasks[2].Requester, ShouldEqual, b.Requester) 871 So(tasks[2].Version, ShouldEqual, v.Id) 872 So(tasks[2].Revision, ShouldEqual, v.Revision) 873 So(tasks[2].Project, ShouldEqual, project.Identifier) 874 875 So(tasks[3].Id, ShouldNotEqual, "") 876 So(tasks[3].Secret, ShouldNotEqual, "") 877 So(tasks[3].DisplayName, ShouldEqual, "taskD") 878 So(tasks[3].BuildId, ShouldEqual, buildId) 879 So(tasks[3].DistroId, ShouldEqual, "") 880 So(tasks[3].BuildVariant, ShouldEqual, buildVar1.Name) 881 So(tasks[3].CreateTime.Truncate(time.Second), ShouldResemble, 882 b.CreateTime.Truncate(time.Second)) 883 So(tasks[3].PushTime.Truncate(time.Second), ShouldResemble, 884 b.PushTime.Truncate(time.Second)) 885 So(tasks[3].Status, ShouldEqual, evergreen.TaskUndispatched) 886 So(tasks[3].Activated, ShouldEqual, b.Activated) 887 So(tasks[3].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) 888 So(tasks[3].Requester, ShouldEqual, b.Requester) 889 So(tasks[3].Version, ShouldEqual, v.Id) 890 So(tasks[3].Revision, ShouldEqual, v.Revision) 891 So(tasks[3].Project, ShouldEqual, project.Identifier) 892 }) 893 894 Convey("if the activated flag is set, the build and all its tasks should be activated", 895 func() { 896 897 buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, true, nil) 898 So(err, ShouldBeNil) 899 So(buildId, ShouldNotEqual, "") 900 901 // find the build from the db 902 build, err := build.FindOne(build.ById(buildId)) 903 So(err, ShouldBeNil) 904 So(build.Activated, ShouldBeTrue) 905 906 // find the tasks, make sure they were all created 907 tasks, err := task.Find(task.All.Sort([]string{task.DisplayNameKey})) 908 So(err, ShouldBeNil) 909 So(len(tasks), ShouldEqual, 4) 910 911 So(tasks[0].Id, ShouldNotEqual, "") 912 So(tasks[0].Secret, ShouldNotEqual, "") 913 So(tasks[0].DisplayName, ShouldEqual, "taskA") 914 So(tasks[0].BuildId, ShouldEqual, buildId) 915 So(tasks[0].DistroId, ShouldEqual, "") 916 So(tasks[0].BuildVariant, ShouldEqual, buildVar1.Name) 917 So(tasks[0].CreateTime.Truncate(time.Second), ShouldResemble, 918 build.CreateTime.Truncate(time.Second)) 919 So(tasks[0].PushTime.Truncate(time.Second), ShouldResemble, 920 build.PushTime.Truncate(time.Second)) 921 So(tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) 922 So(tasks[0].Activated, ShouldEqual, build.Activated) 923 So(tasks[0].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) 924 So(tasks[0].Requester, ShouldEqual, build.Requester) 925 So(tasks[0].Version, ShouldEqual, v.Id) 926 So(tasks[0].Revision, ShouldEqual, v.Revision) 927 So(tasks[0].Project, ShouldEqual, project.Identifier) 928 929 So(tasks[1].Id, ShouldNotEqual, "") 930 So(tasks[1].Secret, ShouldNotEqual, "") 931 So(tasks[1].DisplayName, ShouldEqual, "taskB") 932 So(tasks[1].BuildId, ShouldEqual, buildId) 933 So(tasks[1].DistroId, ShouldEqual, "") 934 So(tasks[1].BuildVariant, ShouldEqual, buildVar1.Name) 935 So(tasks[1].CreateTime.Truncate(time.Second), ShouldResemble, 936 build.CreateTime.Truncate(time.Second)) 937 So(tasks[1].PushTime.Truncate(time.Second), ShouldResemble, 938 build.PushTime.Truncate(time.Second)) 939 So(tasks[1].Status, ShouldEqual, evergreen.TaskUndispatched) 940 So(tasks[1].Activated, ShouldEqual, build.Activated) 941 So(tasks[1].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) 942 So(tasks[1].Requester, ShouldEqual, build.Requester) 943 So(tasks[1].Version, ShouldEqual, v.Id) 944 So(tasks[1].Revision, ShouldEqual, v.Revision) 945 So(tasks[1].Project, ShouldEqual, project.Identifier) 946 947 So(tasks[2].Id, ShouldNotEqual, "") 948 So(tasks[2].Secret, ShouldNotEqual, "") 949 So(tasks[2].DisplayName, ShouldEqual, "taskC") 950 So(tasks[2].BuildId, ShouldEqual, buildId) 951 So(tasks[2].DistroId, ShouldEqual, "") 952 So(tasks[2].BuildVariant, ShouldEqual, buildVar1.Name) 953 So(tasks[2].CreateTime.Truncate(time.Second), ShouldResemble, 954 build.CreateTime.Truncate(time.Second)) 955 So(tasks[2].PushTime.Truncate(time.Second), ShouldResemble, 956 build.PushTime.Truncate(time.Second)) 957 So(tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) 958 So(tasks[2].Activated, ShouldEqual, build.Activated) 959 So(tasks[2].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) 960 So(tasks[2].Requester, ShouldEqual, build.Requester) 961 So(tasks[2].Version, ShouldEqual, v.Id) 962 So(tasks[2].Revision, ShouldEqual, v.Revision) 963 So(tasks[2].Project, ShouldEqual, project.Identifier) 964 965 So(tasks[3].Id, ShouldNotEqual, "") 966 So(tasks[3].Secret, ShouldNotEqual, "") 967 So(tasks[3].DisplayName, ShouldEqual, "taskD") 968 So(tasks[3].BuildId, ShouldEqual, buildId) 969 So(tasks[3].DistroId, ShouldEqual, "") 970 So(tasks[3].BuildVariant, ShouldEqual, buildVar1.Name) 971 So(tasks[3].CreateTime.Truncate(time.Second), ShouldResemble, 972 build.CreateTime.Truncate(time.Second)) 973 So(tasks[3].PushTime.Truncate(time.Second), ShouldResemble, 974 build.PushTime.Truncate(time.Second)) 975 So(tasks[3].Status, ShouldEqual, evergreen.TaskUndispatched) 976 So(tasks[3].Activated, ShouldEqual, build.Activated) 977 So(tasks[3].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) 978 So(tasks[3].Requester, ShouldEqual, build.Requester) 979 So(tasks[3].Version, ShouldEqual, v.Id) 980 So(tasks[3].Revision, ShouldEqual, v.Revision) 981 So(tasks[3].Project, ShouldEqual, project.Identifier) 982 }) 983 984 }) 985 } 986 987 func TestDeletingBuild(t *testing.T) { 988 989 Convey("With a build", t, func() { 990 991 testutil.HandleTestingErr(db.Clear(build.Collection), t, "Error clearing"+ 992 " '%v' collection", build.Collection) 993 994 b := &build.Build{ 995 Id: "build", 996 } 997 So(b.Insert(), ShouldBeNil) 998 999 Convey("deleting it should remove it and all its associated"+ 1000 " tasks from the database", func() { 1001 1002 testutil.HandleTestingErr(db.ClearCollections(task.Collection), t, "Error"+ 1003 " clearing '%v' collection", task.Collection) 1004 1005 // insert two tasks that are part of the build, and one that isn't 1006 matchingTaskOne := &task.Task{ 1007 Id: "matchingOne", 1008 BuildId: b.Id, 1009 } 1010 So(matchingTaskOne.Insert(), ShouldBeNil) 1011 1012 matchingTaskTwo := &task.Task{ 1013 Id: "matchingTwo", 1014 BuildId: b.Id, 1015 } 1016 So(matchingTaskTwo.Insert(), ShouldBeNil) 1017 1018 nonMatchingTask := &task.Task{ 1019 Id: "nonMatching", 1020 BuildId: "blech", 1021 } 1022 So(nonMatchingTask.Insert(), ShouldBeNil) 1023 1024 // delete the build, make sure only it and its tasks are deleted 1025 1026 So(DeleteBuild(b.Id), ShouldBeNil) 1027 1028 b, err := build.FindOne(build.ById(b.Id)) 1029 So(err, ShouldBeNil) 1030 So(b, ShouldBeNil) 1031 1032 matchingTasks, err := task.Find(task.ByBuildId("build")) 1033 So(err, ShouldBeNil) 1034 So(len(matchingTasks), ShouldEqual, 0) 1035 1036 nonMatchingTask, err = task.FindOne(task.ById(nonMatchingTask.Id)) 1037 So(err, ShouldBeNil) 1038 So(nonMatchingTask, ShouldNotBeNil) 1039 }) 1040 }) 1041 } 1042 1043 func TestSetNumDeps(t *testing.T) { 1044 Convey("setNumDeps correctly sets NumDependents for each task", t, func() { 1045 tasks := []*task.Task{ 1046 {Id: "task1"}, 1047 { 1048 Id: "task2", 1049 DependsOn: []task.Dependency{{TaskId: "task1"}}, 1050 }, 1051 { 1052 Id: "task3", 1053 DependsOn: []task.Dependency{{TaskId: "task1"}}, 1054 }, 1055 { 1056 Id: "task4", 1057 DependsOn: []task.Dependency{{TaskId: "task2"}, {TaskId: "task3"}, {TaskId: "not_here"}}, 1058 }, 1059 } 1060 setNumDeps(tasks) 1061 So(len(tasks), ShouldEqual, 4) 1062 So(tasks[0].NumDependents, ShouldEqual, 3) 1063 So(tasks[1].NumDependents, ShouldEqual, 1) 1064 So(tasks[2].NumDependents, ShouldEqual, 1) 1065 So(tasks[3].NumDependents, ShouldEqual, 0) 1066 }) 1067 } 1068 1069 func TestSortTasks(t *testing.T) { 1070 Convey("sortTasks topologically sorts tasks by dependency", t, func() { 1071 Convey("for tasks with single dependencies", func() { 1072 tasks := []task.Task{ 1073 { 1074 Id: "idA", 1075 DisplayName: "A", 1076 DependsOn: []task.Dependency{ 1077 {TaskId: "idB"}, 1078 }, 1079 }, 1080 { 1081 Id: "idB", 1082 DisplayName: "B", 1083 DependsOn: []task.Dependency{ 1084 {TaskId: "idC"}, 1085 }, 1086 }, 1087 { 1088 Id: "idC", 1089 DisplayName: "C", 1090 }, 1091 } 1092 1093 sortedTasks := sortTasks(tasks) 1094 So(len(sortedTasks), ShouldEqual, 3) 1095 So(sortedTasks[0].DisplayName, ShouldEqual, "C") 1096 So(sortedTasks[1].DisplayName, ShouldEqual, "B") 1097 So(sortedTasks[2].DisplayName, ShouldEqual, "A") 1098 }) 1099 Convey("for tasks with multiplie dependencies", func() { 1100 tasks := []task.Task{ 1101 { 1102 Id: "idA", 1103 DisplayName: "A", 1104 DependsOn: []task.Dependency{ 1105 {TaskId: "idB"}, 1106 {TaskId: "idC"}, 1107 }, 1108 }, 1109 { 1110 Id: "idB", 1111 DisplayName: "B", 1112 DependsOn: []task.Dependency{ 1113 {TaskId: "idC"}, 1114 }, 1115 }, 1116 { 1117 Id: "idC", 1118 DisplayName: "C", 1119 }, 1120 } 1121 1122 sortedTasks := sortTasks(tasks) 1123 So(len(sortedTasks), ShouldEqual, 3) 1124 So(sortedTasks[0].DisplayName, ShouldEqual, "C") 1125 So(sortedTasks[1].DisplayName, ShouldEqual, "B") 1126 So(sortedTasks[2].DisplayName, ShouldEqual, "A") 1127 }) 1128 }) 1129 1130 Convey("grouping tasks by common dependencies and sorting alphabetically within groups", t, func() { 1131 tasks := []task.Task{ 1132 { 1133 Id: "idA", 1134 DisplayName: "A", 1135 DependsOn: []task.Dependency{ 1136 {TaskId: "idE"}, 1137 }, 1138 }, 1139 { 1140 Id: "idB", 1141 DisplayName: "B", 1142 DependsOn: []task.Dependency{ 1143 {TaskId: "idD"}, 1144 }, 1145 }, 1146 { 1147 Id: "idC", 1148 DisplayName: "C", 1149 DependsOn: []task.Dependency{ 1150 {TaskId: "idD"}, 1151 }, 1152 }, 1153 { 1154 Id: "idD", 1155 DisplayName: "D", 1156 }, 1157 { 1158 Id: "idE", 1159 DisplayName: "E", 1160 }, 1161 } 1162 1163 sortedTasks := sortTasks(tasks) 1164 So(len(sortedTasks), ShouldEqual, 5) 1165 So(sortedTasks[0].DisplayName, ShouldEqual, "D") 1166 So(sortedTasks[1].DisplayName, ShouldEqual, "E") 1167 So(sortedTasks[2].DisplayName, ShouldEqual, "B") 1168 So(sortedTasks[3].DisplayName, ShouldEqual, "C") 1169 So(sortedTasks[4].DisplayName, ShouldEqual, "A") 1170 }) 1171 1172 Convey("special-casing tasks with cross-variant dependencies to the far right", t, func() { 1173 tasks := []task.Task{ 1174 { 1175 Id: "idA", 1176 DisplayName: "A", 1177 DependsOn: []task.Dependency{ 1178 {TaskId: "idB"}, 1179 {TaskId: "idC"}, 1180 }, 1181 }, 1182 { 1183 Id: "idB", 1184 DisplayName: "B", 1185 DependsOn: []task.Dependency{ 1186 {TaskId: "idC"}, 1187 }, 1188 }, 1189 { 1190 Id: "idC", 1191 DisplayName: "C", 1192 DependsOn: []task.Dependency{ 1193 {TaskId: "cross-variant"}, 1194 }, 1195 }, 1196 { 1197 Id: "idD", 1198 DisplayName: "D", 1199 }, 1200 } 1201 1202 sortedTasks := sortTasks(tasks) 1203 So(len(sortedTasks), ShouldEqual, 4) 1204 So(sortedTasks[0].DisplayName, ShouldEqual, "D") 1205 So(sortedTasks[1].DisplayName, ShouldEqual, "C") 1206 So(sortedTasks[2].DisplayName, ShouldEqual, "B") 1207 So(sortedTasks[3].DisplayName, ShouldEqual, "A") 1208 1209 Convey("when there are cross-variant dependencies on different tasks", func() { 1210 1211 tasks = append(tasks, 1212 task.Task{ 1213 Id: "idE", 1214 DisplayName: "E", 1215 DependsOn: []task.Dependency{ 1216 {TaskId: "cross-variant2"}, 1217 }}, 1218 task.Task{ 1219 Id: "idF", 1220 DisplayName: "F", 1221 DependsOn: []task.Dependency{ 1222 {TaskId: "idE"}, 1223 }}) 1224 sortedTasks = sortTasks(tasks) 1225 So(len(sortedTasks), ShouldEqual, 6) 1226 So(sortedTasks[0].DisplayName, ShouldEqual, "D") 1227 So(sortedTasks[1].DisplayName, ShouldEqual, "C") 1228 So(sortedTasks[2].DisplayName, ShouldEqual, "E") 1229 So(sortedTasks[3].DisplayName, ShouldEqual, "B") 1230 So(sortedTasks[4].DisplayName, ShouldEqual, "F") 1231 So(sortedTasks[5].DisplayName, ShouldEqual, "A") 1232 }) 1233 }) 1234 }