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  }