github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/apiv3/servicecontext/task.go (about) 1 package servicecontext 2 3 import ( 4 "fmt" 5 "net/http" 6 7 "github.com/evergreen-ci/evergreen" 8 "github.com/evergreen-ci/evergreen/apiv3" 9 serviceModel "github.com/evergreen-ci/evergreen/model" 10 "github.com/evergreen-ci/evergreen/model/task" 11 "github.com/evergreen-ci/evergreen/util" 12 "github.com/pkg/errors" 13 ) 14 15 // DBTaskConnector is a struct that implements the Task related methods 16 // from the ServiceContext through interactions with he backing database. 17 type DBTaskConnector struct{} 18 19 // FindTaskById uses the service layer's task type to query the backing database for 20 // the task with the given taskId. 21 func (tc *DBTaskConnector) FindTaskById(taskId string) (*task.Task, error) { 22 t, err := task.FindOne(task.ById(taskId)) 23 if err != nil { 24 return nil, err 25 } 26 if t == nil { 27 return nil, &apiv3.APIError{ 28 StatusCode: http.StatusNotFound, 29 Message: fmt.Sprintf("task with id %s not found", taskId), 30 } 31 } 32 return t, nil 33 } 34 35 // FindTasksByBuildId uses the service layer's task type to query the backing database for a 36 // list of task that matches buildId. It accepts the startTaskId and a limit 37 // to allow for pagination of the queries. It returns results sorted by taskId. 38 func (tc *DBTaskConnector) FindTasksByBuildId(buildId, taskId, status string, limit int, sortDir int) ([]task.Task, error) { 39 pipeline := task.TasksByBuildIdPipeline(buildId, taskId, status, limit, sortDir) 40 res := []task.Task{} 41 42 err := task.Aggregate(pipeline, &res) 43 if err != nil { 44 return []task.Task{}, err 45 } 46 if len(res) == 0 { 47 var message string 48 if status != "" { 49 message = fmt.Sprintf("tasks from build '%s' with status '%s' "+ 50 "not found", buildId, status) 51 } else { 52 message = fmt.Sprintf("tasks from build '%s' not found", buildId) 53 } 54 return []task.Task{}, &apiv3.APIError{ 55 StatusCode: http.StatusNotFound, 56 Message: message, 57 } 58 } 59 60 if taskId != "" { 61 found := false 62 for _, t := range res { 63 if t.Id == taskId { 64 found = true 65 break 66 } 67 } 68 if !found { 69 return []task.Task{}, &apiv3.APIError{ 70 StatusCode: http.StatusNotFound, 71 Message: fmt.Sprintf("task with id '%s' not found", taskId), 72 } 73 } 74 } 75 return res, nil 76 } 77 78 func (tc *DBTaskConnector) FindTasksByIds(ids []string) ([]task.Task, error) { 79 ts, err := task.Find(task.ByIds(ids)) 80 if err != nil { 81 return nil, err 82 } 83 if len(ts) == 0 { 84 return []task.Task{}, &apiv3.APIError{ 85 StatusCode: http.StatusNotFound, 86 Message: "no tasks found", 87 } 88 } 89 return ts, nil 90 } 91 92 func (tc *DBTestConnector) FindTasksByProjectAndCommit(projectId, commitHash, taskId, 93 status string, limit, sortDir int) ([]task.Task, error) { 94 pipeline := task.TasksByProjectAndCommitPipeline(projectId, commitHash, taskId, 95 status, limit, sortDir) 96 res := []task.Task{} 97 98 err := task.Aggregate(pipeline, &res) 99 if err != nil { 100 return []task.Task{}, err 101 } 102 if len(res) == 0 { 103 var message string 104 if status != "" { 105 message = fmt.Sprintf("task from project '%s' and commit '%s' with status '%s' "+ 106 "not found", projectId, commitHash, status) 107 } else { 108 message = fmt.Sprintf("task from project '%s' and commit '%s' not found", 109 projectId, commitHash) 110 } 111 return []task.Task{}, &apiv3.APIError{ 112 StatusCode: http.StatusNotFound, 113 Message: message, 114 } 115 } 116 117 if taskId != "" { 118 found := false 119 for _, t := range res { 120 if t.Id == taskId { 121 found = true 122 break 123 } 124 } 125 if !found { 126 return []task.Task{}, &apiv3.APIError{ 127 StatusCode: http.StatusNotFound, 128 Message: fmt.Sprintf("task with id '%s' not found", taskId), 129 } 130 } 131 } 132 return res, nil 133 } 134 135 // SetTaskPriority changes the priority value of a task using a call to the 136 // service layer function. 137 func (tc *DBTaskConnector) SetTaskPriority(t *task.Task, priority int64) error { 138 err := t.SetPriority(priority) 139 return err 140 } 141 142 // SetTaskPriority changes the priority value of a task using a call to the 143 // service layer function. 144 func (tc *DBTaskConnector) SetTaskActivated(taskId, user string, activated bool) error { 145 return errors.Wrap(serviceModel.SetActiveState(taskId, user, activated), 146 "Erorr setting task active") 147 } 148 149 // ResetTask sets the task to be in an unexecuted state and prepares it to be 150 // run again. 151 func (tc *DBTaskConnector) ResetTask(taskId, username string, proj *serviceModel.Project) error { 152 return errors.Wrap(serviceModel.TryResetTask(taskId, username, evergreen.RESTV2Package, proj, nil), 153 "Reset task error") 154 } 155 156 // MockTaskConnector stores a cached set of tasks that are queried against by the 157 // implementations of the ServiceContext interface's Task related functions. 158 type MockTaskConnector struct { 159 CachedTasks []task.Task 160 StoredError error 161 } 162 163 // FindTaskById provides a mock implementation of the functions for the 164 // ServiceContext interface without needing to use a database. It returns results 165 // based on the cached tasks in the MockTaskConnector. 166 func (mtc *MockTaskConnector) FindTaskById(taskId string) (*task.Task, error) { 167 for _, t := range mtc.CachedTasks { 168 if t.Id == taskId { 169 return &t, mtc.StoredError 170 } 171 } 172 return nil, mtc.StoredError 173 } 174 175 // FindTestsBytaskId 176 func (mtc *MockTaskConnector) FindTasksByProjectAndCommit(projectId, commitHash, taskId, 177 status string, limit, sortDir int) ([]task.Task, error) { 178 if mtc.StoredError != nil { 179 return []task.Task{}, mtc.StoredError 180 } 181 182 ofProjectAndCommit := []task.Task{} 183 for _, t := range mtc.CachedTasks { 184 if t.Project == projectId && t.Revision == commitHash { 185 ofProjectAndCommit = append(ofProjectAndCommit, t) 186 } 187 } 188 189 // loop until the filename is found 190 for ix, t := range ofProjectAndCommit { 191 if t.Id == taskId { 192 // We've found the test 193 var testsToReturn []task.Task 194 if sortDir < 0 { 195 if ix-limit > 0 { 196 testsToReturn = ofProjectAndCommit[ix-(limit) : ix] 197 } else { 198 testsToReturn = ofProjectAndCommit[:ix] 199 } 200 } else { 201 if ix+limit > len(ofProjectAndCommit) { 202 testsToReturn = ofProjectAndCommit[ix:] 203 } else { 204 testsToReturn = ofProjectAndCommit[ix : ix+limit] 205 } 206 } 207 return testsToReturn, nil 208 } 209 } 210 return nil, nil 211 } 212 func (mdf *MockTaskConnector) FindTasksByIds(taskIds []string) ([]task.Task, error) { 213 return mdf.CachedTasks, mdf.StoredError 214 } 215 216 // FindTaskByBuildId provides a mock implementation of the function for the 217 // ServiceContext interface without needing to use a database. It returns results 218 // based on the cached tasks in the MockTaskConnector. 219 func (mdf *MockTaskConnector) FindTasksByBuildId(buildId, startTaskId, status string, limit, 220 sortDir int) ([]task.Task, error) { 221 if mdf.StoredError != nil { 222 return []task.Task{}, mdf.StoredError 223 } 224 ofBuildIdAndStatus := []task.Task{} 225 for _, t := range mdf.CachedTasks { 226 if t.BuildId == buildId { 227 if status == "" || t.Status == status { 228 ofBuildIdAndStatus = append(ofBuildIdAndStatus, t) 229 } 230 } 231 } 232 233 // loop until the start task is found 234 for ix, t := range ofBuildIdAndStatus { 235 if t.Id == startTaskId { 236 // We've found the task 237 var tasksToReturn []task.Task 238 if sortDir < 0 { 239 if ix-limit > 0 { 240 tasksToReturn = mdf.CachedTasks[ix-(limit) : ix] 241 } else { 242 tasksToReturn = mdf.CachedTasks[:ix] 243 } 244 } else { 245 if ix+limit > len(mdf.CachedTasks) { 246 tasksToReturn = mdf.CachedTasks[ix:] 247 } else { 248 tasksToReturn = mdf.CachedTasks[ix : ix+limit] 249 } 250 } 251 return tasksToReturn, nil 252 } 253 } 254 return nil, nil 255 } 256 257 // SetTaskPriority changes the priority value of a task using a call to the 258 // service layer function. 259 func (mdf *MockTaskConnector) SetTaskPriority(it *task.Task, priority int64) error { 260 for ix, t := range mdf.CachedTasks { 261 if t.Id == it.Id { 262 mdf.CachedTasks[ix].Priority = priority 263 return mdf.StoredError 264 } 265 } 266 return mdf.StoredError 267 } 268 269 // SetTaskActivated changes the activation value of a task using a call to the 270 // service layer function. 271 func (mdf *MockTaskConnector) SetTaskActivated(taskId, user string, activated bool) error { 272 for ix, t := range mdf.CachedTasks { 273 if t.Id == taskId { 274 mdf.CachedTasks[ix].Activated = activated 275 mdf.CachedTasks[ix].ActivatedBy = user 276 return mdf.StoredError 277 } 278 } 279 return mdf.StoredError 280 } 281 282 func (mdf *MockTaskConnector) ResetTask(taskId, username string, proj *serviceModel.Project) error { 283 for ix, t := range mdf.CachedTasks { 284 if t.Id == taskId { 285 t.Activated = true 286 t.Secret = "new secret" 287 t.Status = evergreen.TaskUndispatched 288 t.DispatchTime = util.ZeroTime 289 t.StartTime = util.ZeroTime 290 t.ScheduledTime = util.ZeroTime 291 t.FinishTime = util.ZeroTime 292 t.TestResults = []task.TestResult{} 293 mdf.CachedTasks[ix] = t 294 } 295 } 296 return mdf.StoredError 297 }