summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/onsi/gomega/ghttp/handlers.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/onsi/gomega/ghttp/handlers.go')
-rw-r--r--vendor/github.com/onsi/gomega/ghttp/handlers.go313
1 files changed, 313 insertions, 0 deletions
diff --git a/vendor/github.com/onsi/gomega/ghttp/handlers.go b/vendor/github.com/onsi/gomega/ghttp/handlers.go
new file mode 100644
index 0000000..63ff691
--- /dev/null
+++ b/vendor/github.com/onsi/gomega/ghttp/handlers.go
@@ -0,0 +1,313 @@
+package ghttp
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "reflect"
+
+ "github.com/golang/protobuf/proto"
+ . "github.com/onsi/gomega"
+ "github.com/onsi/gomega/types"
+)
+
+//CombineHandler takes variadic list of handlers and produces one handler
+//that calls each handler in order.
+func CombineHandlers(handlers ...http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ for _, handler := range handlers {
+ handler(w, req)
+ }
+ }
+}
+
+//VerifyRequest returns a handler that verifies that a request uses the specified method to connect to the specified path
+//You may also pass in an optional rawQuery string which is tested against the request's `req.URL.RawQuery`
+//
+//For path, you may pass in a string, in which case strict equality will be applied
+//Alternatively you can pass in a matcher (ContainSubstring("/foo") and MatchRegexp("/foo/[a-f0-9]+") for example)
+func VerifyRequest(method string, path interface{}, rawQuery ...string) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ Ω(req.Method).Should(Equal(method), "Method mismatch")
+ switch p := path.(type) {
+ case types.GomegaMatcher:
+ Ω(req.URL.Path).Should(p, "Path mismatch")
+ default:
+ Ω(req.URL.Path).Should(Equal(path), "Path mismatch")
+ }
+ if len(rawQuery) > 0 {
+ values, err := url.ParseQuery(rawQuery[0])
+ Ω(err).ShouldNot(HaveOccurred(), "Expected RawQuery is malformed")
+
+ Ω(req.URL.Query()).Should(Equal(values), "RawQuery mismatch")
+ }
+ }
+}
+
+//VerifyContentType returns a handler that verifies that a request has a Content-Type header set to the
+//specified value
+func VerifyContentType(contentType string) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ Ω(req.Header.Get("Content-Type")).Should(Equal(contentType))
+ }
+}
+
+//VerifyBasicAuth returns a handler that verifies the request contains a BasicAuth Authorization header
+//matching the passed in username and password
+func VerifyBasicAuth(username string, password string) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ auth := req.Header.Get("Authorization")
+ Ω(auth).ShouldNot(Equal(""), "Authorization header must be specified")
+
+ decoded, err := base64.StdEncoding.DecodeString(auth[6:])
+ Ω(err).ShouldNot(HaveOccurred())
+
+ Ω(string(decoded)).Should(Equal(fmt.Sprintf("%s:%s", username, password)), "Authorization mismatch")
+ }
+}
+
+//VerifyHeader returns a handler that verifies the request contains the passed in headers.
+//The passed in header keys are first canonicalized via http.CanonicalHeaderKey.
+//
+//The request must contain *all* the passed in headers, but it is allowed to have additional headers
+//beyond the passed in set.
+func VerifyHeader(header http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ for key, values := range header {
+ key = http.CanonicalHeaderKey(key)
+ Ω(req.Header[key]).Should(Equal(values), "Header mismatch for key: %s", key)
+ }
+ }
+}
+
+//VerifyHeaderKV returns a handler that verifies the request contains a header matching the passed in key and values
+//(recall that a `http.Header` is a mapping from string (key) to []string (values))
+//It is a convenience wrapper around `VerifyHeader` that allows you to avoid having to create an `http.Header` object.
+func VerifyHeaderKV(key string, values ...string) http.HandlerFunc {
+ return VerifyHeader(http.Header{key: values})
+}
+
+//VerifyBody returns a handler that verifies that the body of the request matches the passed in byte array.
+//It does this using Equal().
+func VerifyBody(expectedBody []byte) http.HandlerFunc {
+ return CombineHandlers(
+ func(w http.ResponseWriter, req *http.Request) {
+ body, err := ioutil.ReadAll(req.Body)
+ req.Body.Close()
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(Equal(expectedBody), "Body Mismatch")
+ },
+ )
+}
+
+//VerifyJSON returns a handler that verifies that the body of the request is a valid JSON representation
+//matching the passed in JSON string. It does this using Gomega's MatchJSON method
+//
+//VerifyJSON also verifies that the request's content type is application/json
+func VerifyJSON(expectedJSON string) http.HandlerFunc {
+ return CombineHandlers(
+ VerifyContentType("application/json"),
+ func(w http.ResponseWriter, req *http.Request) {
+ body, err := ioutil.ReadAll(req.Body)
+ req.Body.Close()
+ Ω(err).ShouldNot(HaveOccurred())
+ Ω(body).Should(MatchJSON(expectedJSON), "JSON Mismatch")
+ },
+ )
+}
+
+//VerifyJSONRepresenting is similar to VerifyJSON. Instead of taking a JSON string, however, it
+//takes an arbitrary JSON-encodable object and verifies that the requests's body is a JSON representation
+//that matches the object
+func VerifyJSONRepresenting(object interface{}) http.HandlerFunc {
+ data, err := json.Marshal(object)
+ Ω(err).ShouldNot(HaveOccurred())
+ return CombineHandlers(
+ VerifyContentType("application/json"),
+ VerifyJSON(string(data)),
+ )
+}
+
+//VerifyForm returns a handler that verifies a request contains the specified form values.
+//
+//The request must contain *all* of the specified values, but it is allowed to have additional
+//form values beyond the passed in set.
+func VerifyForm(values url.Values) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
+ err := r.ParseForm()
+ Ω(err).ShouldNot(HaveOccurred())
+ for key, vals := range values {
+ Ω(r.Form[key]).Should(Equal(vals), "Form mismatch for key: %s", key)
+ }
+ }
+}
+
+//VerifyFormKV returns a handler that verifies a request contains a form key with the specified values.
+//
+//It is a convenience wrapper around `VerifyForm` that lets you avoid having to create a `url.Values` object.
+func VerifyFormKV(key string, values ...string) http.HandlerFunc {
+ return VerifyForm(url.Values{key: values})
+}
+
+//VerifyProtoRepresenting returns a handler that verifies that the body of the request is a valid protobuf
+//representation of the passed message.
+//
+//VerifyProtoRepresenting also verifies that the request's content type is application/x-protobuf
+func VerifyProtoRepresenting(expected proto.Message) http.HandlerFunc {
+ return CombineHandlers(
+ VerifyContentType("application/x-protobuf"),
+ func(w http.ResponseWriter, req *http.Request) {
+ body, err := ioutil.ReadAll(req.Body)
+ Ω(err).ShouldNot(HaveOccurred())
+ req.Body.Close()
+
+ expectedType := reflect.TypeOf(expected)
+ actualValuePtr := reflect.New(expectedType.Elem())
+
+ actual, ok := actualValuePtr.Interface().(proto.Message)
+ Ω(ok).Should(BeTrue(), "Message value is not a proto.Message")
+
+ err = proto.Unmarshal(body, actual)
+ Ω(err).ShouldNot(HaveOccurred(), "Failed to unmarshal protobuf")
+
+ Ω(actual).Should(Equal(expected), "ProtoBuf Mismatch")
+ },
+ )
+}
+
+func copyHeader(src http.Header, dst http.Header) {
+ for key, value := range src {
+ dst[key] = value
+ }
+}
+
+/*
+RespondWith returns a handler that responds to a request with the specified status code and body
+
+Body may be a string or []byte
+
+Also, RespondWith can be given an optional http.Header. The headers defined therein will be added to the response headers.
+*/
+func RespondWith(statusCode int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ if len(optionalHeader) == 1 {
+ copyHeader(optionalHeader[0], w.Header())
+ }
+ w.WriteHeader(statusCode)
+ switch x := body.(type) {
+ case string:
+ w.Write([]byte(x))
+ case []byte:
+ w.Write(x)
+ default:
+ Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
+ }
+ }
+}
+
+/*
+RespondWithPtr returns a handler that responds to a request with the specified status code and body
+
+Unlike RespondWith, you pass RepondWithPtr a pointer to the status code and body allowing different tests
+to share the same setup but specify different status codes and bodies.
+
+Also, RespondWithPtr can be given an optional http.Header. The headers defined therein will be added to the response headers.
+Since the http.Header can be mutated after the fact you don't need to pass in a pointer.
+*/
+func RespondWithPtr(statusCode *int, body interface{}, optionalHeader ...http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ if len(optionalHeader) == 1 {
+ copyHeader(optionalHeader[0], w.Header())
+ }
+ w.WriteHeader(*statusCode)
+ if body != nil {
+ switch x := (body).(type) {
+ case *string:
+ w.Write([]byte(*x))
+ case *[]byte:
+ w.Write(*x)
+ default:
+ Ω(body).Should(BeNil(), "Invalid type for body. Should be string or []byte.")
+ }
+ }
+ }
+}
+
+/*
+RespondWithJSONEncoded returns a handler that responds to a request with the specified status code and a body
+containing the JSON-encoding of the passed in object
+
+Also, RespondWithJSONEncoded can be given an optional http.Header. The headers defined therein will be added to the response headers.
+*/
+func RespondWithJSONEncoded(statusCode int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
+ data, err := json.Marshal(object)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ var headers http.Header
+ if len(optionalHeader) == 1 {
+ headers = optionalHeader[0]
+ } else {
+ headers = make(http.Header)
+ }
+ if _, found := headers["Content-Type"]; !found {
+ headers["Content-Type"] = []string{"application/json"}
+ }
+ return RespondWith(statusCode, string(data), headers)
+}
+
+/*
+RespondWithJSONEncodedPtr behaves like RespondWithJSONEncoded but takes a pointer
+to a status code and object.
+
+This allows different tests to share the same setup but specify different status codes and JSON-encoded
+objects.
+
+Also, RespondWithJSONEncodedPtr can be given an optional http.Header. The headers defined therein will be added to the response headers.
+Since the http.Header can be mutated after the fact you don't need to pass in a pointer.
+*/
+func RespondWithJSONEncodedPtr(statusCode *int, object interface{}, optionalHeader ...http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ data, err := json.Marshal(object)
+ Ω(err).ShouldNot(HaveOccurred())
+ var headers http.Header
+ if len(optionalHeader) == 1 {
+ headers = optionalHeader[0]
+ } else {
+ headers = make(http.Header)
+ }
+ if _, found := headers["Content-Type"]; !found {
+ headers["Content-Type"] = []string{"application/json"}
+ }
+ copyHeader(headers, w.Header())
+ w.WriteHeader(*statusCode)
+ w.Write(data)
+ }
+}
+
+//RespondWithProto returns a handler that responds to a request with the specified status code and a body
+//containing the protobuf serialization of the provided message.
+//
+//Also, RespondWithProto can be given an optional http.Header. The headers defined therein will be added to the response headers.
+func RespondWithProto(statusCode int, message proto.Message, optionalHeader ...http.Header) http.HandlerFunc {
+ return func(w http.ResponseWriter, req *http.Request) {
+ data, err := proto.Marshal(message)
+ Ω(err).ShouldNot(HaveOccurred())
+
+ var headers http.Header
+ if len(optionalHeader) == 1 {
+ headers = optionalHeader[0]
+ } else {
+ headers = make(http.Header)
+ }
+ if _, found := headers["Content-Type"]; !found {
+ headers["Content-Type"] = []string{"application/x-protobuf"}
+ }
+ copyHeader(headers, w.Header())
+
+ w.WriteHeader(statusCode)
+ w.Write(data)
+ }
+}