github.com/billybanfield/evergreen@v0.0.0-20170525200750-eeee692790f7/apiv3/route/handler_test.go (about) 1 package route 2 3 import ( 4 "io/ioutil" 5 "net/http" 6 "net/http/httptest" 7 "net/url" 8 "testing" 9 10 "github.com/evergreen-ci/evergreen" 11 "github.com/evergreen-ci/evergreen/apiv3" 12 "github.com/evergreen-ci/evergreen/apiv3/model" 13 "github.com/evergreen-ci/evergreen/apiv3/servicecontext" 14 "github.com/evergreen-ci/evergreen/util" 15 "github.com/gorilla/mux" 16 "github.com/pkg/errors" 17 . "github.com/smartystreets/goconvey/convey" 18 ) 19 20 func TestMakeHandler(t *testing.T) { 21 22 Convey("When creating an http.HandlerFunc", t, func() { 23 auth := &mockAuthenticator{} 24 requestHandler := &mockRequestHandler{} 25 mockMethod := MethodHandler{ 26 Authenticator: auth, 27 RequestHandler: requestHandler, 28 } 29 30 Convey("And authenticator errors should cause response to "+ 31 "contain error information", func() { 32 auth.err = apiv3.APIError{ 33 StatusCode: http.StatusBadRequest, 34 Message: "Not Authenticated", 35 } 36 checkResultMatchesBasic(mockMethod, auth.err, nil, http.StatusBadRequest, t) 37 }) 38 Convey("And parseValidate errors should cause response to "+ 39 "contain error information", func() { 40 requestHandler.parseValidateErr = apiv3.APIError{ 41 StatusCode: http.StatusRequestEntityTooLarge, 42 Message: "Request too large to parse", 43 } 44 checkResultMatchesBasic(mockMethod, requestHandler.parseValidateErr, 45 nil, http.StatusRequestEntityTooLarge, t) 46 }) 47 Convey("And execute errors should cause response to "+ 48 "contain error information", func() { 49 requestHandler.executeErr = apiv3.APIError{ 50 StatusCode: http.StatusNotFound, 51 Message: "Not found in DB", 52 } 53 checkResultMatchesBasic(mockMethod, requestHandler.executeErr, 54 nil, http.StatusNotFound, t) 55 }) 56 Convey("And parseValidate and execute errors should cause response to "+ 57 "contain parseValidate error information", func() { 58 requestHandler.executeErr = apiv3.APIError{ 59 StatusCode: http.StatusNotFound, 60 Message: "Not found in DB", 61 } 62 requestHandler.parseValidateErr = apiv3.APIError{ 63 StatusCode: http.StatusBadRequest, 64 Message: "Request did not contain all fields", 65 } 66 checkResultMatchesBasic(mockMethod, requestHandler.parseValidateErr, 67 nil, http.StatusBadRequest, t) 68 }) 69 Convey("And authenticate and execute errors should cause response to "+ 70 "contain authenticate error information", func() { 71 auth.err = apiv3.APIError{ 72 StatusCode: http.StatusBadRequest, 73 Message: "Not Authenticated", 74 } 75 requestHandler.executeErr = apiv3.APIError{ 76 StatusCode: http.StatusNotFound, 77 Message: "Not found in DB", 78 } 79 checkResultMatchesBasic(mockMethod, auth.err, 80 nil, http.StatusBadRequest, t) 81 }) 82 Convey("And non-API errors should be surfaced as an internal "+ 83 "server error", func() { 84 requestHandler.executeErr = errors.New("The DB is broken") 85 checkResultMatchesBasic(mockMethod, requestHandler.executeErr, 86 nil, http.StatusInternalServerError, t) 87 }) 88 Convey("And api model should be returned successfully ", func() { 89 requestHandler.storedModels = []model.Model{ 90 &model.MockModel{ 91 FieldId: "model_id", 92 FieldInt1: 1234, 93 FieldInt2: 4567, 94 FieldMap: map[string]string{ 95 "mapkey1": "mapval1", 96 "mapkey2": "mapval2", 97 }, 98 FieldStruct: &model.MockSubStruct{1}, 99 }, 100 } 101 checkResultMatchesBasic(mockMethod, nil, 102 requestHandler.storedModels, http.StatusOK, t) 103 }) 104 }) 105 } 106 107 type headerCheckFunc func(map[string][]string, *testing.T) 108 109 func checkResultMatchesBasic(m MethodHandler, expectedErr error, 110 expectedModels []model.Model, expectedStatusCode int, t *testing.T) { 111 checkResultMatches(m, expectedErr, expectedModels, nil, "", expectedStatusCode, t) 112 } 113 114 func checkResultMatches(m MethodHandler, expectedErr error, 115 expectedModels []model.Model, headerCheck headerCheckFunc, queryParams string, 116 expectedStatusCode int, t *testing.T) { 117 118 testRoute := "/test/route" 119 120 handler := makeHandler(m, &servicecontext.MockServiceContext{}) 121 122 u := &url.URL{ 123 RawQuery: queryParams, 124 Path: testRoute, 125 } 126 127 req, err := http.NewRequest(evergreen.MethodGet, u.String(), nil) 128 So(err, ShouldBeNil) 129 130 resp := httptest.NewRecorder() 131 r := mux.NewRouter() 132 r.HandleFunc(testRoute, handler) 133 134 r.ServeHTTP(resp, req) 135 136 if expectedErr != nil { 137 errResult := apiv3.APIError{} 138 wrappedBody := ioutil.NopCloser(resp.Body) 139 140 err := util.ReadJSONInto(wrappedBody, &errResult) 141 So(err, ShouldBeNil) 142 143 So(errResult.StatusCode, ShouldEqual, expectedStatusCode) 144 if apiErr, ok := expectedErr.(apiv3.APIError); ok { 145 So(apiErr.Message, ShouldEqual, errResult.Message) 146 } else { 147 So(expectedErr.Error(), ShouldEqual, errResult.Message) 148 } 149 So(resp.Code, ShouldEqual, expectedStatusCode) 150 } else if len(expectedModels) > 0 { 151 wrappedBody := ioutil.NopCloser(resp.Body) 152 153 var respResult []*model.MockModel 154 if len(expectedModels) == 1 { 155 singleResult := &model.MockModel{} 156 err := util.ReadJSONInto(wrappedBody, singleResult) 157 So(err, ShouldBeNil) 158 respResult = append(respResult, singleResult) 159 } else { 160 err := util.ReadJSONInto(wrappedBody, &respResult) 161 So(err, ShouldBeNil) 162 } 163 164 for ix, res := range respResult { 165 var resModel model.Model = res 166 So(resModel, ShouldResemble, expectedModels[ix]) 167 } 168 169 } else { 170 t.Errorf("Expected-error and expected-model cannot both be nil") 171 } 172 173 if headerCheck != nil { 174 headerCheck(resp.Header(), t) 175 } 176 }