github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/apiv3/route/test_routes.go (about) 1 package route 2 3 import ( 4 "net/http" 5 6 "github.com/evergreen-ci/evergreen" 7 "github.com/evergreen-ci/evergreen/apiv3" 8 "github.com/evergreen-ci/evergreen/apiv3/model" 9 "github.com/evergreen-ci/evergreen/apiv3/servicecontext" 10 "github.com/evergreen-ci/evergreen/model/task" 11 "github.com/mongodb/grip" 12 "github.com/pkg/errors" 13 ) 14 15 // getTestRouteManager gets the route manager for the GET /tasks/{task_id}/tests. 16 func getTestRouteManager(route string, version int) *RouteManager { 17 tgh := &testGetHandler{} 18 testGetMethodHandler := MethodHandler{ 19 PrefetchFunctions: []PrefetchFunc{PrefetchUser, PrefetchProjectContext}, 20 Authenticator: &RequireUserAuthenticator{}, 21 RequestHandler: tgh.Handler(), 22 MethodType: evergreen.MethodGet, 23 } 24 25 taskRoute := RouteManager{ 26 Route: route, 27 Methods: []MethodHandler{testGetMethodHandler}, 28 Version: version, 29 } 30 return &taskRoute 31 } 32 33 // testGetHandlerArgs are the additional arguments that are needed when fetching 34 // paginated results for the tests. 35 type testGetHandlerArgs struct { 36 taskId string 37 testStatus string 38 } 39 40 // testGetHandler is the MethodHandler for the GET /tasks/{task_id}/tests route. 41 type testGetHandler struct { 42 *PaginationExecutor 43 } 44 45 func (hgh *testGetHandler) Handler() RequestHandler { 46 testPaginationExecutor := &PaginationExecutor{ 47 KeyQueryParam: "start_at", 48 LimitQueryParam: "limit", 49 Paginator: testPaginator, 50 51 Args: testGetHandlerArgs{}, 52 } 53 54 return &testGetHandler{testPaginationExecutor} 55 } 56 57 // ParseAndValidate fetches the task Id and 'status' from the url and 58 // sets them as part of the args. 59 func (tgh *testGetHandler) ParseAndValidate(r *http.Request) error { 60 projCtx := MustHaveProjectContext(r) 61 if projCtx.Task == nil { 62 return apiv3.APIError{ 63 Message: "Task not found", 64 StatusCode: http.StatusNotFound, 65 } 66 } 67 tgh.Args = testGetHandlerArgs{ 68 taskId: projCtx.Task.Id, 69 testStatus: r.URL.Query().Get("status"), 70 } 71 return tgh.PaginationExecutor.ParseAndValidate(r) 72 } 73 74 // testPaginator is the PaginatorFunc that implements the functionality of paginating 75 // over the tests results of a task. It executes the database lookup and creates 76 // the pages for pagination. 77 func testPaginator(key string, limit int, args interface{}, sc servicecontext.ServiceContext) ([]model.Model, 78 *PageResult, error) { 79 tghArgs, ok := args.(testGetHandlerArgs) 80 if !ok { 81 grip.EmergencyPanic("Test pagination args had wrong type") 82 } 83 tests, err := sc.FindTestsByTaskId(tghArgs.taskId, key, tghArgs.testStatus, limit*2, 1) 84 if err != nil { 85 if _, ok := err.(*apiv3.APIError); !ok { 86 err = errors.Wrap(err, "Database error") 87 } 88 return []model.Model{}, nil, err 89 } 90 91 // Make the previous page 92 prevTests, err := sc.FindTestsByTaskId(tghArgs.taskId, key, tghArgs.testStatus, limit, -1) 93 if err != nil { 94 if apiErr, ok := err.(*apiv3.APIError); !ok || apiErr.StatusCode != http.StatusNotFound { 95 err = errors.Wrap(err, "Database error") 96 } 97 return []model.Model{}, nil, err 98 } 99 100 nextPage := makeNextTestsPage(tests, limit) 101 prevPage := makePrevTestsPage(prevTests) 102 103 pageResults := &PageResult{ 104 Next: nextPage, 105 Prev: prevPage, 106 } 107 108 lastIndex := len(tests) 109 if nextPage != nil { 110 lastIndex = limit 111 } 112 113 // Truncate the hosts to just those that will be returned. 114 tests = tests[:lastIndex] 115 116 models := make([]model.Model, len(tests)) 117 for ix, testResult := range tests { 118 at := &model.APITest{} 119 err = at.BuildFromService(tghArgs.taskId) 120 if err != nil { 121 return []model.Model{}, nil, errors.Wrap(err, "Model error") 122 } 123 err = at.BuildFromService(&testResult) 124 if err != nil { 125 return []model.Model{}, nil, errors.Wrap(err, "Model error") 126 } 127 models[ix] = at 128 } 129 return models, pageResults, nil 130 } 131 132 func makeNextTestsPage(tests []task.TestResult, limit int) *Page { 133 var nextPage *Page 134 if len(tests) > limit { 135 nextLimit := len(tests) - limit 136 nextPage = &Page{ 137 Relation: "next", 138 Key: tests[limit].TestFile, 139 Limit: nextLimit, 140 } 141 } 142 return nextPage 143 } 144 145 func makePrevTestsPage(tests []task.TestResult) *Page { 146 var prevPage *Page 147 if len(tests) > 1 { 148 prevPage = &Page{ 149 Relation: "prev", 150 Key: tests[0].TestFile, 151 Limit: len(tests), 152 } 153 } 154 return prevPage 155 }