// getBuildVariantHistory returns a slice of builds that surround a given build. // As many as 'before' builds (less recent builds) plus as many as 'after' builds // (more recent builds) are returned. func getBuildVariantHistory(buildId string, before int, after int) ([]build.Build, error) { b, err := build.FindOne(build.ById(buildId)) if err != nil { return nil, err } if b == nil { return nil, fmt.Errorf("no build with id %v", buildId) } lessRecentBuilds, err := build.Find( build.ByBeforeRevision(b.Project, b.BuildVariant, b.RevisionOrderNumber). WithFields(build.IdKey, build.TasksKey, build.StatusKey, build.VersionKey, build.ActivatedKey). Limit(before)) if err != nil { return nil, err } moreRecentBuilds, err := build.Find( build.ByAfterRevision(b.Project, b.BuildVariant, b.RevisionOrderNumber). WithFields(build.IdKey, build.TasksKey, build.StatusKey, build.VersionKey, build.ActivatedKey). Limit(after)) if err != nil { return nil, err } builds := make([]build.Build, 0, len(lessRecentBuilds)+len(moreRecentBuilds)) for i := len(moreRecentBuilds); i > 0; i-- { builds = append(builds, moreRecentBuilds[i-1]) } builds = append(builds, lessRecentBuilds...) return builds, nil }
func TestBuildMarkStarted(t *testing.T) { Convey("With a build", t, func() { testutil.HandleTestingErr(db.Clear(build.Collection), t, "Error clearing"+ " '%v' collection", build.Collection) b := &build.Build{ Id: "build", Status: evergreen.BuildCreated, } So(b.Insert(), ShouldBeNil) Convey("marking it as started should update the status and"+ " start time, both in memory and in the database", func() { startTime := time.Now() So(build.TryMarkStarted(b.Id, startTime), ShouldBeNil) // refresh from db and check again b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Status, ShouldEqual, evergreen.BuildStarted) So(b.StartTime.Round(time.Second).Equal( startTime.Round(time.Second)), ShouldBeTrue) }) }) }
func TestBuildMarkFinished(t *testing.T) { Convey("With a build", t, func() { testutil.HandleTestingErr(db.Clear(build.Collection), t, "Error clearing"+ " '%v' collection", build.Collection) startTime := time.Now() b := &build.Build{ Id: "build", StartTime: startTime, } So(b.Insert(), ShouldBeNil) Convey("marking it as finished should update the status,"+ " finish time, and duration, both in memory and in the"+ " database", func() { finishTime := time.Now() So(b.MarkFinished(evergreen.BuildSucceeded, finishTime), ShouldBeNil) So(b.Status, ShouldEqual, evergreen.BuildSucceeded) So(b.FinishTime.Equal(finishTime), ShouldBeTrue) So(b.TimeTaken, ShouldEqual, finishTime.Sub(startTime)) // refresh from db and check again b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Status, ShouldEqual, evergreen.BuildSucceeded) So(b.FinishTime.Round(time.Second).Equal( finishTime.Round(time.Second)), ShouldBeTrue) So(b.TimeTaken, ShouldEqual, finishTime.Sub(startTime)) }) }) }
func TestUpdateBuildStatusForTask(t *testing.T) { Convey("With two tasks and a build", t, func() { testutil.HandleTestingErr(db.ClearCollections(task.Collection, build.Collection, version.Collection), t, "Error clearing task and build collections") displayName := "testName" b := &build.Build{ Id: "buildtest", Status: evergreen.BuildStarted, Version: "abc", } v := &version.Version{ Id: b.Version, Status: evergreen.VersionStarted, } testTask := task.Task{ Id: "testone", DisplayName: displayName, Activated: false, BuildId: b.Id, Project: "sample", Status: evergreen.TaskFailed, } anotherTask := task.Task{ Id: "two", DisplayName: displayName, Activated: true, BuildId: b.Id, Project: "sample", Status: evergreen.TaskFailed, } b.Tasks = []build.TaskCache{ { Id: testTask.Id, Status: evergreen.TaskSucceeded, }, { Id: anotherTask.Id, Status: evergreen.TaskFailed, }, } So(b.Insert(), ShouldBeNil) So(testTask.Insert(), ShouldBeNil) So(anotherTask.Insert(), ShouldBeNil) So(v.Insert(), ShouldBeNil) Convey("updating the build for a task should update the build's status and the version's status", func() { So(UpdateBuildAndVersionStatusForTask(testTask.Id), ShouldBeNil) b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Status, ShouldEqual, evergreen.BuildFailed) v, err := version.FindOne(version.ById(v.Id)) So(v.Status, ShouldEqual, evergreen.VersionFailed) }) }) }
// Given build id, get last successful build before this one func getBuildVariantHistoryLastSuccess(buildId string) (*build.Build, error) { b, err := build.FindOne(build.ById(buildId)) if err != nil { return nil, err } if b.Status == evergreen.BuildSucceeded { return b, nil } return b.PreviousSuccessful() }
func TestDeletingBuild(t *testing.T) { Convey("With a build", t, func() { testutil.HandleTestingErr(db.Clear(build.Collection), t, "Error clearing"+ " '%v' collection", build.Collection) b := &build.Build{ Id: "build", } So(b.Insert(), ShouldBeNil) Convey("deleting it should remove it and all its associated"+ " tasks from the database", func() { testutil.HandleTestingErr(db.ClearCollections(task.Collection), t, "Error"+ " clearing '%v' collection", task.Collection) // insert two tasks that are part of the build, and one that isn't matchingTaskOne := &task.Task{ Id: "matchingOne", BuildId: b.Id, } So(matchingTaskOne.Insert(), ShouldBeNil) matchingTaskTwo := &task.Task{ Id: "matchingTwo", BuildId: b.Id, } So(matchingTaskTwo.Insert(), ShouldBeNil) nonMatchingTask := &task.Task{ Id: "nonMatching", BuildId: "blech", } So(nonMatchingTask.Insert(), ShouldBeNil) // delete the build, make sure only it and its tasks are deleted So(DeleteBuild(b.Id), ShouldBeNil) b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b, ShouldBeNil) matchingTasks, err := task.Find(task.ByBuildId("build")) So(err, ShouldBeNil) So(len(matchingTasks), ShouldEqual, 0) nonMatchingTask, err = task.FindOne(task.ById(nonMatchingTask.Id)) So(err, ShouldBeNil) So(nonMatchingTask, ShouldNotBeNil) }) }) }
func TestMarkStart(t *testing.T) { Convey("With a task, build and version", t, func() { testutil.HandleTestingErr(db.ClearCollections(task.Collection, build.Collection, version.Collection), t, "Error clearing task and build collections") displayName := "testName" b := &build.Build{ Id: "buildtest", Status: evergreen.BuildCreated, Version: "abc", } v := &version.Version{ Id: b.Version, Status: evergreen.VersionCreated, } testTask := task.Task{ Id: "testTask", DisplayName: displayName, Activated: true, BuildId: b.Id, Project: "sample", Status: evergreen.TaskUndispatched, Version: b.Version, } b.Tasks = []build.TaskCache{ { Id: testTask.Id, Status: evergreen.TaskUndispatched, }, } So(b.Insert(), ShouldBeNil) So(testTask.Insert(), ShouldBeNil) So(v.Insert(), ShouldBeNil) Convey("when calling MarkStart, the task, version and build should be updated", func() { So(MarkStart(testTask.Id), ShouldBeNil) testTask, err := task.FindOne(task.ById(testTask.Id)) So(err, ShouldBeNil) So(testTask.Status, ShouldEqual, evergreen.TaskStarted) b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Status, ShouldEqual, evergreen.BuildStarted) So(b.Tasks, ShouldNotBeNil) So(len(b.Tasks), ShouldEqual, 1) So(b.Tasks[0].Status, ShouldEqual, evergreen.TaskStarted) v, err := version.FindOne(version.ById(v.Id)) So(err, ShouldBeNil) So(v.Status, ShouldEqual, evergreen.VersionStarted) }) }) }
// Returns a JSON response with the marshalled output of the build // specified in the request. func (restapi *restAPI) getBuildInfo(w http.ResponseWriter, r *http.Request) { buildId := mux.Vars(r)["build_id"] srcBuild, err := build.FindOne(build.ById(buildId)) if err != nil || srcBuild == nil { msg := fmt.Sprintf("Error finding build '%v'", buildId) statusCode := http.StatusNotFound if err != nil { evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err) statusCode = http.StatusInternalServerError } restapi.WriteJSON(w, statusCode, responseError{Message: msg}) return } destBuild := &restBuild{} // Copy the contents from the database into our local build type err = angier.TransferByFieldNames(srcBuild, destBuild) if err != nil { msg := fmt.Sprintf("Error finding build '%v'", buildId) evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err) restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg}) return } destBuild.Tasks = make(buildStatusByTask, len(srcBuild.Tasks)) for _, task := range srcBuild.Tasks { status := buildStatus{ Id: task.Id, Status: task.Status, TimeTaken: task.TimeTaken, } destBuild.Tasks[task.DisplayName] = status } restapi.WriteJSON(w, http.StatusOK, destBuild) return }
// populateTaskBuildVersion takes a task, build, and version ID and populates a projectContext // with as many of the task, build, and version documents as possible. // If any of the provided IDs is blank, they will be inferred from the more selective ones. // Returns the project ID of the data found, which may be blank if the IDs are empty. func (pc *projectContext) populateTaskBuildVersion(taskId, buildId, versionId string) (string, error) { projectId := "" var err error // Fetch task if there's a task ID present; if we find one, populate build/version IDs from it if len(taskId) > 0 { pc.Task, err = task.FindOne(task.ById(taskId)) if err != nil { return "", err } if pc.Task != nil { // override build and version ID with the ones this task belongs to buildId = pc.Task.BuildId versionId = pc.Task.Version projectId = pc.Task.Project } } // Fetch build if there's a build ID present; if we find one, populate version ID from it if len(buildId) > 0 { pc.Build, err = build.FindOne(build.ById(buildId)) if err != nil { return "", err } if pc.Build != nil { versionId = pc.Build.Version projectId = pc.Build.Project } } if len(versionId) > 0 { pc.Version, err = version.FindOne(version.ById(versionId)) if err != nil { return "", err } if pc.Version != nil { projectId = pc.Version.Identifier } } return projectId, nil }
// Activates any builds if their BatchTimes have elapsed. func (repoTracker *RepoTracker) activateElapsedBuilds(v *version.Version) (err error) { projectId := repoTracker.ProjectRef.Identifier hasActivated := false now := time.Now() for i, status := range v.BuildVariants { // last comparison is to check that ActivateAt is actually set if !status.Activated && now.After(status.ActivateAt) && !status.ActivateAt.IsZero() { evergreen.Logger.Logf(slogger.INFO, "activating variant %v for project %v, revision %v", status.BuildVariant, projectId, v.Revision) // Go copies the slice value, we want to modify the actual value status.Activated = true status.ActivateAt = now v.BuildVariants[i] = status b, err := build.FindOne(build.ById(status.BuildId)) if err != nil { evergreen.Logger.Logf(slogger.ERROR, "error retrieving build for project %v, variant %v, build %v: %v", projectId, status.BuildVariant, status.BuildId, err) continue } evergreen.Logger.Logf(slogger.INFO, "activating build %v for project %v, variant %v", status.BuildId, projectId, status.BuildVariant) // Don't need to set the version in here since we do it ourselves in a single update if err = model.SetBuildActivation(b.Id, true); err != nil { evergreen.Logger.Logf(slogger.ERROR, "error activating build %v for project %v, variant %v: %v", b.Id, projectId, status.BuildVariant, err) continue } hasActivated = true } } // If any variants were activated, update the stored version so that we don't // attempt to activate them again if hasActivated { return v.UpdateBuildVariants() } return nil }
// Returns a JSON response with the status of the specified build. // The keys of the object are the task names. func (restapi restAPI) getBuildStatus(w http.ResponseWriter, r *http.Request) { buildId := mux.Vars(r)["build_id"] b, err := build.FindOne(build.ById(buildId)) if err != nil || b == nil { msg := fmt.Sprintf("Error finding build '%v'", buildId) statusCode := http.StatusNotFound if err != nil { evergreen.Logger.Logf(slogger.ERROR, "%v: %v", msg, err) statusCode = http.StatusInternalServerError } restapi.WriteJSON(w, statusCode, responseError{Message: msg}) return } result := buildStatusContent{ Id: buildId, BuildVariant: b.BuildVariant, Tasks: make(buildStatusByTask, len(b.Tasks)), } for _, task := range b.Tasks { status := buildStatus{ Id: task.Id, Status: task.Status, TimeTaken: task.TimeTaken, } result.Tasks[task.DisplayName] = status } restapi.WriteJSON(w, http.StatusOK, result) return }
func TestMarkAsDispatched(t *testing.T) { var ( taskId string hostId string buildId string task *Task myHost *host.Host b *build.Build ) Convey("With a task", t, func() { taskId = "t1" hostId = "h1" buildId = "b1" task = &Task{ Id: taskId, BuildId: buildId, } myHost = &host.Host{ Id: hostId, } b = &build.Build{ Id: buildId, Tasks: []build.TaskCache{ {Id: taskId}, }, } testutil.HandleTestingErr( db.ClearCollections(TasksCollection, build.Collection, host.Collection), t, "Error clearing test collections") So(task.Insert(), ShouldBeNil) So(myHost.Insert(), ShouldBeNil) So(b.Insert(), ShouldBeNil) Convey("when marking the task as dispatched, the fields for"+ " the task, the host it is on, and the build it is a part of"+ " should be set to reflect this", func() { // mark the task as dispatched So(task.MarkAsDispatched(myHost, time.Now()), ShouldBeNil) // make sure the task's fields were updated, both in memory and // in the db So(task.DispatchTime, ShouldNotResemble, time.Unix(0, 0)) So(task.Status, ShouldEqual, evergreen.TaskDispatched) So(task.HostId, ShouldEqual, myHost.Id) So(task.LastHeartbeat, ShouldResemble, task.DispatchTime) task, err := FindTask(taskId) So(err, ShouldBeNil) So(task.DispatchTime, ShouldNotResemble, time.Unix(0, 0)) So(task.Status, ShouldEqual, evergreen.TaskDispatched) So(task.HostId, ShouldEqual, myHost.Id) So(task.LastHeartbeat, ShouldResemble, task.DispatchTime) // make sure the build's fields were updated in the db b, err = build.FindOne(build.ById(buildId)) So(err, ShouldBeNil) So(b.Tasks[0].Status, ShouldEqual, evergreen.TaskDispatched) }) }) }
func (uis *UIServer) modifyBuild(w http.ResponseWriter, r *http.Request) { projCtx := MustHaveProjectContext(r) user := MustHaveUser(r) if projCtx.Build == nil { http.Error(w, "Not found", http.StatusNotFound) return } reqBody, err := ioutil.ReadAll(r.Body) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer r.Body.Close() putParams := struct { Action string `json:"action"` Active bool `json:"active"` Abort bool `json:"abort"` Priority string `json:"priority"` TaskIds []string `json:"taskIds"` }{} err = json.Unmarshal(reqBody, &putParams) if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // determine what action needs to be taken switch putParams.Action { case "abort": if err := model.AbortBuild(projCtx.Build.Id, user.Id); err != nil { http.Error(w, fmt.Sprintf("Error aborting build %v", projCtx.Build.Id), http.StatusInternalServerError) return } model.RefreshTasksCache(projCtx.Build.Id) case "set_priority": priority, err := strconv.ParseInt(putParams.Priority, 10, 64) if err != nil { http.Error(w, "Bad priority value; must be int", http.StatusBadRequest) return } if priority > evergreen.MaxTaskPriority { if !uis.isSuperUser(user) { http.Error(w, fmt.Sprintf("Insufficient access to set priority %v, can only set prior less than or equal to %v", priority, evergreen.MaxTaskPriority), http.StatusBadRequest) return } } err = model.SetBuildPriority(projCtx.Build.Id, priority) if err != nil { http.Error(w, fmt.Sprintf("Error setting priority on build %v", projCtx.Build.Id), http.StatusInternalServerError) return } case "set_active": err := model.SetBuildActivation(projCtx.Build.Id, putParams.Active, user.Id) if err != nil { http.Error(w, fmt.Sprintf("Error marking build %v as activated=%v", projCtx.Build.Id, putParams.Active), http.StatusInternalServerError) return } case "restart": if err := model.RestartBuild(projCtx.Build.Id, putParams.TaskIds, putParams.Abort, user.Id); err != nil { http.Error(w, fmt.Sprintf("Error restarting build %v", projCtx.Build.Id), http.StatusInternalServerError) return } default: uis.WriteJSON(w, http.StatusBadRequest, "Unrecognized action") return } // After updating the build, fetch updated version to serve back to client projCtx.Build, err = build.FindOne(build.ById(projCtx.Build.Id)) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, err) return } updatedBuild := uiBuild{ Build: *projCtx.Build, CurrentTime: time.Now().UnixNano(), Elapsed: time.Now().Sub(projCtx.Build.StartTime), RepoOwner: projCtx.ProjectRef.Owner, Repo: projCtx.ProjectRef.Repo, Version: *projCtx.Version, } uiTasks, err := getUiTaskCache(projCtx.Build) if err != nil { uis.LoggedError(w, r, http.StatusInternalServerError, err) return } updatedBuild.Tasks = uiTasks uis.WriteJSON(w, http.StatusOK, updatedBuild) }
// loadAlertContext fetches details from the database for all documents that are associated with the // AlertRequest. For example, it populates the task/build/version/project using the // task/build/version/project ids in the alert request document. func (qp *QueueProcessor) loadAlertContext(a *alert.AlertRequest) (*AlertContext, error) { aCtx := &AlertContext{AlertRequest: a} aCtx.Settings = qp.config taskId, projectId, buildId, versionId := a.TaskId, a.ProjectId, a.BuildId, a.VersionId patchId := a.PatchId var err error if len(a.HostId) > 0 { aCtx.Host, err = host.FindOne(host.ById(a.HostId)) if err != nil { return nil, err } } // Fetch task if there's a task ID present; if we find one, populate build/version IDs from it if len(taskId) > 0 { aCtx.Task, err = model.FindTask(taskId) if err != nil { return nil, err } if aCtx.Task != nil && aCtx.Task.Execution != a.Execution { oldTaskId := fmt.Sprintf("%s_%v", taskId, a.Execution) aCtx.Task, err = model.FindOneOldTask(bson.M{"_id": oldTaskId}, db.NoProjection, db.NoSort) if err != nil { return nil, err } } if aCtx.Task != nil { // override build and version ID with the ones this task belongs to buildId = aCtx.Task.BuildId versionId = aCtx.Task.Version projectId = aCtx.Task.Project aCtx.FailedTests = []model.TestResult{} for _, test := range aCtx.Task.TestResults { if test.Status == "fail" { aCtx.FailedTests = append(aCtx.FailedTests, test) } } } } // Fetch build if there's a build ID present; if we find one, populate version ID from it if len(buildId) > 0 { aCtx.Build, err = build.FindOne(build.ById(buildId)) if err != nil { return nil, err } if aCtx.Build != nil { versionId = aCtx.Build.Version projectId = aCtx.Build.Project } } if len(versionId) > 0 { aCtx.Version, err = version.FindOne(version.ById(versionId)) if err != nil { return nil, err } if aCtx.Version != nil { projectId = aCtx.Version.Identifier } } if len(patchId) > 0 { if !patch.IsValidId(patchId) { return nil, fmt.Errorf("patch id '%v' is not an object id", patchId) } aCtx.Patch, err = patch.FindOne(patch.ById(patch.NewId(patchId)).Project(patch.ExcludePatchDiff)) } else if aCtx.Version != nil { // patch isn't in URL but the version in context has one, get it aCtx.Patch, err = patch.FindOne(patch.ByVersion(aCtx.Version.Id).Project(patch.ExcludePatchDiff)) } // If there's a finalized patch loaded into context but not a version, load the version // associated with the patch as the context's version. if aCtx.Version == nil && aCtx.Patch != nil && aCtx.Patch.Version != "" { aCtx.Version, err = version.FindOne(version.ById(aCtx.Patch.Version).WithoutFields(version.ConfigKey)) if err != nil { return nil, err } } if len(projectId) > 0 { aCtx.ProjectRef, err = qp.findProject(projectId) if err != nil { return nil, err } } return aCtx, nil }
// UpdateBuildStatusForTask finds all the builds for a task and updates the // status of the build based on the task's status. func UpdateBuildAndVersionStatusForTask(taskId string) error { // retrieve the task by the task id t, err := task.FindOne(task.ById(taskId)) if err != nil { return err } finishTime := time.Now() // get all of the tasks in the same build b, err := build.FindOne(build.ById(t.BuildId)) if err != nil { return err } buildTasks, err := task.Find(task.ByBuildId(b.Id)) if err != nil { return err } pushTaskExists := false for _, t := range buildTasks { if t.DisplayName == evergreen.PushStage { pushTaskExists = true } } failedTask := false pushSuccess := true pushCompleted := false finishedTasks := 0 // update the build's status based on tasks for this build for _, t := range buildTasks { if task.IsFinished(t) { finishedTasks += 1 // if it was a compile task, mark the build status accordingly if t.DisplayName == evergreen.CompileStage { if t.Status != evergreen.TaskSucceeded { failedTask = true finishedTasks = -1 err = b.MarkFinished(evergreen.BuildFailed, finishTime) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking build as finished: %v", err) return err } break } } else if t.DisplayName == evergreen.PushStage { pushCompleted = true // if it's a finished push, check if it was successful if t.Status != evergreen.TaskSucceeded { err = b.UpdateStatus(evergreen.BuildFailed) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error updating build status: %v", err) return err } pushSuccess = false } } else { // update the build's status when a test task isn't successful if t.Status != evergreen.TaskSucceeded { err = b.UpdateStatus(evergreen.BuildFailed) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error updating build status: %v", err) return err } failedTask = true } } } } // if there are no failed tasks, mark the build as started if !failedTask { err = b.UpdateStatus(evergreen.BuildStarted) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error updating build status: %v", err) return err } } // if a compile task didn't fail, then the // build is only finished when both the compile // and test tasks are completed or when those are // both completed in addition to a push (a push // does not occur if there's a failed task) if finishedTasks >= len(buildTasks)-1 { if !failedTask { if pushTaskExists { // this build has a push task associated with it. if pushCompleted && pushSuccess { // the push succeeded, so mark the build as succeeded. err = b.MarkFinished(evergreen.BuildSucceeded, finishTime) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking build as finished: %v", err) return err } } else if pushCompleted && !pushSuccess { // the push failed, mark build failed. err = b.MarkFinished(evergreen.BuildFailed, finishTime) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking build as finished: %v", err) return err } } else { //This build does have a "push" task, but it hasn't finished yet //So do nothing, since we don't know the status yet. } if err = MarkVersionCompleted(b.Version, finishTime); err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking version as finished: %v", err) return err } } else { // this build has no push task. so go ahead and mark it success/failure. if err = b.MarkFinished(evergreen.BuildSucceeded, finishTime); err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking build as finished: %v", err) return err } if b.Requester == evergreen.PatchVersionRequester { if err = TryMarkPatchBuildFinished(b, finishTime); err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking patch as finished: %v", err) return err } } if err = MarkVersionCompleted(b.Version, finishTime); err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking version as finished: %v", err) return err } } } else { // some task failed if err = b.MarkFinished(evergreen.BuildFailed, finishTime); err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking build as finished: %v", err) return err } if b.Requester == evergreen.PatchVersionRequester { if err = TryMarkPatchBuildFinished(b, finishTime); err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking patch as finished: %v", err) return err } } if err = MarkVersionCompleted(b.Version, finishTime); err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error marking version as finished: %v", err) return err } } // update the build's makespan information if the task has finished err = updateMakespans(b) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error updating makespan information: %v", err) return err } } // this is helpful for when we restart a compile task if finishedTasks == 0 { err = b.UpdateStatus(evergreen.BuildCreated) if err != nil { evergreen.Logger.Errorf(slogger.ERROR, "Error updating build status: %v", err) return err } } return nil }
func TestBuildRestart(t *testing.T) { Convey("Restarting a build", t, func() { testutil.HandleTestingErr(db.ClearCollections(build.Collection, task.Collection), t, "Error clearing test collection") b := &build.Build{ Id: "build", Tasks: []build.TaskCache{ { Id: "task1", Status: evergreen.TaskSucceeded, Activated: true, }, { Id: "task2", Status: evergreen.TaskDispatched, Activated: true, }, { Id: "task3", Status: evergreen.TaskDispatched, Activated: true, }, { Id: "task4", Status: evergreen.TaskDispatched, Activated: true, }, }, } So(b.Insert(), ShouldBeNil) Convey("with task abort should update the status of"+ " non in-progress tasks and abort in-progress ones", func() { taskOne := &task.Task{ Id: "task1", DisplayName: "task1", BuildId: b.Id, Status: evergreen.TaskSucceeded, } So(taskOne.Insert(), ShouldBeNil) taskTwo := &task.Task{ Id: "task2", DisplayName: "task2", BuildId: b.Id, Status: evergreen.TaskDispatched, } So(taskTwo.Insert(), ShouldBeNil) So(RestartBuild(b.Id, []string{"task1", "task2"}, true, evergreen.DefaultTaskActivator), ShouldBeNil) b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Status, ShouldEqual, evergreen.BuildCreated) So(b.Activated, ShouldEqual, true) So(b.Tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) So(b.Tasks[1].Status, ShouldEqual, evergreen.TaskDispatched) So(b.Tasks[0].Activated, ShouldEqual, true) So(b.Tasks[1].Activated, ShouldEqual, true) taskOne, err = task.FindOne(task.ById("task1")) So(err, ShouldBeNil) So(taskOne.Status, ShouldEqual, evergreen.TaskUndispatched) taskTwo, err = task.FindOne(task.ById("task2")) So(err, ShouldBeNil) So(taskTwo.Aborted, ShouldEqual, true) }) Convey("without task abort should update the status"+ " of only those build tasks not in-progress", func() { taskThree := &task.Task{ Id: "task3", DisplayName: "task3", BuildId: b.Id, Status: evergreen.TaskSucceeded, } So(taskThree.Insert(), ShouldBeNil) taskFour := &task.Task{ Id: "task4", DisplayName: "task4", BuildId: b.Id, Status: evergreen.TaskDispatched, } So(taskFour.Insert(), ShouldBeNil) So(RestartBuild(b.Id, []string{"task3", "task4"}, false, evergreen.DefaultTaskActivator), ShouldBeNil) b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(err, ShouldBeNil) So(b.Status, ShouldEqual, evergreen.BuildCreated) So(b.Activated, ShouldEqual, true) So(b.Tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) So(b.Tasks[3].Status, ShouldEqual, evergreen.TaskDispatched) So(b.Tasks[2].Activated, ShouldEqual, true) So(b.Tasks[3].Activated, ShouldEqual, true) taskThree, err = task.FindOne(task.ById("task3")) So(err, ShouldBeNil) So(taskThree.Status, ShouldEqual, evergreen.TaskUndispatched) taskFour, err = task.FindOne(task.ById("task4")) So(err, ShouldBeNil) So(taskFour.Aborted, ShouldEqual, false) So(taskFour.Status, ShouldEqual, evergreen.TaskDispatched) }) }) }
func TestBuildSetActivated(t *testing.T) { Convey("With a build", t, func() { testutil.HandleTestingErr(db.ClearCollections(build.Collection, TasksCollection), t, "Error clearing test collection") Convey("when changing the activated status of the build", func() { Convey("the activated status of the build and all undispatched"+ " tasks that are part of it should be set", func() { b := &build.Build{ Id: "build", Activated: true, BuildVariant: "bv", } So(b.Insert(), ShouldBeNil) // insert three tasks, with only one of them undispatched and // belonging to the correct build wrongBuildId := &Task{ Id: "wrongBuildId", BuildId: "blech", Status: evergreen.TaskUndispatched, Activated: true, } So(wrongBuildId.Insert(), ShouldBeNil) wrongStatus := &Task{ Id: "wrongStatus", BuildId: b.Id, Status: evergreen.TaskDispatched, Activated: true, } So(wrongStatus.Insert(), ShouldBeNil) matching := &Task{ Id: "matching", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true, } So(matching.Insert(), ShouldBeNil) So(SetBuildActivation(b.Id, false), ShouldBeNil) // the build should have been updated in the db b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Activated, ShouldBeFalse) // only the matching task should have been updated deactivatedTasks, err := FindAllTasks( bson.M{TaskActivatedKey: false}, db.NoProjection, db.NoSort, db.NoSkip, db.NoLimit, ) So(err, ShouldBeNil) So(len(deactivatedTasks), ShouldEqual, 1) So(deactivatedTasks[0].Id, ShouldEqual, matching.Id) }) Convey("all of the undispatched task caches within the build"+ " should be updated, both in memory and in the"+ " database", func() { b := &build.Build{ Id: "build", Activated: true, BuildVariant: "foo", Tasks: []build.TaskCache{ { Id: "tc1", Status: evergreen.TaskUndispatched, Activated: true, }, { Id: "tc2", Status: evergreen.TaskDispatched, Activated: true, }, { Id: "tc3", Status: evergreen.TaskUndispatched, Activated: true, }, }, } So(b.Insert(), ShouldBeNil) t1 := &Task{Id: "tc1", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true} t2 := &Task{Id: "tc2", BuildId: b.Id, Status: evergreen.TaskDispatched, Activated: true} t3 := &Task{Id: "tc3", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true} So(t1.Insert(), ShouldBeNil) So(t2.Insert(), ShouldBeNil) So(t3.Insert(), ShouldBeNil) So(SetBuildActivation(b.Id, false), ShouldBeNil) // refresh from the database and check again b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Activated, ShouldBeFalse) So(b.Tasks[0].Activated, ShouldBeFalse) So(b.Tasks[1].Activated, ShouldBeTrue) So(b.Tasks[2].Activated, ShouldBeFalse) }) }) }) }
func TestBuildSetActivated(t *testing.T) { Convey("With a build", t, func() { testutil.HandleTestingErr(db.ClearCollections(build.Collection, task.Collection), t, "Error clearing test collection") Convey("when changing the activated status of the build to true", func() { Convey("the activated status of the build and all undispatched"+ " tasks that are part of it should be set", func() { user := "******" b := &build.Build{ Id: "build", Activated: true, BuildVariant: "bv", } So(b.Insert(), ShouldBeNil) // insert three tasks, with only one of them undispatched and // belonging to the correct build wrongBuildId := &task.Task{ Id: "wrongBuildId", BuildId: "blech", Status: evergreen.TaskUndispatched, Activated: true, } So(wrongBuildId.Insert(), ShouldBeNil) wrongStatus := &task.Task{ Id: "wrongStatus", BuildId: b.Id, Status: evergreen.TaskDispatched, Activated: true, } So(wrongStatus.Insert(), ShouldBeNil) matching := &task.Task{ Id: "matching", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true, } So(matching.Insert(), ShouldBeNil) differentUser := &task.Task{ Id: "differentUser", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true, ActivatedBy: user, } So(differentUser.Insert(), ShouldBeNil) So(SetBuildActivation(b.Id, false, evergreen.DefaultTaskActivator), ShouldBeNil) // the build should have been updated in the db b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Activated, ShouldBeFalse) So(b.ActivatedBy, ShouldEqual, evergreen.DefaultTaskActivator) // only the matching task should have been updated that has not been set by a user deactivatedTasks, err := task.Find(task.ByActivation(false)) So(err, ShouldBeNil) So(len(deactivatedTasks), ShouldEqual, 1) So(deactivatedTasks[0].Id, ShouldEqual, matching.Id) // task with the different user activating should be activated with that user differentUserTask, err := task.FindOne(task.ById(differentUser.Id)) So(err, ShouldBeNil) So(differentUserTask.Activated, ShouldBeTrue) So(differentUserTask.ActivatedBy, ShouldEqual, user) }) Convey("all of the undispatched task caches within the build"+ " should be updated, both in memory and in the"+ " database", func() { b := &build.Build{ Id: "build", Activated: true, BuildVariant: "foo", Tasks: []build.TaskCache{ { Id: "tc1", Status: evergreen.TaskUndispatched, Activated: true, }, { Id: "tc2", Status: evergreen.TaskDispatched, Activated: true, }, { Id: "tc3", Status: evergreen.TaskUndispatched, Activated: true, }, { Id: "tc4", Status: evergreen.TaskUndispatched, Activated: true, }, }, } So(b.Insert(), ShouldBeNil) t1 := &task.Task{Id: "tc1", DisplayName: "tc1", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true} t2 := &task.Task{Id: "tc2", DisplayName: "tc2", BuildId: b.Id, Status: evergreen.TaskDispatched, Activated: true} t3 := &task.Task{Id: "tc3", DisplayName: "tc3", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true} t4 := &task.Task{Id: "tc4", DisplayName: "tc4", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: true, ActivatedBy: "anotherUser"} So(t1.Insert(), ShouldBeNil) So(t2.Insert(), ShouldBeNil) So(t3.Insert(), ShouldBeNil) So(t4.Insert(), ShouldBeNil) So(SetBuildActivation(b.Id, false, evergreen.DefaultTaskActivator), ShouldBeNil) // refresh from the database and check again b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Activated, ShouldBeFalse) So(b.Tasks[0].Activated, ShouldBeFalse) So(b.Tasks[1].Activated, ShouldBeTrue) So(b.Tasks[2].Activated, ShouldBeFalse) So(b.Tasks[3].Activated, ShouldBeTrue) }) Convey("if a build is activated by a user it should not be able to be deactivated by evergreen", func() { user := "******" b := &build.Build{ Id: "anotherBuild", Activated: true, BuildVariant: "bv", } So(b.Insert(), ShouldBeNil) matching := &task.Task{ Id: "matching", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: false, } So(matching.Insert(), ShouldBeNil) matching2 := &task.Task{ Id: "matching2", BuildId: b.Id, Status: evergreen.TaskUndispatched, Activated: false, } So(matching2.Insert(), ShouldBeNil) // have a user set the build activation to true So(SetBuildActivation(b.Id, true, user), ShouldBeNil) // task with the different user activating should be activated with that user task1, err := task.FindOne(task.ById(matching.Id)) So(err, ShouldBeNil) So(task1.Activated, ShouldBeTrue) So(task1.ActivatedBy, ShouldEqual, user) // task with the different user activating should be activated with that user task2, err := task.FindOne(task.ById(matching2.Id)) So(err, ShouldBeNil) So(task2.Activated, ShouldBeTrue) So(task2.ActivatedBy, ShouldEqual, user) // refresh from the database and check again b, err = build.FindOne(build.ById(b.Id)) So(b.Activated, ShouldBeTrue) So(b.ActivatedBy, ShouldEqual, user) // deactivate the task from evergreen and nothing should be deactivated. So(SetBuildActivation(b.Id, false, evergreen.DefaultTaskActivator), ShouldBeNil) // refresh from the database and check again b, err = build.FindOne(build.ById(b.Id)) So(b.Activated, ShouldBeTrue) So(b.ActivatedBy, ShouldEqual, user) // task with the different user activating should be activated with that user task1, err = task.FindOne(task.ById(matching.Id)) So(err, ShouldBeNil) So(task1.Activated, ShouldBeTrue) So(task1.ActivatedBy, ShouldEqual, user) // task with the different user activating should be activated with that user task2, err = task.FindOne(task.ById(matching2.Id)) So(err, ShouldBeNil) So(task2.Activated, ShouldBeTrue) So(task2.ActivatedBy, ShouldEqual, user) }) }) }) }
func TestBuildMarkAborted(t *testing.T) { Convey("With a build", t, func() { testutil.HandleTestingErr(db.ClearCollections(build.Collection, task.Collection, version.Collection), t, "Error clearing test collection") v := &version.Version{ Id: "v", BuildVariants: []version.BuildStatus{ { BuildVariant: "bv", Activated: true, }, }, } So(v.Insert(), ShouldBeNil) b := &build.Build{ Id: "build", Activated: true, BuildVariant: "bv", Version: "v", } So(b.Insert(), ShouldBeNil) Convey("when marking it as aborted", func() { Convey("it should be deactivated", func() { So(AbortBuild(b.Id, evergreen.DefaultTaskActivator), ShouldBeNil) b, err := build.FindOne(build.ById(b.Id)) So(err, ShouldBeNil) So(b.Activated, ShouldBeFalse) }) Convey("all abortable tasks for it should be aborted", func() { // insert two abortable tasks and one non-abortable task // for the correct build, and one abortable task for // a different build abortableOne := &task.Task{ Id: "abortableOne", BuildId: b.Id, Status: evergreen.TaskStarted, } So(abortableOne.Insert(), ShouldBeNil) abortableTwo := &task.Task{ Id: "abortableTwo", BuildId: b.Id, Status: evergreen.TaskDispatched, } So(abortableTwo.Insert(), ShouldBeNil) notAbortable := &task.Task{ Id: "notAbortable", BuildId: b.Id, Status: evergreen.TaskSucceeded, } So(notAbortable.Insert(), ShouldBeNil) wrongBuildId := &task.Task{ Id: "wrongBuildId", BuildId: "blech", Status: evergreen.TaskStarted, } So(wrongBuildId.Insert(), ShouldBeNil) // aborting the build should mark only the two abortable tasks // with the correct build id as aborted So(AbortBuild(b.Id, evergreen.DefaultTaskActivator), ShouldBeNil) abortedTasks, err := task.Find(task.ByAborted(true)) So(err, ShouldBeNil) So(len(abortedTasks), ShouldEqual, 2) So(taskIdInSlice(abortedTasks, abortableOne.Id), ShouldBeTrue) So(taskIdInSlice(abortedTasks, abortableTwo.Id), ShouldBeTrue) }) }) }) }
func TestCreateBuildFromVersion(t *testing.T) { Convey("When creating a build from a version", t, func() { testutil.HandleTestingErr(db.ClearCollections(build.Collection, task.Collection), t, "Error clearing test collection") // the mock build variant we'll be using. runs all three tasks buildVar1 := BuildVariant{ Name: "buildVar", DisplayName: "Build Variant", Tasks: []BuildVariantTask{ {Name: "taskA"}, {Name: "taskB"}, {Name: "taskC"}, {Name: "taskD"}, }, } buildVar2 := BuildVariant{ Name: "buildVar2", DisplayName: "Build Variant 2", Tasks: []BuildVariantTask{ {Name: "taskA"}, {Name: "taskB"}, {Name: "taskC"}, {Name: "taskE"}, }, } buildVar3 := BuildVariant{ Name: "buildVar3", DisplayName: "Build Variant 3", Tasks: []BuildVariantTask{ { // wait for the first BV's taskA to complete Name: "taskA", DependsOn: []TaskDependency{{Name: "taskA", Variant: "buildVar"}}, }, }, } project := &Project{ Tasks: []ProjectTask{ { Name: "taskA", Priority: 5, Tags: []string{"tag1", "tag2"}, DependsOn: []TaskDependency{}, }, { Name: "taskB", Tags: []string{"tag1", "tag2"}, DependsOn: []TaskDependency{{Name: "taskA", Variant: "buildVar"}}, }, { Name: "taskC", Tags: []string{"tag1", "tag2"}, DependsOn: []TaskDependency{ {Name: "taskA"}, {Name: "taskB"}, }, }, { Name: "taskD", Tags: []string{"tag1", "tag2"}, DependsOn: []TaskDependency{{Name: AllDependencies}}, }, { Name: "taskE", Tags: []string{"tag1", "tag2"}, DependsOn: []TaskDependency{ { Name: AllDependencies, Variant: AllVariants, }, }, }, }, BuildVariants: []BuildVariant{buildVar1, buildVar2, buildVar3}, } // the mock version we'll be using v := &version.Version{ Id: "versionId", CreateTime: time.Now(), Revision: "foobar", RevisionOrderNumber: 500, Requester: evergreen.RepotrackerVersionRequester, BuildVariants: []version.BuildStatus{ { BuildVariant: buildVar1.Name, Activated: false, }, { BuildVariant: buildVar2.Name, Activated: false, }, { BuildVariant: buildVar3.Name, Activated: false, }, }, } tt := BuildTaskIdTable(project, v) Convey("the task id table should be well-formed", func() { So(tt.GetId("buildVar", "taskA"), ShouldNotEqual, "") So(tt.GetId("buildVar", "taskB"), ShouldNotEqual, "") So(tt.GetId("buildVar", "taskC"), ShouldNotEqual, "") So(tt.GetId("buildVar", "taskD"), ShouldNotEqual, "") So(tt.GetId("buildVar2", "taskA"), ShouldNotEqual, "") So(tt.GetId("buildVar2", "taskB"), ShouldNotEqual, "") So(tt.GetId("buildVar2", "taskC"), ShouldNotEqual, "") So(tt.GetId("buildVar2", "taskE"), ShouldNotEqual, "") So(tt.GetId("buildVar3", "taskA"), ShouldNotEqual, "") Convey(`and incorrect GetId() calls should return ""`, func() { So(tt.GetId("buildVar", "taskF"), ShouldEqual, "") So(tt.GetId("buildVar2", "taskD"), ShouldEqual, "") So(tt.GetId("buildVar7", "taskA"), ShouldEqual, "") }) }) Convey("if a non-existent build variant is passed in, an error should be returned", func() { buildId, err := CreateBuildFromVersion(project, v, tt, "blecch", false, []string{}) So(err, ShouldNotBeNil) So(buildId, ShouldEqual, "") }) Convey("if no task names are passed in to be used, all of the default"+ " tasks for the build variant should be created", func() { buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") buildId2, err := CreateBuildFromVersion(project, v, tt, buildVar2.Name, false, nil) So(err, ShouldBeNil) So(buildId2, ShouldNotEqual, "") // find the tasks, make sure they were all created tasks, err := task.Find(task.All) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 8) So(len(tasks[0].Tags), ShouldEqual, 2) }) Convey("if a non-empty list of task names is passed in, only the"+ " specified tasks should be created", func() { buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, []string{"taskA", "taskB"}) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the tasks, make sure they were all created tasks, err := task.Find(task.All) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 2) }) Convey("the build should contain task caches that correspond exactly"+ " to the tasks created", func() { buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the tasks, make sure they were all created tasks, err := task.Find(task.All) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 4) // find the build from the db b, err := build.FindOne(build.ById(buildId)) So(err, ShouldBeNil) So(len(b.Tasks), ShouldEqual, 4) // make sure the task caches are correct. they should also appear // in the same order that they appear in the project file So(b.Tasks[0].Id, ShouldNotEqual, "") So(b.Tasks[0].DisplayName, ShouldEqual, "taskA") So(b.Tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) So(b.Tasks[1].Id, ShouldNotEqual, "") So(b.Tasks[1].DisplayName, ShouldEqual, "taskB") So(b.Tasks[1].Status, ShouldEqual, evergreen.TaskUndispatched) So(b.Tasks[2].Id, ShouldNotEqual, "") So(b.Tasks[2].DisplayName, ShouldEqual, "taskC") So(b.Tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) So(b.Tasks[3].Id, ShouldNotEqual, "") So(b.Tasks[3].DisplayName, ShouldEqual, "taskD") So(b.Tasks[3].Status, ShouldEqual, evergreen.TaskUndispatched) }) Convey("all of the tasks created should have the dependencies"+ "and priorities specified in the project", func() { buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") buildId2, err := CreateBuildFromVersion(project, v, tt, buildVar2.Name, false, nil) So(err, ShouldBeNil) So(buildId2, ShouldNotEqual, "") buildId3, err := CreateBuildFromVersion(project, v, tt, buildVar3.Name, false, nil) So(err, ShouldBeNil) So(buildId3, ShouldNotEqual, "") // find the tasks, make sure they were all created tasks, err := task.Find(task.All.Sort([]string{task.DisplayNameKey, task.BuildVariantKey})) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 9) // taskA So(len(tasks[0].DependsOn), ShouldEqual, 0) So(len(tasks[1].DependsOn), ShouldEqual, 0) So(len(tasks[2].DependsOn), ShouldEqual, 1) So(tasks[0].Priority, ShouldEqual, 5) So(tasks[1].Priority, ShouldEqual, 5) So(tasks[2].DependsOn, ShouldResemble, []task.Dependency{{tasks[0].Id, evergreen.TaskSucceeded}}) // taskB So(tasks[3].DependsOn, ShouldResemble, []task.Dependency{{tasks[0].Id, evergreen.TaskSucceeded}}) So(tasks[4].DependsOn, ShouldResemble, []task.Dependency{{tasks[0].Id, evergreen.TaskSucceeded}}) //cross-variant So(tasks[3].Priority, ShouldEqual, 0) So(tasks[4].Priority, ShouldEqual, 0) //default priority // taskC So(tasks[5].DependsOn, ShouldResemble, []task.Dependency{ {tasks[0].Id, evergreen.TaskSucceeded}, {tasks[3].Id, evergreen.TaskSucceeded}}) So(tasks[6].DependsOn, ShouldResemble, []task.Dependency{ {tasks[1].Id, evergreen.TaskSucceeded}, {tasks[4].Id, evergreen.TaskSucceeded}}) So(tasks[7].DependsOn, ShouldResemble, []task.Dependency{ {tasks[0].Id, evergreen.TaskSucceeded}, {tasks[3].Id, evergreen.TaskSucceeded}, {tasks[5].Id, evergreen.TaskSucceeded}}) So(tasks[8].DisplayName, ShouldEqual, "taskE") So(len(tasks[8].DependsOn), ShouldEqual, 8) }) Convey("all of the build's essential fields should be set"+ " correctly", func() { buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the build from the db b, err := build.FindOne(build.ById(buildId)) So(err, ShouldBeNil) // verify all the fields are set appropriately So(len(b.Tasks), ShouldEqual, 4) So(b.CreateTime.Truncate(time.Second), ShouldResemble, v.CreateTime.Truncate(time.Second)) So(b.PushTime.Truncate(time.Second), ShouldResemble, v.CreateTime.Truncate(time.Second)) So(b.Activated, ShouldEqual, v.BuildVariants[0].Activated) So(b.Project, ShouldEqual, project.Identifier) So(b.Revision, ShouldEqual, v.Revision) So(b.Status, ShouldEqual, evergreen.BuildCreated) So(b.BuildVariant, ShouldEqual, buildVar1.Name) So(b.Version, ShouldEqual, v.Id) So(b.DisplayName, ShouldEqual, buildVar1.DisplayName) So(b.RevisionOrderNumber, ShouldEqual, v.RevisionOrderNumber) So(b.Requester, ShouldEqual, v.Requester) }) Convey("all of the tasks' essential fields should be set"+ " correctly", func() { buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the build from the db b, err := build.FindOne(build.ById(buildId)) So(err, ShouldBeNil) // find the tasks, make sure they were all created tasks, err := task.Find(task.All.Sort([]string{task.DisplayNameKey})) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 4) So(tasks[0].Id, ShouldNotEqual, "") So(tasks[0].Secret, ShouldNotEqual, "") So(tasks[0].DisplayName, ShouldEqual, "taskA") So(tasks[0].BuildId, ShouldEqual, buildId) So(tasks[0].DistroId, ShouldEqual, "") So(tasks[0].BuildVariant, ShouldEqual, buildVar1.Name) So(tasks[0].CreateTime.Truncate(time.Second), ShouldResemble, b.CreateTime.Truncate(time.Second)) So(tasks[0].PushTime.Truncate(time.Second), ShouldResemble, b.PushTime.Truncate(time.Second)) So(tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[0].Activated, ShouldEqual, b.Activated) So(tasks[0].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) So(tasks[0].Requester, ShouldEqual, b.Requester) So(tasks[0].Version, ShouldEqual, v.Id) So(tasks[0].Revision, ShouldEqual, v.Revision) So(tasks[0].Project, ShouldEqual, project.Identifier) So(tasks[1].Id, ShouldNotEqual, "") So(tasks[1].Secret, ShouldNotEqual, "") So(tasks[1].DisplayName, ShouldEqual, "taskB") So(tasks[1].BuildId, ShouldEqual, buildId) So(tasks[1].DistroId, ShouldEqual, "") So(tasks[1].BuildVariant, ShouldEqual, buildVar1.Name) So(tasks[1].CreateTime.Truncate(time.Second), ShouldResemble, b.CreateTime.Truncate(time.Second)) So(tasks[1].PushTime.Truncate(time.Second), ShouldResemble, b.PushTime.Truncate(time.Second)) So(tasks[1].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[1].Activated, ShouldEqual, b.Activated) So(tasks[1].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) So(tasks[1].Requester, ShouldEqual, b.Requester) So(tasks[1].Version, ShouldEqual, v.Id) So(tasks[1].Revision, ShouldEqual, v.Revision) So(tasks[1].Project, ShouldEqual, project.Identifier) So(tasks[2].Id, ShouldNotEqual, "") So(tasks[2].Secret, ShouldNotEqual, "") So(tasks[2].DisplayName, ShouldEqual, "taskC") So(tasks[2].BuildId, ShouldEqual, buildId) So(tasks[2].DistroId, ShouldEqual, "") So(tasks[2].BuildVariant, ShouldEqual, buildVar1.Name) So(tasks[2].CreateTime.Truncate(time.Second), ShouldResemble, b.CreateTime.Truncate(time.Second)) So(tasks[2].PushTime.Truncate(time.Second), ShouldResemble, b.PushTime.Truncate(time.Second)) So(tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[2].Activated, ShouldEqual, b.Activated) So(tasks[2].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) So(tasks[2].Requester, ShouldEqual, b.Requester) So(tasks[2].Version, ShouldEqual, v.Id) So(tasks[2].Revision, ShouldEqual, v.Revision) So(tasks[2].Project, ShouldEqual, project.Identifier) So(tasks[3].Id, ShouldNotEqual, "") So(tasks[3].Secret, ShouldNotEqual, "") So(tasks[3].DisplayName, ShouldEqual, "taskD") So(tasks[3].BuildId, ShouldEqual, buildId) So(tasks[3].DistroId, ShouldEqual, "") So(tasks[3].BuildVariant, ShouldEqual, buildVar1.Name) So(tasks[3].CreateTime.Truncate(time.Second), ShouldResemble, b.CreateTime.Truncate(time.Second)) So(tasks[3].PushTime.Truncate(time.Second), ShouldResemble, b.PushTime.Truncate(time.Second)) So(tasks[3].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[3].Activated, ShouldEqual, b.Activated) So(tasks[3].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) So(tasks[3].Requester, ShouldEqual, b.Requester) So(tasks[3].Version, ShouldEqual, v.Id) So(tasks[3].Revision, ShouldEqual, v.Revision) So(tasks[3].Project, ShouldEqual, project.Identifier) }) Convey("if the activated flag is set, the build and all its tasks should be activated", func() { buildId, err := CreateBuildFromVersion(project, v, tt, buildVar1.Name, true, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the build from the db build, err := build.FindOne(build.ById(buildId)) So(err, ShouldBeNil) So(build.Activated, ShouldBeTrue) // find the tasks, make sure they were all created tasks, err := task.Find(task.All.Sort([]string{task.DisplayNameKey})) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 4) So(tasks[0].Id, ShouldNotEqual, "") So(tasks[0].Secret, ShouldNotEqual, "") So(tasks[0].DisplayName, ShouldEqual, "taskA") So(tasks[0].BuildId, ShouldEqual, buildId) So(tasks[0].DistroId, ShouldEqual, "") So(tasks[0].BuildVariant, ShouldEqual, buildVar1.Name) So(tasks[0].CreateTime.Truncate(time.Second), ShouldResemble, build.CreateTime.Truncate(time.Second)) So(tasks[0].PushTime.Truncate(time.Second), ShouldResemble, build.PushTime.Truncate(time.Second)) So(tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[0].Activated, ShouldEqual, build.Activated) So(tasks[0].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) So(tasks[0].Requester, ShouldEqual, build.Requester) So(tasks[0].Version, ShouldEqual, v.Id) So(tasks[0].Revision, ShouldEqual, v.Revision) So(tasks[0].Project, ShouldEqual, project.Identifier) So(tasks[1].Id, ShouldNotEqual, "") So(tasks[1].Secret, ShouldNotEqual, "") So(tasks[1].DisplayName, ShouldEqual, "taskB") So(tasks[1].BuildId, ShouldEqual, buildId) So(tasks[1].DistroId, ShouldEqual, "") So(tasks[1].BuildVariant, ShouldEqual, buildVar1.Name) So(tasks[1].CreateTime.Truncate(time.Second), ShouldResemble, build.CreateTime.Truncate(time.Second)) So(tasks[1].PushTime.Truncate(time.Second), ShouldResemble, build.PushTime.Truncate(time.Second)) So(tasks[1].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[1].Activated, ShouldEqual, build.Activated) So(tasks[1].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) So(tasks[1].Requester, ShouldEqual, build.Requester) So(tasks[1].Version, ShouldEqual, v.Id) So(tasks[1].Revision, ShouldEqual, v.Revision) So(tasks[1].Project, ShouldEqual, project.Identifier) So(tasks[2].Id, ShouldNotEqual, "") So(tasks[2].Secret, ShouldNotEqual, "") So(tasks[2].DisplayName, ShouldEqual, "taskC") So(tasks[2].BuildId, ShouldEqual, buildId) So(tasks[2].DistroId, ShouldEqual, "") So(tasks[2].BuildVariant, ShouldEqual, buildVar1.Name) So(tasks[2].CreateTime.Truncate(time.Second), ShouldResemble, build.CreateTime.Truncate(time.Second)) So(tasks[2].PushTime.Truncate(time.Second), ShouldResemble, build.PushTime.Truncate(time.Second)) So(tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[2].Activated, ShouldEqual, build.Activated) So(tasks[2].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) So(tasks[2].Requester, ShouldEqual, build.Requester) So(tasks[2].Version, ShouldEqual, v.Id) So(tasks[2].Revision, ShouldEqual, v.Revision) So(tasks[2].Project, ShouldEqual, project.Identifier) So(tasks[3].Id, ShouldNotEqual, "") So(tasks[3].Secret, ShouldNotEqual, "") So(tasks[3].DisplayName, ShouldEqual, "taskD") So(tasks[3].BuildId, ShouldEqual, buildId) So(tasks[3].DistroId, ShouldEqual, "") So(tasks[3].BuildVariant, ShouldEqual, buildVar1.Name) So(tasks[3].CreateTime.Truncate(time.Second), ShouldResemble, build.CreateTime.Truncate(time.Second)) So(tasks[3].PushTime.Truncate(time.Second), ShouldResemble, build.PushTime.Truncate(time.Second)) So(tasks[3].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[3].Activated, ShouldEqual, build.Activated) So(tasks[3].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) So(tasks[3].Requester, ShouldEqual, build.Requester) So(tasks[3].Version, ShouldEqual, v.Id) So(tasks[3].Revision, ShouldEqual, v.Revision) So(tasks[3].Project, ShouldEqual, project.Identifier) }) }) }
func TestCreateBuildFromVersion(t *testing.T) { Convey("When creating a build from a version", t, func() { testutil.HandleTestingErr(db.ClearCollections(build.Collection, TasksCollection), t, "Error clearing test collection") // the mock build variant we'll be using. runs all three tasks buildVar := BuildVariant{ Name: "buildVar", DisplayName: "Build Variant", Tasks: []BuildVariantTask{ {Name: "taskA"}, {Name: "taskB"}, {Name: "taskC"}, {Name: "taskD"}, }, } // the mock project we'll be using. the mock tasks are: // taskOne - no dependencies // taskTwo - depends on taskOne // taskThree - depends on taskOne and taskTwo project := &Project{ Tasks: []ProjectTask{ ProjectTask{ Name: "taskA", DependsOn: []TaskDependency{}, }, ProjectTask{ Name: "taskB", DependsOn: []TaskDependency{ TaskDependency{ Name: "taskA", }, }, }, ProjectTask{ Name: "taskC", DependsOn: []TaskDependency{ TaskDependency{ Name: "taskA", }, TaskDependency{ Name: "taskB", }, }, }, ProjectTask{ Name: "taskD", DependsOn: []TaskDependency{ TaskDependency{ Name: AllDependencies, }, }, }, }, BuildVariants: []BuildVariant{buildVar}, } // the mock version we'll be using v := &version.Version{ Id: "versionId", CreateTime: time.Now(), Revision: "foobar", RevisionOrderNumber: 500, Requester: evergreen.RepotrackerVersionRequester, BuildVariants: []version.BuildStatus{ { BuildVariant: buildVar.Name, Activated: false, }, }, } Convey("if a non-existent build variant is passed in, an error should"+ " be returned", func() { buildId, err := CreateBuildFromVersion(project, v, "blecch", false, []string{}) So(err, ShouldNotBeNil) So(buildId, ShouldEqual, "") }) Convey("if no task names are passed in to be used, all of the default"+ " tasks for the build variant should be created", func() { buildId, err := CreateBuildFromVersion(project, v, buildVar.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the tasks, make sure they were all created tasks, err := FindAllTasks( bson.M{}, db.NoProjection, db.NoSort, db.NoSkip, db.NoLimit, ) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 4) }) Convey("if a non-empty list of task names is passed in, only the"+ " specified tasks should be created", func() { buildId, err := CreateBuildFromVersion(project, v, buildVar.Name, false, []string{"taskA", "taskB"}) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the tasks, make sure they were all created tasks, err := FindAllTasks( bson.M{}, db.NoProjection, db.NoSort, db.NoSkip, db.NoLimit, ) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 2) }) Convey("the build should contain task caches that correspond exactly"+ " to the tasks created", func() { buildId, err := CreateBuildFromVersion(project, v, buildVar.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the tasks, make sure they were all created tasks, err := FindAllTasks( bson.M{}, db.NoProjection, db.NoSort, db.NoSkip, db.NoLimit, ) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 4) // find the build from the db b, err := build.FindOne(build.ById(buildId)) So(err, ShouldBeNil) So(len(b.Tasks), ShouldEqual, 4) // make sure the task caches are correct. they should also appear // in the same order that they appear in the project file So(b.Tasks[0].Id, ShouldNotEqual, "") So(b.Tasks[0].DisplayName, ShouldEqual, "taskA") So(b.Tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) So(b.Tasks[1].Id, ShouldNotEqual, "") So(b.Tasks[1].DisplayName, ShouldEqual, "taskB") So(b.Tasks[1].Status, ShouldEqual, evergreen.TaskUndispatched) So(b.Tasks[2].Id, ShouldNotEqual, "") So(b.Tasks[2].DisplayName, ShouldEqual, "taskC") So(b.Tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) So(b.Tasks[3].Id, ShouldNotEqual, "") So(b.Tasks[3].DisplayName, ShouldEqual, "taskD") So(b.Tasks[3].Status, ShouldEqual, evergreen.TaskUndispatched) }) Convey("all of the tasks created should have the dependencies"+ " specified in the project", func() { buildId, err := CreateBuildFromVersion(project, v, buildVar.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the tasks, make sure they were all created tasks, err := FindAllTasks( bson.M{}, db.NoProjection, []string{"display_name"}, db.NoSkip, db.NoLimit, ) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 4) So(len(tasks[0].DependsOn), ShouldEqual, 0) So(tasks[1].DependsOn, ShouldResemble, []string{tasks[0].Id}) So(tasks[2].DependsOn, ShouldResemble, []string{tasks[0].Id, tasks[1].Id}) So(tasks[3].DependsOn, ShouldResemble, []string{tasks[0].Id, tasks[1].Id, tasks[2].Id}) }) Convey("all of the build's essential fields should be set"+ " correctly", func() { buildId, err := CreateBuildFromVersion(project, v, buildVar.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the build from the db b, err := build.FindOne(build.ById(buildId)) So(err, ShouldBeNil) // verify all the fields are set appropriately So(len(b.Tasks), ShouldEqual, 4) So(b.CreateTime.Truncate(time.Second), ShouldResemble, v.CreateTime.Truncate(time.Second)) So(b.PushTime.Truncate(time.Second), ShouldResemble, v.CreateTime.Truncate(time.Second)) So(b.Activated, ShouldEqual, v.BuildVariants[0].Activated) So(b.Project, ShouldEqual, project.Identifier) So(b.Revision, ShouldEqual, v.Revision) So(b.Status, ShouldEqual, evergreen.BuildCreated) So(b.BuildVariant, ShouldEqual, buildVar.Name) So(b.Version, ShouldEqual, v.Id) So(b.DisplayName, ShouldEqual, buildVar.DisplayName) So(b.RevisionOrderNumber, ShouldEqual, v.RevisionOrderNumber) So(b.Requester, ShouldEqual, v.Requester) }) Convey("all of the tasks' essential fields should be set"+ " correctly", func() { buildId, err := CreateBuildFromVersion(project, v, buildVar.Name, false, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the build from the db b, err := build.FindOne(build.ById(buildId)) So(err, ShouldBeNil) // find the tasks, make sure they were all created tasks, err := FindAllTasks( bson.M{}, db.NoProjection, []string{"display_name"}, db.NoSkip, db.NoLimit, ) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 4) So(tasks[0].Id, ShouldNotEqual, "") So(tasks[0].Secret, ShouldNotEqual, "") So(tasks[0].DisplayName, ShouldEqual, "taskA") So(tasks[0].BuildId, ShouldEqual, buildId) So(tasks[0].DistroId, ShouldEqual, "") So(tasks[0].BuildVariant, ShouldEqual, buildVar.Name) So(tasks[0].CreateTime.Truncate(time.Second), ShouldResemble, b.CreateTime.Truncate(time.Second)) So(tasks[0].PushTime.Truncate(time.Second), ShouldResemble, b.PushTime.Truncate(time.Second)) So(tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[0].Activated, ShouldEqual, b.Activated) So(tasks[0].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) So(tasks[0].Requester, ShouldEqual, b.Requester) So(tasks[0].Version, ShouldEqual, v.Id) So(tasks[0].Revision, ShouldEqual, v.Revision) So(tasks[0].Project, ShouldEqual, project.Identifier) So(tasks[1].Id, ShouldNotEqual, "") So(tasks[1].Secret, ShouldNotEqual, "") So(tasks[1].DisplayName, ShouldEqual, "taskB") So(tasks[1].BuildId, ShouldEqual, buildId) So(tasks[1].DistroId, ShouldEqual, "") So(tasks[1].BuildVariant, ShouldEqual, buildVar.Name) So(tasks[1].CreateTime.Truncate(time.Second), ShouldResemble, b.CreateTime.Truncate(time.Second)) So(tasks[1].PushTime.Truncate(time.Second), ShouldResemble, b.PushTime.Truncate(time.Second)) So(tasks[1].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[1].Activated, ShouldEqual, b.Activated) So(tasks[1].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) So(tasks[1].Requester, ShouldEqual, b.Requester) So(tasks[1].Version, ShouldEqual, v.Id) So(tasks[1].Revision, ShouldEqual, v.Revision) So(tasks[1].Project, ShouldEqual, project.Identifier) So(tasks[2].Id, ShouldNotEqual, "") So(tasks[2].Secret, ShouldNotEqual, "") So(tasks[2].DisplayName, ShouldEqual, "taskC") So(tasks[2].BuildId, ShouldEqual, buildId) So(tasks[2].DistroId, ShouldEqual, "") So(tasks[2].BuildVariant, ShouldEqual, buildVar.Name) So(tasks[2].CreateTime.Truncate(time.Second), ShouldResemble, b.CreateTime.Truncate(time.Second)) So(tasks[2].PushTime.Truncate(time.Second), ShouldResemble, b.PushTime.Truncate(time.Second)) So(tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[2].Activated, ShouldEqual, b.Activated) So(tasks[2].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) So(tasks[2].Requester, ShouldEqual, b.Requester) So(tasks[2].Version, ShouldEqual, v.Id) So(tasks[2].Revision, ShouldEqual, v.Revision) So(tasks[2].Project, ShouldEqual, project.Identifier) So(tasks[3].Id, ShouldNotEqual, "") So(tasks[3].Secret, ShouldNotEqual, "") So(tasks[3].DisplayName, ShouldEqual, "taskD") So(tasks[3].BuildId, ShouldEqual, buildId) So(tasks[3].DistroId, ShouldEqual, "") So(tasks[3].BuildVariant, ShouldEqual, buildVar.Name) So(tasks[3].CreateTime.Truncate(time.Second), ShouldResemble, b.CreateTime.Truncate(time.Second)) So(tasks[3].PushTime.Truncate(time.Second), ShouldResemble, b.PushTime.Truncate(time.Second)) So(tasks[3].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[3].Activated, ShouldEqual, b.Activated) So(tasks[3].RevisionOrderNumber, ShouldEqual, b.RevisionOrderNumber) So(tasks[3].Requester, ShouldEqual, b.Requester) So(tasks[3].Version, ShouldEqual, v.Id) So(tasks[3].Revision, ShouldEqual, v.Revision) So(tasks[3].Project, ShouldEqual, project.Identifier) }) Convey("if the activated flag is set, the build and all its tasks should be activated", func() { buildId, err := CreateBuildFromVersion(project, v, buildVar.Name, true, nil) So(err, ShouldBeNil) So(buildId, ShouldNotEqual, "") // find the build from the db build, err := build.FindOne(build.ById(buildId)) So(err, ShouldBeNil) So(build.Activated, ShouldBeTrue) // find the tasks, make sure they were all created tasks, err := FindAllTasks( bson.M{}, db.NoProjection, []string{"display_name"}, db.NoSkip, db.NoLimit, ) So(err, ShouldBeNil) So(len(tasks), ShouldEqual, 4) So(tasks[0].Id, ShouldNotEqual, "") So(tasks[0].Secret, ShouldNotEqual, "") So(tasks[0].DisplayName, ShouldEqual, "taskA") So(tasks[0].BuildId, ShouldEqual, buildId) So(tasks[0].DistroId, ShouldEqual, "") So(tasks[0].BuildVariant, ShouldEqual, buildVar.Name) So(tasks[0].CreateTime.Truncate(time.Second), ShouldResemble, build.CreateTime.Truncate(time.Second)) So(tasks[0].PushTime.Truncate(time.Second), ShouldResemble, build.PushTime.Truncate(time.Second)) So(tasks[0].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[0].Activated, ShouldEqual, build.Activated) So(tasks[0].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) So(tasks[0].Requester, ShouldEqual, build.Requester) So(tasks[0].Version, ShouldEqual, v.Id) So(tasks[0].Revision, ShouldEqual, v.Revision) So(tasks[0].Project, ShouldEqual, project.Identifier) So(tasks[1].Id, ShouldNotEqual, "") So(tasks[1].Secret, ShouldNotEqual, "") So(tasks[1].DisplayName, ShouldEqual, "taskB") So(tasks[1].BuildId, ShouldEqual, buildId) So(tasks[1].DistroId, ShouldEqual, "") So(tasks[1].BuildVariant, ShouldEqual, buildVar.Name) So(tasks[1].CreateTime.Truncate(time.Second), ShouldResemble, build.CreateTime.Truncate(time.Second)) So(tasks[1].PushTime.Truncate(time.Second), ShouldResemble, build.PushTime.Truncate(time.Second)) So(tasks[1].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[1].Activated, ShouldEqual, build.Activated) So(tasks[1].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) So(tasks[1].Requester, ShouldEqual, build.Requester) So(tasks[1].Version, ShouldEqual, v.Id) So(tasks[1].Revision, ShouldEqual, v.Revision) So(tasks[1].Project, ShouldEqual, project.Identifier) So(tasks[2].Id, ShouldNotEqual, "") So(tasks[2].Secret, ShouldNotEqual, "") So(tasks[2].DisplayName, ShouldEqual, "taskC") So(tasks[2].BuildId, ShouldEqual, buildId) So(tasks[2].DistroId, ShouldEqual, "") So(tasks[2].BuildVariant, ShouldEqual, buildVar.Name) So(tasks[2].CreateTime.Truncate(time.Second), ShouldResemble, build.CreateTime.Truncate(time.Second)) So(tasks[2].PushTime.Truncate(time.Second), ShouldResemble, build.PushTime.Truncate(time.Second)) So(tasks[2].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[2].Activated, ShouldEqual, build.Activated) So(tasks[2].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) So(tasks[2].Requester, ShouldEqual, build.Requester) So(tasks[2].Version, ShouldEqual, v.Id) So(tasks[2].Revision, ShouldEqual, v.Revision) So(tasks[2].Project, ShouldEqual, project.Identifier) So(tasks[3].Id, ShouldNotEqual, "") So(tasks[3].Secret, ShouldNotEqual, "") So(tasks[3].DisplayName, ShouldEqual, "taskD") So(tasks[3].BuildId, ShouldEqual, buildId) So(tasks[3].DistroId, ShouldEqual, "") So(tasks[3].BuildVariant, ShouldEqual, buildVar.Name) So(tasks[3].CreateTime.Truncate(time.Second), ShouldResemble, build.CreateTime.Truncate(time.Second)) So(tasks[3].PushTime.Truncate(time.Second), ShouldResemble, build.PushTime.Truncate(time.Second)) So(tasks[3].Status, ShouldEqual, evergreen.TaskUndispatched) So(tasks[3].Activated, ShouldEqual, build.Activated) So(tasks[3].RevisionOrderNumber, ShouldEqual, build.RevisionOrderNumber) So(tasks[3].Requester, ShouldEqual, build.Requester) So(tasks[3].Version, ShouldEqual, v.Id) So(tasks[3].Revision, ShouldEqual, v.Revision) So(tasks[3].Project, ShouldEqual, project.Identifier) }) }) }