github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/model/task/task_test.go (about) 1 package task 2 3 import ( 4 "testing" 5 "time" 6 7 "github.com/evergreen-ci/evergreen" 8 "github.com/evergreen-ci/evergreen/apimodels" 9 "github.com/evergreen-ci/evergreen/db" 10 "github.com/evergreen-ci/evergreen/model/build" 11 "github.com/evergreen-ci/evergreen/model/distro" 12 "github.com/evergreen-ci/evergreen/model/host" 13 "github.com/evergreen-ci/evergreen/testutil" 14 "github.com/evergreen-ci/evergreen/util" 15 "github.com/mongodb/grip" 16 . "github.com/smartystreets/goconvey/convey" 17 "gopkg.in/mgo.v2/bson" 18 ) 19 20 var ( 21 conf = testutil.TestConfig() 22 oneMs = time.Millisecond 23 ) 24 25 func init() { 26 db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(conf)) 27 grip.CatchError(grip.SetSender(testutil.SetupTestSender(""))) 28 } 29 30 var depTaskIds = []Dependency{ 31 {"td1", evergreen.TaskSucceeded}, 32 {"td2", evergreen.TaskSucceeded}, 33 {"td3", ""}, // Default == "success" 34 {"td4", evergreen.TaskFailed}, 35 {"td5", AllStatuses}, 36 } 37 38 // update statuses of test tasks in the db 39 func updateTestDepTasks(t *testing.T) { 40 // cases for success/default 41 for _, depTaskId := range depTaskIds[:3] { 42 testutil.HandleTestingErr(UpdateOne( 43 bson.M{"_id": depTaskId.TaskId}, 44 bson.M{"$set": bson.M{"status": evergreen.TaskSucceeded}}, 45 ), t, "Error setting task status") 46 } 47 // cases for * and failure 48 for _, depTaskId := range depTaskIds[3:] { 49 testutil.HandleTestingErr(UpdateOne( 50 bson.M{"_id": depTaskId.TaskId}, 51 bson.M{"$set": bson.M{"status": evergreen.TaskFailed}}, 52 ), t, "Error setting task status") 53 } 54 } 55 56 func TestDependenciesMet(t *testing.T) { 57 58 var taskId string 59 var task *Task 60 var depTasks []*Task 61 62 Convey("With a task", t, func() { 63 64 taskId = "t1" 65 66 task = &Task{ 67 Id: taskId, 68 } 69 70 depTasks = []*Task{ 71 {Id: depTaskIds[0].TaskId, Status: evergreen.TaskUndispatched}, 72 {Id: depTaskIds[1].TaskId, Status: evergreen.TaskUndispatched}, 73 {Id: depTaskIds[2].TaskId, Status: evergreen.TaskUndispatched}, 74 {Id: depTaskIds[3].TaskId, Status: evergreen.TaskUndispatched}, 75 {Id: depTaskIds[4].TaskId, Status: evergreen.TaskUndispatched}, 76 } 77 78 So(db.Clear(Collection), ShouldBeNil) 79 for _, depTask := range depTasks { 80 So(depTask.Insert(), ShouldBeNil) 81 } 82 83 Convey("if the task has no dependencies its dependencies should"+ 84 " be met by default", func() { 85 task.DependsOn = []Dependency{} 86 met, err := task.DependenciesMet(map[string]Task{}) 87 So(err, ShouldBeNil) 88 So(met, ShouldBeTrue) 89 }) 90 91 Convey("if only some of the tasks dependencies are finished"+ 92 " successfully, then it should not think its dependencies are met", 93 func() { 94 task.DependsOn = depTaskIds 95 So(UpdateOne( 96 bson.M{"_id": depTaskIds[0].TaskId}, 97 bson.M{ 98 "$set": bson.M{ 99 "status": evergreen.TaskSucceeded, 100 }, 101 }, 102 ), ShouldBeNil) 103 met, err := task.DependenciesMet(map[string]Task{}) 104 So(err, ShouldBeNil) 105 So(met, ShouldBeFalse) 106 }) 107 108 Convey("if all of the tasks dependencies are finished properly, it"+ 109 " should correctly believe its dependencies are met", func() { 110 task.DependsOn = depTaskIds 111 updateTestDepTasks(t) 112 met, err := task.DependenciesMet(map[string]Task{}) 113 So(err, ShouldBeNil) 114 So(met, ShouldBeTrue) 115 }) 116 117 Convey("tasks not in the dependency cache should be pulled into the"+ 118 " cache during dependency checking", func() { 119 dependencyCache := make(map[string]Task) 120 task.DependsOn = depTaskIds 121 updateTestDepTasks(t) 122 met, err := task.DependenciesMet(dependencyCache) 123 So(err, ShouldBeNil) 124 So(met, ShouldBeTrue) 125 for _, depTaskId := range depTaskIds[:4] { 126 So(dependencyCache[depTaskId.TaskId].Id, ShouldEqual, depTaskId.TaskId) 127 } 128 So(dependencyCache["td5"].Id, ShouldEqual, "td5") 129 }) 130 131 Convey("cached dependencies should be used rather than fetching them"+ 132 " from the database", func() { 133 updateTestDepTasks(t) 134 dependencyCache := make(map[string]Task) 135 task.DependsOn = depTaskIds 136 met, err := task.DependenciesMet(dependencyCache) 137 So(err, ShouldBeNil) 138 So(met, ShouldBeTrue) 139 140 // alter the dependency cache so that it should seem as if the 141 // dependencies are not met 142 cachedTask := dependencyCache[depTaskIds[0].TaskId] 143 So(cachedTask.Status, ShouldEqual, evergreen.TaskSucceeded) 144 cachedTask.Status = evergreen.TaskFailed 145 dependencyCache[depTaskIds[0].TaskId] = cachedTask 146 met, err = task.DependenciesMet(dependencyCache) 147 So(err, ShouldBeNil) 148 So(met, ShouldBeFalse) 149 150 }) 151 152 Convey("extraneous tasks in the dependency cache should be ignored", 153 func() { 154 So(UpdateOne( 155 bson.M{"_id": depTaskIds[0].TaskId}, 156 bson.M{ 157 "$set": bson.M{ 158 "status": evergreen.TaskSucceeded, 159 }, 160 }, 161 ), ShouldBeNil) 162 So(UpdateOne( 163 bson.M{"_id": depTaskIds[1].TaskId}, 164 bson.M{ 165 "$set": bson.M{ 166 "status": evergreen.TaskSucceeded, 167 }, 168 }, 169 ), ShouldBeNil) 170 So(UpdateOne( 171 bson.M{"_id": depTaskIds[2].TaskId}, 172 bson.M{ 173 "$set": bson.M{ 174 "status": evergreen.TaskFailed, 175 }, 176 }, 177 ), ShouldBeNil) 178 179 dependencyCache := make(map[string]Task) 180 task.DependsOn = []Dependency{depTaskIds[0], depTaskIds[1], 181 depTaskIds[2]} 182 met, err := task.DependenciesMet(dependencyCache) 183 So(err, ShouldBeNil) 184 So(met, ShouldBeFalse) 185 186 // remove the failed task from the dependencies (but not from 187 // the cache). it should be ignored in the next pass 188 task.DependsOn = []Dependency{depTaskIds[0], depTaskIds[1]} 189 met, err = task.DependenciesMet(dependencyCache) 190 So(err, ShouldBeNil) 191 So(met, ShouldBeTrue) 192 }) 193 }) 194 } 195 196 func TestSetTasksScheduledTime(t *testing.T) { 197 Convey("With some tasks", t, func() { 198 199 So(db.Clear(Collection), ShouldBeNil) 200 201 tasks := []Task{ 202 {Id: "t1", ScheduledTime: util.ZeroTime}, 203 {Id: "t2", ScheduledTime: util.ZeroTime}, 204 {Id: "t3", ScheduledTime: util.ZeroTime}, 205 } 206 for _, task := range tasks { 207 So(task.Insert(), ShouldBeNil) 208 } 209 Convey("when updating ScheduledTime for some of the tasks", func() { 210 testTime := time.Unix(31337, 0) 211 So(SetTasksScheduledTime(tasks[1:], testTime), ShouldBeNil) 212 213 Convey("the tasks should be updated in memory", func() { 214 So(tasks[0].ScheduledTime, ShouldResemble, util.ZeroTime) 215 So(tasks[1].ScheduledTime, ShouldResemble, testTime) 216 So(tasks[2].ScheduledTime, ShouldResemble, testTime) 217 218 Convey("and in the db", func() { 219 // Need to use a margin of error on time tests 220 // because of minor differences between how mongo 221 // and golang store dates. The date from the db 222 // can be interpreted as being a few nanoseconds off 223 t1, err := FindOne(ById("t1")) 224 So(err, ShouldBeNil) 225 So(t1.ScheduledTime.Round(oneMs), ShouldResemble, util.ZeroTime) 226 t2, err := FindOne(ById("t2")) 227 So(err, ShouldBeNil) 228 So(t2.ScheduledTime.Round(oneMs), ShouldResemble, testTime) 229 t3, err := FindOne(ById("t3")) 230 So(err, ShouldBeNil) 231 So(t3.ScheduledTime.Round(oneMs), ShouldResemble, testTime) 232 }) 233 234 Convey("if we update a second time", func() { 235 newTime := time.Unix(99999999, 0) 236 So(newTime, ShouldHappenAfter, testTime) 237 So(SetTasksScheduledTime(tasks, newTime), ShouldBeNil) 238 239 Convey("only unset scheduled times should be updated", func() { 240 t1, err := FindOne(ById("t1")) 241 So(err, ShouldBeNil) 242 So(t1.ScheduledTime.Round(oneMs), ShouldResemble, newTime) 243 t2, err := FindOne(ById("t2")) 244 So(err, ShouldBeNil) 245 So(t2.ScheduledTime.Round(oneMs), ShouldResemble, testTime) 246 t3, err := FindOne(ById("t3")) 247 So(err, ShouldBeNil) 248 So(t3.ScheduledTime.Round(oneMs), ShouldResemble, testTime) 249 }) 250 }) 251 252 }) 253 254 }) 255 }) 256 } 257 258 func TestTaskSetPriority(t *testing.T) { 259 260 Convey("With a task", t, func() { 261 262 testutil.HandleTestingErr(db.Clear(Collection), t, "Error clearing"+ 263 " '%v' collection", Collection) 264 265 tasks := []Task{ 266 { 267 Id: "one", 268 DependsOn: []Dependency{{"two", ""}, {"three", ""}, {"four", ""}}, 269 Activated: true, 270 }, 271 { 272 Id: "two", 273 Priority: 5, 274 Activated: true, 275 }, 276 { 277 Id: "three", 278 DependsOn: []Dependency{{"five", ""}}, 279 Activated: true, 280 }, 281 { 282 Id: "four", 283 DependsOn: []Dependency{{"five", ""}}, 284 Activated: true, 285 }, 286 { 287 Id: "five", 288 Activated: true, 289 }, 290 { 291 Id: "six", 292 Activated: true, 293 }, 294 } 295 296 for _, task := range tasks { 297 So(task.Insert(), ShouldBeNil) 298 } 299 300 Convey("setting its priority should update it in-memory"+ 301 " and update it and all dependencies in the database", func() { 302 303 So(tasks[0].SetPriority(1), ShouldBeNil) 304 So(tasks[0].Priority, ShouldEqual, 1) 305 306 task, err := FindOne(ById("one")) 307 So(err, ShouldBeNil) 308 So(task, ShouldNotBeNil) 309 So(task.Priority, ShouldEqual, 1) 310 311 task, err = FindOne(ById("two")) 312 So(err, ShouldBeNil) 313 So(task, ShouldNotBeNil) 314 So(task.Priority, ShouldEqual, 5) 315 316 task, err = FindOne(ById("three")) 317 So(err, ShouldBeNil) 318 So(task, ShouldNotBeNil) 319 So(task.Priority, ShouldEqual, 1) 320 321 task, err = FindOne(ById("four")) 322 So(err, ShouldBeNil) 323 So(task, ShouldNotBeNil) 324 So(task.Id, ShouldEqual, "four") 325 So(task.Priority, ShouldEqual, 1) 326 327 task, err = FindOne(ById("five")) 328 So(err, ShouldBeNil) 329 So(task, ShouldNotBeNil) 330 So(task.Id, ShouldEqual, "five") 331 So(task.Priority, ShouldEqual, 1) 332 333 task, err = FindOne(ById("six")) 334 So(err, ShouldBeNil) 335 So(task, ShouldNotBeNil) 336 So(task.Id, ShouldEqual, "six") 337 So(task.Priority, ShouldEqual, 0) 338 339 }) 340 341 Convey("decreasing priority should update the task but not its dependencies", func() { 342 343 So(tasks[0].SetPriority(1), ShouldBeNil) 344 So(tasks[0].Activated, ShouldEqual, true) 345 So(tasks[0].SetPriority(-1), ShouldBeNil) 346 So(tasks[0].Priority, ShouldEqual, -1) 347 348 task, err := FindOne(ById("one")) 349 So(err, ShouldBeNil) 350 So(task, ShouldNotBeNil) 351 So(task.Priority, ShouldEqual, -1) 352 So(task.Activated, ShouldEqual, false) 353 354 task, err = FindOne(ById("two")) 355 So(err, ShouldBeNil) 356 So(task, ShouldNotBeNil) 357 So(task.Priority, ShouldEqual, 5) 358 So(task.Activated, ShouldEqual, true) 359 360 task, err = FindOne(ById("three")) 361 So(err, ShouldBeNil) 362 So(task, ShouldNotBeNil) 363 So(task.Priority, ShouldEqual, 1) 364 So(task.Activated, ShouldEqual, true) 365 366 task, err = FindOne(ById("four")) 367 So(err, ShouldBeNil) 368 So(task, ShouldNotBeNil) 369 So(task.Id, ShouldEqual, "four") 370 So(task.Priority, ShouldEqual, 1) 371 So(task.Activated, ShouldEqual, true) 372 373 task, err = FindOne(ById("five")) 374 So(err, ShouldBeNil) 375 So(task, ShouldNotBeNil) 376 So(task.Id, ShouldEqual, "five") 377 So(task.Priority, ShouldEqual, 1) 378 So(task.Activated, ShouldEqual, true) 379 380 task, err = FindOne(ById("six")) 381 So(err, ShouldBeNil) 382 So(task, ShouldNotBeNil) 383 So(task.Id, ShouldEqual, "six") 384 So(task.Priority, ShouldEqual, 0) 385 So(task.Activated, ShouldEqual, true) 386 }) 387 }) 388 389 } 390 391 func TestFindTasksByIds(t *testing.T) { 392 Convey("When calling FindTasksByIds...", t, func() { 393 So(db.Clear(Collection), ShouldBeNil) 394 Convey("only tasks with the specified ids should be returned", func() { 395 396 tasks := []Task{ 397 { 398 Id: "one", 399 }, 400 { 401 Id: "two", 402 }, 403 { 404 Id: "three", 405 }, 406 } 407 408 for _, task := range tasks { 409 So(task.Insert(), ShouldBeNil) 410 } 411 412 dbTasks, err := Find(ByIds([]string{"one", "two"})) 413 So(err, ShouldBeNil) 414 So(len(dbTasks), ShouldEqual, 2) 415 So(dbTasks[0].Id, ShouldNotEqual, "three") 416 So(dbTasks[1].Id, ShouldNotEqual, "three") 417 }) 418 }) 419 } 420 421 func TestCountSimilarFailingTasks(t *testing.T) { 422 Convey("When calling CountSimilarFailingTasks...", t, func() { 423 So(db.Clear(Collection), ShouldBeNil) 424 Convey("only failed tasks with the same project, requester, display "+ 425 "name and revision but different buildvariants should be returned", 426 func() { 427 project := "project" 428 requester := "testing" 429 displayName := "compile" 430 buildVariant := "testVariant" 431 revision := "asdf ;lkj asdf ;lkj " 432 433 tasks := []Task{ 434 { 435 Id: "one", 436 Project: project, 437 DisplayName: displayName, 438 BuildVariant: buildVariant + "1", 439 Revision: revision, 440 Requester: requester, 441 }, 442 { 443 Id: "two", 444 Project: project, 445 DisplayName: displayName, 446 BuildVariant: buildVariant + "2", 447 Revision: revision, 448 Requester: requester, 449 Status: evergreen.TaskFailed, 450 }, 451 // task succeeded so should not be returned 452 { 453 Id: "three", 454 Project: project, 455 DisplayName: displayName, 456 BuildVariant: buildVariant + "2", 457 Revision: revision, 458 Requester: requester, 459 Status: evergreen.TaskSucceeded, 460 }, 461 // same buildvariant so should not be returned 462 { 463 Id: "four", 464 Project: project, 465 DisplayName: displayName, 466 BuildVariant: buildVariant + "1", 467 Revision: revision, 468 Requester: requester, 469 Status: evergreen.TaskFailed, 470 }, 471 // different project so should not be returned 472 { 473 Id: "five", 474 Project: project + "1", 475 DisplayName: displayName, 476 BuildVariant: buildVariant + "2", 477 Revision: revision, 478 Requester: requester, 479 Status: evergreen.TaskFailed, 480 }, 481 // different requester so should not be returned 482 { 483 Id: "six", 484 Project: project, 485 DisplayName: displayName, 486 BuildVariant: buildVariant + "2", 487 Revision: revision, 488 Requester: requester + "1", 489 Status: evergreen.TaskFailed, 490 }, 491 // different revision so should not be returned 492 { 493 Id: "seven", 494 Project: project, 495 DisplayName: displayName, 496 BuildVariant: buildVariant + "1", 497 Revision: revision + "1", 498 Requester: requester, 499 Status: evergreen.TaskFailed, 500 }, 501 // different display name so should not be returned 502 { 503 Id: "eight", 504 Project: project, 505 DisplayName: displayName + "1", 506 BuildVariant: buildVariant, 507 Revision: revision, 508 Requester: requester, 509 Status: evergreen.TaskFailed, 510 }, 511 } 512 513 for _, task := range tasks { 514 So(task.Insert(), ShouldBeNil) 515 } 516 517 dbTasks, err := tasks[0].CountSimilarFailingTasks() 518 So(err, ShouldBeNil) 519 So(dbTasks, ShouldEqual, 1) 520 }) 521 }) 522 } 523 524 func TestMarkAsDispatched(t *testing.T) { 525 526 var ( 527 taskId string 528 hostId string 529 buildId string 530 distroId string 531 task *Task 532 myHost *host.Host 533 b *build.Build 534 ) 535 536 Convey("With a task", t, func() { 537 538 taskId = "t1" 539 hostId = "h1" 540 buildId = "b1" 541 distroId = "d1" 542 543 task = &Task{ 544 Id: taskId, 545 BuildId: buildId, 546 } 547 548 myHost = &host.Host{ 549 Id: hostId, 550 Distro: distro.Distro{Id: distroId}, 551 } 552 553 b = &build.Build{ 554 Id: buildId, 555 Tasks: []build.TaskCache{ 556 {Id: taskId}, 557 }, 558 } 559 560 testutil.HandleTestingErr( 561 db.ClearCollections(Collection, build.Collection, host.Collection), 562 t, "Error clearing test collections") 563 564 So(task.Insert(), ShouldBeNil) 565 So(myHost.Insert(), ShouldBeNil) 566 So(b.Insert(), ShouldBeNil) 567 568 Convey("when marking the task as dispatched, the fields for"+ 569 " the task, the host it is on, and the build it is a part of"+ 570 " should be set to reflect this", func() { 571 572 // mark the task as dispatched 573 So(task.MarkAsDispatched(myHost.Id, myHost.Distro.Id, time.Now()), ShouldBeNil) 574 575 // make sure the task's fields were updated, both in ©memory and 576 // in the db 577 So(task.DispatchTime, ShouldNotResemble, time.Unix(0, 0)) 578 So(task.Status, ShouldEqual, evergreen.TaskDispatched) 579 So(task.HostId, ShouldEqual, myHost.Id) 580 So(task.LastHeartbeat, ShouldResemble, task.DispatchTime) 581 task, err := FindOne(ById(taskId)) 582 So(err, ShouldBeNil) 583 So(task.DispatchTime, ShouldNotResemble, time.Unix(0, 0)) 584 So(task.Status, ShouldEqual, evergreen.TaskDispatched) 585 So(task.HostId, ShouldEqual, myHost.Id) 586 So(task.LastHeartbeat, ShouldResemble, task.DispatchTime) 587 588 }) 589 590 }) 591 592 } 593 594 func TestTimeAggregations(t *testing.T) { 595 Convey("With multiple tasks with different times", t, func() { 596 So(db.Clear(Collection), ShouldBeNil) 597 task1 := Task{Id: "bogus", 598 ScheduledTime: time.Unix(1000, 0), 599 StartTime: time.Unix(1010, 0), 600 FinishTime: time.Unix(1030, 0), 601 DistroId: "osx"} 602 task2 := Task{Id: "fake", 603 ScheduledTime: time.Unix(1000, 0), 604 StartTime: time.Unix(1020, 0), 605 FinishTime: time.Unix(1050, 0), 606 DistroId: "osx"} 607 task3 := Task{Id: "placeholder", 608 ScheduledTime: time.Unix(1000, 0), 609 StartTime: time.Unix(1060, 0), 610 FinishTime: time.Unix(1180, 0), 611 DistroId: "templOS"} 612 So(task1.Insert(), ShouldBeNil) 613 So(task2.Insert(), ShouldBeNil) 614 So(task3.Insert(), ShouldBeNil) 615 616 Convey("on an aggregation on FinishTime - StartTime", func() { 617 timeMap, err := AverageTaskTimeDifference( 618 StartTimeKey, 619 FinishTimeKey, 620 DistroIdKey, 621 util.ZeroTime) 622 So(err, ShouldBeNil) 623 624 Convey("the proper averages should be computed", func() { 625 // osx = ([1030-1010] + [1050-1020])/2 = (20+30)/2 = 25 626 So(timeMap["osx"].Seconds(), ShouldEqual, 25) 627 // templOS = (1180 - 1060)/1 = 120/1 = 120 628 So(timeMap["templOS"].Seconds(), ShouldEqual, 120) 629 }) 630 }) 631 632 Convey("on an aggregation on StartTime - ScheduledTime", func() { 633 timeMap, err := AverageTaskTimeDifference( 634 ScheduledTimeKey, 635 StartTimeKey, 636 DistroIdKey, 637 util.ZeroTime) 638 So(err, ShouldBeNil) 639 640 Convey("the proper averages should be computed", func() { 641 // osx = ([1010-1000] + [1020-1000])/2 = (10+20)/2 = 15 642 So(timeMap["osx"].Seconds(), ShouldEqual, 15) 643 // templOS = (1060-1000)/1 = 60/1 = 60 644 So(timeMap["templOS"].Seconds(), ShouldEqual, 60) 645 }) 646 }) 647 648 Convey("but when given non-time fields", func() { 649 650 Convey("most cases should return an empty map", func() { 651 timeMap, err := AverageTaskTimeDifference( 652 IdKey, 653 DistroIdKey, 654 DistroIdKey, 655 util.ZeroTime) 656 So(len(timeMap), ShouldEqual, 0) 657 So(err, ShouldBeNil) 658 timeMap, err = AverageTaskTimeDifference( 659 DistroIdKey, 660 SecretKey, 661 DistroIdKey, 662 util.ZeroTime) 663 So(len(timeMap), ShouldEqual, 0) 664 So(err, ShouldBeNil) 665 }) 666 667 Convey("special key cases should cause real agg errors", func() { 668 timeMap, err := AverageTaskTimeDifference( 669 StartTimeKey, 670 "$$$$$$", 671 DistroIdKey, 672 util.ZeroTime) 673 So(len(timeMap), ShouldEqual, 0) 674 So(err, ShouldNotBeNil) 675 }) 676 }) 677 }) 678 } 679 680 func TestEndingTask(t *testing.T) { 681 Convey("With tasks that are attempting to be marked as finished", t, func() { 682 So(db.Clear(Collection), ShouldBeNil) 683 Convey("a task that has a start time set", func() { 684 now := time.Now() 685 t := &Task{ 686 Id: "taskId", 687 Status: evergreen.TaskStarted, 688 StartTime: now.Add(-5 * time.Minute), 689 } 690 So(t.Insert(), ShouldBeNil) 691 details := &apimodels.TaskEndDetail{ 692 Status: evergreen.TaskFailed, 693 } 694 695 So(t.MarkEnd(now, details), ShouldBeNil) 696 t, err := FindOne(ById(t.Id)) 697 So(err, ShouldBeNil) 698 So(t.Status, ShouldEqual, evergreen.TaskFailed) 699 So(t.FinishTime.Unix(), ShouldEqual, now.Unix()) 700 So(t.StartTime.Unix(), ShouldEqual, now.Add(-5*time.Minute).Unix()) 701 }) 702 Convey("a task with no start time set should have one added", func() { 703 now := time.Now() 704 Convey("a task with a create time < 2 hours should have the start time set to the create time", func() { 705 t := &Task{ 706 Id: "tid", 707 Status: evergreen.TaskDispatched, 708 CreateTime: now.Add(-30 * time.Minute), 709 } 710 So(t.Insert(), ShouldBeNil) 711 details := &apimodels.TaskEndDetail{ 712 Status: evergreen.TaskFailed, 713 } 714 So(t.MarkEnd(now, details), ShouldBeNil) 715 t, err := FindOne(ById(t.Id)) 716 So(err, ShouldBeNil) 717 So(t.StartTime.Unix(), ShouldEqual, t.CreateTime.Unix()) 718 So(t.FinishTime.Unix(), ShouldEqual, now.Unix()) 719 }) 720 Convey("a task with a create time > 2 hours should have the start time set to two hours"+ 721 "before the finish time", func() { 722 t := &Task{ 723 Id: "tid", 724 Status: evergreen.TaskDispatched, 725 CreateTime: now.Add(-3 * time.Hour), 726 } 727 So(t.Insert(), ShouldBeNil) 728 details := &apimodels.TaskEndDetail{ 729 Status: evergreen.TaskFailed, 730 } 731 So(t.MarkEnd(now, details), ShouldBeNil) 732 t, err := FindOne(ById(t.Id)) 733 So(err, ShouldBeNil) 734 startTime := now.Add(-2 * time.Hour) 735 So(t.StartTime.Unix(), ShouldEqual, startTime.Unix()) 736 So(t.FinishTime.Unix(), ShouldEqual, now.Unix()) 737 }) 738 739 }) 740 741 }) 742 }