github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/service/rest_task_history.go (about) 1 package service 2 3 import ( 4 "fmt" 5 "net/http" 6 "time" 7 8 "github.com/evergreen-ci/evergreen" 9 "github.com/evergreen-ci/evergreen/model" 10 "github.com/evergreen-ci/evergreen/util" 11 "github.com/gorilla/mux" 12 "github.com/mongodb/grip" 13 ) 14 15 const ( 16 // Number of revisions to return in task history 17 MaxRestNumRevisions = 10 18 ) 19 20 type RestTestHistoryResult struct { 21 TestFile string `json:"test_file" csv:"test_file"` 22 TaskName string `json:"task_name" csv:"task_name"` 23 TestStatus string `json:"test_status" csv:"test_status"` 24 TaskStatus string `json:"task_status" csv:"task_status"` 25 Revision string `json:"revision" csv:"revision"` 26 Project string `json:"project" csv:"project"` 27 TaskId string `json:"task_id" csv:"task_id"` 28 BuildVariant string `json:"variant" csv:"variant"` 29 StartTime time.Time `json:"start_time" csv:"start_time"` 30 EndTime time.Time `json:"end_time" csv:"end_time"` 31 DurationMS time.Duration `json:"duration" csv:"duration"` 32 Execution int `json:"execution" csv:"execution"` 33 Url string `json:"url" csv:"url"` 34 UrlRaw string `json:"url_raw" csv:"url_raw"` 35 } 36 37 func (restapi restAPI) getTaskHistory(w http.ResponseWriter, r *http.Request) { 38 taskName := mux.Vars(r)["task_name"] 39 projCtx := MustHaveRESTContext(r) 40 project := projCtx.Project 41 if project == nil { 42 restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: "error loading project"}) 43 return 44 } 45 46 buildVariants := project.GetVariantsWithTask(taskName) 47 iter := model.NewTaskHistoryIterator(taskName, buildVariants, project.Identifier) 48 49 chunk, err := iter.GetChunk(nil, MaxRestNumRevisions, NoRevisions, false) 50 if err != nil { 51 msg := fmt.Sprintf("Error finding history for task '%v'", taskName) 52 grip.Errorf("%v: %+v", msg, err) 53 restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: msg}) 54 return 55 } 56 57 restapi.WriteJSON(w, http.StatusOK, chunk) 58 return 59 60 } 61 62 // logURL returns the full URL for linking to a test's logs. 63 // Returns the empty string if no internal or external log is referenced. 64 func logURL(url, logId, root string) string { 65 if logId != "" { 66 return root + "/test_log/" + logId 67 } 68 return url 69 } 70 71 // getTestHistory retrieves the test history query parameters from the request 72 // and passes them to the function that gets the test results. 73 func (restapi restAPI) GetTestHistory(w http.ResponseWriter, r *http.Request) { 74 projectId := mux.Vars(r)["project_id"] 75 if projectId == "" { 76 restapi.WriteJSON(w, http.StatusInternalServerError, responseError{Message: "invalid project id"}) 77 return 78 } 79 params := model.TestHistoryParameters{} 80 params.Project = projectId 81 params.TaskNames = util.GetStringArrayValue(r, "tasks", []string{}) 82 params.TestNames = util.GetStringArrayValue(r, "tests", []string{}) 83 params.BuildVariants = util.GetStringArrayValue(r, "variants", []string{}) 84 params.TestStatuses = util.GetStringArrayValue(r, "testStatuses", []string{}) 85 params.TaskStatuses = util.GetStringArrayValue(r, "taskStatuses", []string{}) 86 87 var err error 88 params.Limit, err = util.GetIntValue(r, "limit", 0) 89 if err != nil { 90 restapi.WriteJSON(w, http.StatusBadRequest, "invalid value for field 'limit'") 91 return 92 } 93 94 if len(params.TaskStatuses) == 0 { 95 params.TaskStatuses = []string{evergreen.TaskFailed} 96 } 97 if len(params.TestStatuses) == 0 { 98 params.TestStatuses = []string{evergreen.TestFailedStatus} 99 } 100 101 params.BeforeRevision = r.FormValue("beforeRevision") 102 params.AfterRevision = r.FormValue("afterRevision") 103 104 beforeDate := r.FormValue("beforeDate") 105 if beforeDate != "" { 106 params.BeforeDate, err = time.Parse(time.RFC3339, beforeDate) 107 if err != nil { 108 restapi.WriteJSON(w, http.StatusBadRequest, "invalid format for field 'before date'") 109 return 110 } 111 } 112 113 afterDate := r.FormValue("afterDate") 114 if afterDate != "" { 115 params.AfterDate, err = time.Parse(time.RFC3339, afterDate) 116 if err != nil { 117 restapi.WriteJSON(w, http.StatusBadRequest, "invalid format for field 'after date'") 118 return 119 } 120 } 121 122 sort := r.FormValue("sort") 123 switch sort { 124 case "earliest": 125 params.Sort = 1 126 case "", "latest": 127 params.Sort = -1 128 default: 129 restapi.WriteJSON(w, http.StatusBadRequest, "invalid sort, must be earliest or latest") 130 return 131 } 132 133 // export format 134 isCSV, err := util.GetBoolValue(r, "csv", false) 135 if err != nil { 136 restapi.WriteJSON(w, http.StatusBadRequest, err.Error()) 137 return 138 } 139 140 err = params.SetDefaultsAndValidate() 141 if err != nil { 142 restapi.WriteJSON(w, http.StatusBadRequest, err.Error()) 143 return 144 } 145 results, err := model.GetTestHistory(¶ms) 146 if err != nil { 147 restapi.WriteJSON(w, http.StatusBadRequest, err.Error()) 148 return 149 } 150 restHistoryResults := []RestTestHistoryResult{} 151 for _, result := range results { 152 startTime := time.Unix(int64(result.StartTime), 0) 153 endTime := time.Unix(int64(result.EndTime), 0) 154 taskStatus := result.TaskStatus 155 if result.TaskStatus == evergreen.TaskFailed { 156 if result.TaskTimedOut { 157 taskStatus = model.TaskTimeout 158 } 159 if result.TaskDetailsType == "system" { 160 taskStatus = model.TaskSystemFailure 161 } 162 } 163 url := logURL(result.Url, result.LogId, restapi.GetSettings().Ui.Url) 164 restHistoryResults = append(restHistoryResults, RestTestHistoryResult{ 165 TestFile: result.TestFile, 166 TaskName: result.TaskName, 167 TestStatus: result.TestStatus, 168 TaskStatus: taskStatus, 169 Revision: result.Revision, 170 Project: result.Project, 171 TaskId: result.TaskId, 172 BuildVariant: result.BuildVariant, 173 StartTime: startTime, 174 EndTime: endTime, 175 DurationMS: endTime.Sub(startTime), 176 Url: url, 177 UrlRaw: result.UrlRaw, 178 Execution: result.Execution, 179 }) 180 } 181 if isCSV { 182 util.WriteCSVResponse(w, http.StatusOK, restHistoryResults) 183 return 184 } 185 restapi.WriteJSON(w, http.StatusOK, restHistoryResults) 186 187 }