github.com/justinjmoses/evergreen@v0.0.0-20170530173719-1d50e381ff0d/service/rest_task_test.go (about) 1 package service 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "math/rand" 7 "net/http" 8 "net/http/httptest" 9 "path/filepath" 10 "testing" 11 "time" 12 13 "github.com/evergreen-ci/evergreen" 14 "github.com/evergreen-ci/evergreen/apimodels" 15 "github.com/evergreen-ci/evergreen/auth" 16 "github.com/evergreen-ci/evergreen/db" 17 "github.com/evergreen-ci/evergreen/model/artifact" 18 "github.com/evergreen-ci/evergreen/model/task" 19 "github.com/evergreen-ci/evergreen/testutil" 20 "github.com/evergreen-ci/render" 21 . "github.com/smartystreets/goconvey/convey" 22 ) 23 24 var taskTestConfig = testutil.TestConfig() 25 26 func init() { 27 db.SetGlobalSessionProvider(db.SessionFactoryFromConfig(taskTestConfig)) 28 } 29 30 func insertTaskForTesting(taskId, versionId, projectName string, testResult task.TestResult) (*task.Task, error) { 31 task := &task.Task{ 32 Id: taskId, 33 CreateTime: time.Now().Add(-20 * time.Minute), 34 ScheduledTime: time.Now().Add(-15 * time.Minute), 35 DispatchTime: time.Now().Add(-14 * time.Minute), 36 StartTime: time.Now().Add(-10 * time.Minute), 37 FinishTime: time.Now().Add(-5 * time.Second), 38 PushTime: time.Now().Add(-1 * time.Millisecond), 39 Version: versionId, 40 Project: projectName, 41 Revision: fmt.Sprintf("%x", rand.Int()), 42 Priority: 10, 43 LastHeartbeat: time.Now(), 44 Activated: false, 45 BuildId: "some-build-id", 46 DistroId: "some-distro-id", 47 BuildVariant: "some-build-variant", 48 DependsOn: []task.Dependency{{"some-other-task", ""}}, 49 DisplayName: "My task", 50 HostId: "some-host-id", 51 Restarts: 0, 52 Execution: 0, 53 Archived: false, 54 RevisionOrderNumber: 42, 55 Requester: evergreen.RepotrackerVersionRequester, 56 Status: "success", 57 Details: apimodels.TaskEndDetail{ 58 TimedOut: false, 59 Description: "some-stage", 60 }, 61 Aborted: false, 62 TimeTaken: time.Duration(100 * time.Millisecond), 63 ExpectedDuration: time.Duration(99 * time.Millisecond), 64 TestResults: []task.TestResult{testResult}, 65 } 66 67 return task, task.Insert() 68 } 69 70 func TestGetTaskInfo(t *testing.T) { 71 72 userManager, err := auth.LoadUserManager(taskTestConfig.AuthConfig) 73 testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config") 74 75 uis := UIServer{ 76 RootURL: taskTestConfig.Ui.Url, 77 Settings: *taskTestConfig, 78 UserManager: userManager, 79 } 80 81 home := evergreen.FindEvergreenHome() 82 83 uis.Render = render.New(render.Options{ 84 Directory: filepath.Join(home, WebRootPath, Templates), 85 DisableCache: true, 86 }) 87 testutil.HandleTestingErr(uis.InitPlugins(), t, "problem loading plugins") 88 router, err := uis.NewRouter() 89 testutil.HandleTestingErr(err, t, "Failed to create ui server router") 90 91 Convey("When finding info on a particular task", t, func() { 92 testutil.HandleTestingErr(db.Clear(task.Collection), t, 93 "Error clearing '%v' collection", task.Collection) 94 95 taskId := "my-task" 96 versionId := "my-version" 97 projectName := "project_test" 98 99 testResult := task.TestResult{ 100 Status: "success", 101 TestFile: "some-test", 102 URL: "some-url", 103 StartTime: float64(time.Now().Add(-9 * time.Minute).Unix()), 104 EndTime: float64(time.Now().Add(-1 * time.Minute).Unix()), 105 } 106 testTask, err := insertTaskForTesting(taskId, versionId, projectName, testResult) 107 So(err, ShouldBeNil) 108 109 file := artifact.File{ 110 Name: "Some Artifact", 111 Link: "some-url", 112 } 113 artifact := artifact.Entry{ 114 TaskId: taskId, 115 Files: []artifact.File{file}, 116 } 117 So(artifact.Upsert(), ShouldBeNil) 118 119 url, err := router.Get("task_info").URL("task_id", taskId) 120 So(err, ShouldBeNil) 121 122 request, err := http.NewRequest("GET", url.String(), nil) 123 So(err, ShouldBeNil) 124 125 response := httptest.NewRecorder() 126 // Need match variables to be set so can call mux.Vars(request) 127 // in the actual handler function 128 router.ServeHTTP(response, request) 129 130 So(response.Code, ShouldEqual, http.StatusOK) 131 132 Convey("response should match contents of database", func() { 133 var jsonBody map[string]interface{} 134 err = json.Unmarshal(response.Body.Bytes(), &jsonBody) 135 So(err, ShouldBeNil) 136 fmt.Println(string(response.Body.Bytes())) 137 138 rawJSONBody := map[string]*json.RawMessage{} 139 err = json.Unmarshal(response.Body.Bytes(), &rawJSONBody) 140 So(err, ShouldBeNil) 141 142 So(jsonBody["id"], ShouldEqual, testTask.Id) 143 144 var createTime time.Time 145 err = json.Unmarshal(*rawJSONBody["create_time"], &createTime) 146 So(err, ShouldBeNil) 147 So(createTime, ShouldHappenWithin, TimePrecision, testTask.CreateTime) 148 149 var scheduledTime time.Time 150 err = json.Unmarshal(*rawJSONBody["scheduled_time"], &scheduledTime) 151 So(err, ShouldBeNil) 152 So(scheduledTime, ShouldHappenWithin, TimePrecision, testTask.ScheduledTime) 153 154 var dispatchTime time.Time 155 err = json.Unmarshal(*rawJSONBody["dispatch_time"], &dispatchTime) 156 So(err, ShouldBeNil) 157 So(dispatchTime, ShouldHappenWithin, TimePrecision, testTask.DispatchTime) 158 159 var startTime time.Time 160 err = json.Unmarshal(*rawJSONBody["start_time"], &startTime) 161 So(err, ShouldBeNil) 162 So(startTime, ShouldHappenWithin, TimePrecision, testTask.StartTime) 163 164 var finishTime time.Time 165 err = json.Unmarshal(*rawJSONBody["finish_time"], &finishTime) 166 So(err, ShouldBeNil) 167 So(finishTime, ShouldHappenWithin, TimePrecision, testTask.FinishTime) 168 169 var pushTime time.Time 170 err = json.Unmarshal(*rawJSONBody["push_time"], &pushTime) 171 So(err, ShouldBeNil) 172 So(pushTime, ShouldHappenWithin, TimePrecision, testTask.PushTime) 173 174 So(jsonBody["version"], ShouldEqual, testTask.Version) 175 So(jsonBody["project"], ShouldEqual, testTask.Project) 176 So(jsonBody["revision"], ShouldEqual, testTask.Revision) 177 So(jsonBody["priority"], ShouldEqual, testTask.Priority) 178 179 var lastHeartbeat time.Time 180 err = json.Unmarshal(*rawJSONBody["last_heartbeat"], &lastHeartbeat) 181 So(err, ShouldBeNil) 182 So(lastHeartbeat, ShouldHappenWithin, TimePrecision, testTask.LastHeartbeat) 183 184 So(jsonBody["activated"], ShouldEqual, testTask.Activated) 185 So(jsonBody["build_id"], ShouldEqual, testTask.BuildId) 186 So(jsonBody["distro"], ShouldEqual, testTask.DistroId) 187 So(jsonBody["build_variant"], ShouldEqual, testTask.BuildVariant) 188 189 var dependsOn []task.Dependency 190 So(rawJSONBody["depends_on"], ShouldNotBeNil) 191 err = json.Unmarshal(*rawJSONBody["depends_on"], &dependsOn) 192 So(err, ShouldBeNil) 193 So(dependsOn, ShouldResemble, testTask.DependsOn) 194 195 So(jsonBody["display_name"], ShouldEqual, testTask.DisplayName) 196 So(jsonBody["host_id"], ShouldEqual, testTask.HostId) 197 So(jsonBody["restarts"], ShouldEqual, testTask.Restarts) 198 So(jsonBody["execution"], ShouldEqual, testTask.Execution) 199 So(jsonBody["archived"], ShouldEqual, testTask.Archived) 200 So(jsonBody["order"], ShouldEqual, testTask.RevisionOrderNumber) 201 So(jsonBody["requester"], ShouldEqual, testTask.Requester) 202 So(jsonBody["status"], ShouldEqual, testTask.Status) 203 204 _jsonStatusDetails, ok := jsonBody["status_details"] 205 So(ok, ShouldBeTrue) 206 jsonStatusDetails, ok := _jsonStatusDetails.(map[string]interface{}) 207 So(ok, ShouldBeTrue) 208 209 So(jsonStatusDetails["timed_out"], ShouldEqual, testTask.Details.TimedOut) 210 So(jsonStatusDetails["timeout_stage"], ShouldEqual, testTask.Details.Description) 211 212 So(jsonBody["aborted"], ShouldEqual, testTask.Aborted) 213 So(jsonBody["time_taken"], ShouldEqual, testTask.TimeTaken) 214 So(jsonBody["expected_duration"], ShouldEqual, testTask.ExpectedDuration) 215 216 _jsonTestResults, ok := jsonBody["test_results"] 217 So(ok, ShouldBeTrue) 218 jsonTestResults, ok := _jsonTestResults.(map[string]interface{}) 219 So(ok, ShouldBeTrue) 220 So(len(jsonTestResults), ShouldEqual, 1) 221 222 _jsonTestResult, ok := jsonTestResults[testResult.TestFile] 223 So(ok, ShouldBeTrue) 224 jsonTestResult, ok := _jsonTestResult.(map[string]interface{}) 225 So(ok, ShouldBeTrue) 226 227 So(jsonTestResult["status"], ShouldEqual, testResult.Status) 228 So(jsonTestResult["time_taken"], ShouldNotBeNil) // value correctness is unchecked 229 230 _jsonTestResultLogs, ok := jsonTestResult["logs"] 231 So(ok, ShouldBeTrue) 232 jsonTestResultLogs, ok := _jsonTestResultLogs.(map[string]interface{}) 233 So(ok, ShouldBeTrue) 234 235 So(jsonTestResultLogs["url"], ShouldEqual, testResult.URL) 236 237 var jsonFiles []map[string]interface{} 238 err = json.Unmarshal(*rawJSONBody["files"], &jsonFiles) 239 So(err, ShouldBeNil) 240 So(len(jsonFiles), ShouldEqual, 1) 241 242 jsonFile := jsonFiles[0] 243 So(jsonFile["name"], ShouldEqual, file.Name) 244 So(jsonFile["url"], ShouldEqual, file.Link) 245 }) 246 }) 247 248 Convey("When finding info on a nonexistent task", t, func() { 249 taskId := "not-present" 250 251 url, err := router.Get("task_info").URL("task_id", taskId) 252 So(err, ShouldBeNil) 253 254 request, err := http.NewRequest("GET", url.String(), nil) 255 So(err, ShouldBeNil) 256 257 response := httptest.NewRecorder() 258 // Need match variables to be set so can call mux.Vars(request) 259 // in the actual handler function 260 router.ServeHTTP(response, request) 261 262 So(response.Code, ShouldEqual, http.StatusNotFound) 263 264 Convey("response should contain a sensible error message", func() { 265 var jsonBody map[string]interface{} 266 err = json.Unmarshal(response.Body.Bytes(), &jsonBody) 267 So(err, ShouldBeNil) 268 So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0) 269 }) 270 }) 271 } 272 273 func TestGetTaskStatus(t *testing.T) { 274 275 userManager, err := auth.LoadUserManager(taskTestConfig.AuthConfig) 276 testutil.HandleTestingErr(err, t, "Failure in loading UserManager from config") 277 278 uis := UIServer{ 279 RootURL: taskTestConfig.Ui.Url, 280 Settings: *taskTestConfig, 281 UserManager: userManager, 282 } 283 284 home := evergreen.FindEvergreenHome() 285 286 uis.Render = render.New(render.Options{ 287 Directory: filepath.Join(home, WebRootPath, Templates), 288 DisableCache: true, 289 }) 290 testutil.HandleTestingErr(uis.InitPlugins(), t, "problem loading plugins") 291 292 router, err := uis.NewRouter() 293 testutil.HandleTestingErr(err, t, "Failed to create ui server router") 294 295 Convey("When finding the status of a particular task", t, func() { 296 testutil.HandleTestingErr(db.Clear(task.Collection), t, 297 "Error clearing '%v' collection", task.Collection) 298 299 taskId := "my-task" 300 301 testResult := task.TestResult{ 302 Status: "success", 303 TestFile: "some-test", 304 URL: "some-url", 305 StartTime: float64(time.Now().Add(-9 * time.Minute).Unix()), 306 EndTime: float64(time.Now().Add(-1 * time.Minute).Unix()), 307 } 308 testTask := &task.Task{ 309 Id: taskId, 310 DisplayName: "My task", 311 Status: "success", 312 Details: apimodels.TaskEndDetail{ 313 TimedOut: false, 314 Description: "some-stage", 315 }, 316 TestResults: []task.TestResult{testResult}, 317 } 318 So(testTask.Insert(), ShouldBeNil) 319 320 url, err := router.Get("task_status").URL("task_id", taskId) 321 So(err, ShouldBeNil) 322 323 request, err := http.NewRequest("GET", url.String(), nil) 324 So(err, ShouldBeNil) 325 326 response := httptest.NewRecorder() 327 // Need match variables to be set so can call mux.Vars(request) 328 // in the actual handler function 329 router.ServeHTTP(response, request) 330 331 So(response.Code, ShouldEqual, http.StatusOK) 332 333 Convey("response should match contents of database", func() { 334 var jsonBody map[string]interface{} 335 err = json.Unmarshal(response.Body.Bytes(), &jsonBody) 336 So(err, ShouldBeNil) 337 338 rawJSONBody := map[string]*json.RawMessage{} 339 err = json.Unmarshal(response.Body.Bytes(), &rawJSONBody) 340 So(err, ShouldBeNil) 341 342 So(jsonBody["task_id"], ShouldEqual, testTask.Id) 343 So(jsonBody["task_name"], ShouldEqual, testTask.DisplayName) 344 So(jsonBody["status"], ShouldEqual, testTask.Status) 345 346 _jsonStatusDetails, ok := jsonBody["status_details"] 347 So(ok, ShouldBeTrue) 348 jsonStatusDetails, ok := _jsonStatusDetails.(map[string]interface{}) 349 So(ok, ShouldBeTrue) 350 351 So(jsonStatusDetails["timed_out"], ShouldEqual, testTask.Details.TimedOut) 352 So(jsonStatusDetails["timeout_stage"], ShouldEqual, testTask.Details.Description) 353 354 _jsonTestResults, ok := jsonBody["tests"] 355 So(ok, ShouldBeTrue) 356 jsonTestResults, ok := _jsonTestResults.(map[string]interface{}) 357 So(ok, ShouldBeTrue) 358 So(len(jsonTestResults), ShouldEqual, 1) 359 360 _jsonTestResult, ok := jsonTestResults[testResult.TestFile] 361 So(ok, ShouldBeTrue) 362 jsonTestResult, ok := _jsonTestResult.(map[string]interface{}) 363 So(ok, ShouldBeTrue) 364 365 So(jsonTestResult["status"], ShouldEqual, testResult.Status) 366 So(jsonTestResult["time_taken"], ShouldNotBeNil) // value correctness is unchecked 367 368 _jsonTestResultLogs, ok := jsonTestResult["logs"] 369 So(ok, ShouldBeTrue) 370 jsonTestResultLogs, ok := _jsonTestResultLogs.(map[string]interface{}) 371 So(ok, ShouldBeTrue) 372 373 So(jsonTestResultLogs["url"], ShouldEqual, testResult.URL) 374 }) 375 }) 376 377 Convey("When finding the status of a nonexistent task", t, func() { 378 taskId := "not-present" 379 380 url, err := router.Get("task_status").URL("task_id", taskId) 381 So(err, ShouldBeNil) 382 383 request, err := http.NewRequest("GET", url.String(), nil) 384 So(err, ShouldBeNil) 385 386 response := httptest.NewRecorder() 387 // Need match variables to be set so can call mux.Vars(request) 388 // in the actual handler function 389 router.ServeHTTP(response, request) 390 391 So(response.Code, ShouldEqual, http.StatusNotFound) 392 393 Convey("response should contain a sensible error message", func() { 394 var jsonBody map[string]interface{} 395 err = json.Unmarshal(response.Body.Bytes(), &jsonBody) 396 So(err, ShouldBeNil) 397 So(len(jsonBody["message"].(string)), ShouldBeGreaterThan, 0) 398 }) 399 }) 400 }