Codebase list golang-gomega / c0be499
ghttp with t Xander Flood authored 4 years ago William Martin committed 4 years ago
2 changed file(s) with 159 addition(s) and 51 deletion(s). Raw diff Collapse all Expand all
1212 "strings"
1313
1414 "github.com/golang/protobuf/proto"
15 "github.com/onsi/gomega"
1516 . "github.com/onsi/gomega"
1617 "github.com/onsi/gomega/types"
1718 )
1819
20 type GHTTPWithGomega struct {
21 gomega Gomega
22 }
23
24 func NewGHTTPWithGomega(gomega Gomega) *GHTTPWithGomega {
25 return &GHTTPWithGomega{
26 gomega: gomega,
27 }
28 }
29
1930 //CombineHandler takes variadic list of handlers and produces one handler
2031 //that calls each handler in order.
2132 func CombineHandlers(handlers ...http.HandlerFunc) http.HandlerFunc {
3142 //
3243 //For path, you may pass in a string, in which case strict equality will be applied
3344 //Alternatively you can pass in a matcher (ContainSubstring("/foo") and MatchRegexp("/foo/[a-f0-9]+") for example)
34 func VerifyRequest(method string, path interface{}, rawQuery ...string) http.HandlerFunc {
35 return func(w http.ResponseWriter, req *http.Request) {
36 Expect(req.Method).Should(Equal(method), "Method mismatch")
45 func (g GHTTPWithGomega) VerifyRequest(method string, path interface{}, rawQuery ...string) http.HandlerFunc {
46 return func(w http.ResponseWriter, req *http.Request) {
47 g.gomega.Expect(req.Method).Should(Equal(method), "Method mismatch")
3748 switch p := path.(type) {
3849 case types.GomegaMatcher:
39 Expect(req.URL.Path).Should(p, "Path mismatch")
50 g.gomega.Expect(req.URL.Path).Should(p, "Path mismatch")
4051 default:
41 Expect(req.URL.Path).Should(Equal(path), "Path mismatch")
52 g.gomega.Expect(req.URL.Path).Should(Equal(path), "Path mismatch")
4253 }
4354 if len(rawQuery) > 0 {
4455 values, err := url.ParseQuery(rawQuery[0])
45 Expect(err).ShouldNot(HaveOccurred(), "Expected RawQuery is malformed")
46
47 Expect(req.URL.Query()).Should(Equal(values), "RawQuery mismatch")
56 g.gomega.Expect(err).ShouldNot(HaveOccurred(), "Expected RawQuery is malformed")
57
58 g.gomega.Expect(req.URL.Query()).Should(Equal(values), "RawQuery mismatch")
4859 }
4960 }
5061 }
5162
5263 //VerifyContentType returns a handler that verifies that a request has a Content-Type header set to the
5364 //specified value
54 func VerifyContentType(contentType string) http.HandlerFunc {
55 return func(w http.ResponseWriter, req *http.Request) {
56 Expect(req.Header.Get("Content-Type")).Should(Equal(contentType))
65 func (g GHTTPWithGomega) VerifyContentType(contentType string) http.HandlerFunc {
66 return func(w http.ResponseWriter, req *http.Request) {
67 g.gomega.Expect(req.Header.Get("Content-Type")).Should(Equal(contentType))
5768 }
5869 }
5970
6071 //VerifyMimeType returns a handler that verifies that a request has a specified mime type set
6172 //in Content-Type header
62 func VerifyMimeType(mimeType string) http.HandlerFunc {
63 return func(w http.ResponseWriter, req *http.Request) {
64 Expect(strings.Split(req.Header.Get("Content-Type"), ";")[0]).Should(Equal(mimeType))
73 func (g GHTTPWithGomega) VerifyMimeType(mimeType string) http.HandlerFunc {
74 return func(w http.ResponseWriter, req *http.Request) {
75 g.gomega.Expect(strings.Split(req.Header.Get("Content-Type"), ";")[0]).Should(Equal(mimeType))
6576 }
6677 }
6778
6879 //VerifyBasicAuth returns a handler that verifies the request contains a BasicAuth Authorization header
6980 //matching the passed in username and password
70 func VerifyBasicAuth(username string, password string) http.HandlerFunc {
81 func (g GHTTPWithGomega) VerifyBasicAuth(username string, password string) http.HandlerFunc {
7182 return func(w http.ResponseWriter, req *http.Request) {
7283 auth := req.Header.Get("Authorization")
73 Expect(auth).ShouldNot(Equal(""), "Authorization header must be specified")
84 g.gomega.Expect(auth).ShouldNot(Equal(""), "Authorization header must be specified")
7485
7586 decoded, err := base64.StdEncoding.DecodeString(auth[6:])
76 Expect(err).ShouldNot(HaveOccurred())
77
78 Expect(string(decoded)).Should(Equal(fmt.Sprintf("%s:%s", username, password)), "Authorization mismatch")
87 g.gomega.Expect(err).ShouldNot(HaveOccurred())
88
89 g.gomega.Expect(string(decoded)).Should(Equal(fmt.Sprintf("%s:%s", username, password)), "Authorization mismatch")
7990 }
8091 }
8192
8495 //
8596 //The request must contain *all* the passed in headers, but it is allowed to have additional headers
8697 //beyond the passed in set.
87 func VerifyHeader(header http.Header) http.HandlerFunc {
98 func (g GHTTPWithGomega) VerifyHeader(header http.Header) http.HandlerFunc {
8899 return func(w http.ResponseWriter, req *http.Request) {
89100 for key, values := range header {
90101 key = http.CanonicalHeaderKey(key)
91 Expect(req.Header[key]).Should(Equal(values), "Header mismatch for key: %s", key)
102 g.gomega.Expect(req.Header[key]).Should(Equal(values), "Header mismatch for key: %s", key)
92103 }
93104 }
94105 }
96107 //VerifyHeaderKV returns a handler that verifies the request contains a header matching the passed in key and values
97108 //(recall that a `http.Header` is a mapping from string (key) to []string (values))
98109 //It is a convenience wrapper around `VerifyHeader` that allows you to avoid having to create an `http.Header` object.
99 func VerifyHeaderKV(key string, values ...string) http.HandlerFunc {
110 func (g GHTTPWithGomega) VerifyHeaderKV(key string, values ...string) http.HandlerFunc {
100111 return VerifyHeader(http.Header{key: values})
101112 }
102113
103114 //VerifyBody returns a handler that verifies that the body of the request matches the passed in byte array.
104115 //It does this using Equal().
105 func VerifyBody(expectedBody []byte) http.HandlerFunc {
116 func (g GHTTPWithGomega) VerifyBody(expectedBody []byte) http.HandlerFunc {
106117 return CombineHandlers(
107118 func(w http.ResponseWriter, req *http.Request) {
108119 body, err := ioutil.ReadAll(req.Body)
109120 req.Body.Close()
110 Expect(err).ShouldNot(HaveOccurred())
111 Expect(body).Should(Equal(expectedBody), "Body Mismatch")
121 g.gomega.Expect(err).ShouldNot(HaveOccurred())
122 g.gomega.Expect(body).Should(Equal(expectedBody), "Body Mismatch")
112123 },
113124 )
114125 }
117128 //matching the passed in JSON string. It does this using Gomega's MatchJSON method
118129 //
119130 //VerifyJSON also verifies that the request's content type is application/json
120 func VerifyJSON(expectedJSON string) http.HandlerFunc {
131 func (g GHTTPWithGomega) VerifyJSON(expectedJSON string) http.HandlerFunc {
121132 return CombineHandlers(
122133 VerifyMimeType("application/json"),
123134 func(w http.ResponseWriter, req *http.Request) {
124135 body, err := ioutil.ReadAll(req.Body)
125136 req.Body.Close()
126 Expect(err).ShouldNot(HaveOccurred())
127 Expect(body).Should(MatchJSON(expectedJSON), "JSON Mismatch")
137 g.gomega.Expect(err).ShouldNot(HaveOccurred())
138 g.gomega.Expect(body).Should(MatchJSON(expectedJSON), "JSON Mismatch")
128139 },
129140 )
130141 }
132143 //VerifyJSONRepresenting is similar to VerifyJSON. Instead of taking a JSON string, however, it
133144 //takes an arbitrary JSON-encodable object and verifies that the requests's body is a JSON representation
134145 //that matches the object
135 func VerifyJSONRepresenting(object interface{}) http.HandlerFunc {
146 func (g GHTTPWithGomega) VerifyJSONRepresenting(object interface{}) http.HandlerFunc {
136147 data, err := json.Marshal(object)
137 Expect(err).ShouldNot(HaveOccurred())
148 g.gomega.Expect(err).ShouldNot(HaveOccurred())
138149 return CombineHandlers(
139150 VerifyMimeType("application/json"),
140151 VerifyJSON(string(data)),
145156 //
146157 //The request must contain *all* of the specified values, but it is allowed to have additional
147158 //form values beyond the passed in set.
148 func VerifyForm(values url.Values) http.HandlerFunc {
159 func (g GHTTPWithGomega) VerifyForm(values url.Values) http.HandlerFunc {
149160 return func(w http.ResponseWriter, r *http.Request) {
150161 err := r.ParseForm()
151 Expect(err).ShouldNot(HaveOccurred())
162 g.gomega.Expect(err).ShouldNot(HaveOccurred())
152163 for key, vals := range values {
153 Expect(r.Form[key]).Should(Equal(vals), "Form mismatch for key: %s", key)
164 g.gomega.Expect(r.Form[key]).Should(Equal(vals), "Form mismatch for key: %s", key)
154165 }
155166 }
156167 }
158169 //VerifyFormKV returns a handler that verifies a request contains a form key with the specified values.
159170 //
160171 //It is a convenience wrapper around `VerifyForm` that lets you avoid having to create a `url.Values` object.
161 func VerifyFormKV(key string, values ...string) http.HandlerFunc {
172 func (g GHTTPWithGomega) VerifyFormKV(key string, values ...string) http.HandlerFunc {
162173 return VerifyForm(url.Values{key: values})
163174 }
164175
166177 //representation of the passed message.
167178 //
168179 //VerifyProtoRepresenting also verifies that the request's content type is application/x-protobuf
169 func VerifyProtoRepresenting(expected proto.Message) http.HandlerFunc {
180 func (g GHTTPWithGomega) VerifyProtoRepresenting(expected proto.Message) http.HandlerFunc {
170181 return CombineHandlers(
171182 VerifyContentType("application/x-protobuf"),
172183 func(w http.ResponseWriter, req *http.Request) {
173184 body, err := ioutil.ReadAll(req.Body)
174 Expect(err).ShouldNot(HaveOccurred())
185 g.gomega.Expect(err).ShouldNot(HaveOccurred())
175186 req.Body.Close()
176187
177188 expectedType := reflect.TypeOf(expected)
178189 actualValuePtr := reflect.New(expectedType.Elem())
179190
180191 actual, ok := actualValuePtr.Interface().(proto.Message)
181 Expect(ok).Should(BeTrue(), "Message value is not a proto.Message")
192 g.gomega.Expect(ok).Should(BeTrue(), "Message value is not a proto.Message")
182193
183194 err = proto.Unmarshal(body, actual)
184 Expect(err).ShouldNot(HaveOccurred(), "Failed to unmarshal protobuf")
185
186 Expect(actual).Should(Equal(expected), "ProtoBuf Mismatch")
195 g.gomega.Expect(err).ShouldNot(HaveOccurred(), "Failed to unmarshal protobuf")
196
197 g.gomega.Expect(actual).Should(Equal(expected), "ProtoBuf Mismatch")
187198 },
188199 )
189200 }
201212
202213 Also, RespondWith can be given an optional http.Header. The headers defined therein will be added to the response headers.
203214 */
204 func RespondWith(statusCode int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
215 func (g GHTTPWithGomega) RespondWith(statusCode int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
205216 return func(w http.ResponseWriter, req *http.Request) {
206217 if len(optionalHeader) == 1 {
207218 copyHeader(optionalHeader[0], w.Header())
213224 case []byte:
214225 w.Write(x)
215226 default:
216 Expect(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
227 g.gomega.Expect(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
217228 }
218229 }
219230 }
227238 Also, RespondWithPtr can be given an optional http.Header. The headers defined therein will be added to the response headers.
228239 Since the http.Header can be mutated after the fact you don't need to pass in a pointer.
229240 */
230 func RespondWithPtr(statusCode *int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
241 func (g GHTTPWithGomega) RespondWithPtr(statusCode *int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
231242 return func(w http.ResponseWriter, req *http.Request) {
232243 if len(optionalHeader) == 1 {
233244 copyHeader(optionalHeader[0], w.Header())
240251 case *[]byte:
241252 w.Write(*x)
242253 default:
243 Expect(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
254 g.gomega.Expect(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
244255 }
245256 }
246257 }
252263
253264 Also, RespondWithJSONEncoded can be given an optional http.Header. The headers defined therein will be added to the response headers.
254265 */
255 func RespondWithJSONEncoded(statusCode int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
266 func (g GHTTPWithGomega) RespondWithJSONEncoded(statusCode int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
256267 data, err := json.Marshal(object)
257 Expect(err).ShouldNot(HaveOccurred())
268 g.gomega.Expect(err).ShouldNot(HaveOccurred())
258269
259270 var headers http.Header
260271 if len(optionalHeader) == 1 {
278289 Also, RespondWithJSONEncodedPtr can be given an optional http.Header. The headers defined therein will be added to the response headers.
279290 Since the http.Header can be mutated after the fact you don't need to pass in a pointer.
280291 */
281 func RespondWithJSONEncodedPtr(statusCode *int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
292 func (g GHTTPWithGomega) RespondWithJSONEncodedPtr(statusCode *int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
282293 return func(w http.ResponseWriter, req *http.Request) {
283294 data, err := json.Marshal(object)
284 Expect(err).ShouldNot(HaveOccurred())
295 g.gomega.Expect(err).ShouldNot(HaveOccurred())
285296 var headers http.Header
286297 if len(optionalHeader) == 1 {
287298 headers = optionalHeader[0]
301312 //containing the protobuf serialization of the provided message.
302313 //
303314 //Also, RespondWithProto can be given an optional http.Header. The headers defined therein will be added to the response headers.
304 func RespondWithProto(statusCode int, message proto.Message, optionalHeader ...http.Header) http.HandlerFunc {
315 func (g GHTTPWithGomega) RespondWithProto(statusCode int, message proto.Message, optionalHeader ...http.Header) http.HandlerFunc {
305316 return func(w http.ResponseWriter, req *http.Request) {
306317 data, err := proto.Marshal(message)
307 Expect(err).ShouldNot(HaveOccurred())
318 g.gomega.Expect(err).ShouldNot(HaveOccurred())
308319
309320 var headers http.Header
310321 if len(optionalHeader) == 1 {
321332 w.Write(data)
322333 }
323334 }
335
336 func VerifyRequest(method string, path interface{}, rawQuery ...string) http.HandlerFunc {
337 return NewGHTTPWithGomega(gomega.Default).VerifyRequest(method, path, rawQuery...)
338 }
339
340 func VerifyContentType(contentType string) http.HandlerFunc {
341 return NewGHTTPWithGomega(gomega.Default).VerifyContentType(contentType)
342 }
343
344 func VerifyMimeType(mimeType string) http.HandlerFunc {
345 return NewGHTTPWithGomega(gomega.Default).VerifyMimeType(mimeType)
346 }
347
348 func VerifyBasicAuth(username string, password string) http.HandlerFunc {
349 return NewGHTTPWithGomega(gomega.Default).VerifyBasicAuth(username, password)
350 }
351
352 func VerifyHeader(header http.Header) http.HandlerFunc {
353 return NewGHTTPWithGomega(gomega.Default).VerifyHeader(header)
354 }
355
356 func VerifyHeaderKV(key string, values ...string) http.HandlerFunc {
357 return NewGHTTPWithGomega(gomega.Default).VerifyHeaderKV(key, values...)
358 }
359
360 func VerifyBody(expectedBody []byte) http.HandlerFunc {
361 return NewGHTTPWithGomega(gomega.Default).VerifyBody(expectedBody)
362 }
363
364 func VerifyJSON(expectedJSON string) http.HandlerFunc {
365 return NewGHTTPWithGomega(gomega.Default).VerifyJSON(expectedJSON)
366 }
367
368 func VerifyJSONRepresenting(object interface{}) http.HandlerFunc {
369 return NewGHTTPWithGomega(gomega.Default).VerifyJSONRepresenting(object)
370 }
371
372 func VerifyForm(values url.Values) http.HandlerFunc {
373 return NewGHTTPWithGomega(gomega.Default).VerifyForm(values)
374 }
375
376 func VerifyFormKV(key string, values ...string) http.HandlerFunc {
377 return NewGHTTPWithGomega(gomega.Default).VerifyFormKV(key, values...)
378 }
379
380 func VerifyProtoRepresenting(expected proto.Message) http.HandlerFunc {
381 return NewGHTTPWithGomega(gomega.Default).VerifyProtoRepresenting(expected)
382 }
383
384 func RespondWith(statusCode int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
385 return NewGHTTPWithGomega(gomega.Default).RespondWith(statusCode, body, optionalHeader...)
386 }
387
388 func RespondWithPtr(statusCode *int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
389 return NewGHTTPWithGomega(gomega.Default).RespondWithPtr(statusCode, body, optionalHeader...)
390 }
391
392 func RespondWithJSONEncoded(statusCode int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
393 return NewGHTTPWithGomega(gomega.Default).RespondWithJSONEncoded(statusCode, object, optionalHeader...)
394 }
395
396 func RespondWithJSONEncodedPtr(statusCode *int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
397 return NewGHTTPWithGomega(gomega.Default).RespondWithJSONEncodedPtr(statusCode, object, optionalHeader...)
398 }
399
400 func RespondWithProto(statusCode int, message proto.Message, optionalHeader ...http.Header) http.HandlerFunc {
401 return NewGHTTPWithGomega(gomega.Default).RespondWithProto(statusCode, message, optionalHeader...)
402 }
251251 return ConsistentlyWithOffset(0, actual, intervals...)
252252 }
253253
254 // ConsistentlyWithOffset operates like Consistnetly but takes an additional
254 // ConsistentlyWithOffset operates like Consistently but takes an additional
255255 // initial argument to indicate an offset in the call stack. This is useful when building helper
256256 // functions that contain matchers. To learn more, read about `ExpectWithOffset`.
257257 func ConsistentlyWithOffset(offset int, actual interface{}, intervals ...interface{}) AsyncAssertion {
431431
432432 panic(fmt.Sprintf("%v is not a valid interval. Must be time.Duration, parsable duration string or a number.", input))
433433 }
434
435 // Gomega describes the essential Gomega DSL. This interface allows libraries
436 // to abstract between the standard package-level function implementations
437 // and alternatives like *WithT.
438 type Gomega interface {
439 Expect(actual interface{}, extra ...interface{}) Assertion
440 Eventually(actual interface{}, intervals ...interface{}) AsyncAssertion
441 Consistently(actual interface{}, intervals ...interface{}) AsyncAssertion
442 }
443
444 type globalFailHandlerGomega struct{}
445
446 // DefaultGomega supplies the standard package-level implementation
447 var Default Gomega = globalFailHandlerGomega{}
448
449 // Expect is used to make assertions. See documentation for Expect.
450 func (globalFailHandlerGomega) Expect(actual interface{}, extra ...interface{}) Assertion {
451 return Expect(actual, extra...)
452 }
453
454 // Eventually is used to make asynchronous assertions. See documentation for Eventually.
455 func (globalFailHandlerGomega) Eventually(actual interface{}, extra ...interface{}) AsyncAssertion {
456 return Eventually(actual, extra...)
457 }
458
459 // Consistently is used to make asynchronous assertions. See documentation for Consistently.
460 func (globalFailHandlerGomega) Consistently(actual interface{}, extra ...interface{}) AsyncAssertion {
461 return Consistently(actual, extra...)
462 }