|  | package ghttp_test | 
|  |  | 
|  | import ( | 
|  | "bytes" | 
|  | "io" | 
|  | "io/ioutil" | 
|  | "net/http" | 
|  | "net/url" | 
|  | "regexp" | 
|  |  | 
|  | "github.com/golang/protobuf/proto" | 
|  | "github.com/onsi/gomega/gbytes" | 
|  | "github.com/onsi/gomega/ghttp/protobuf" | 
|  |  | 
|  | . "github.com/onsi/ginkgo" | 
|  | . "github.com/onsi/gomega" | 
|  | . "github.com/onsi/gomega/ghttp" | 
|  | ) | 
|  |  | 
|  | var _ = Describe("TestServer", func() { | 
|  | var ( | 
|  | resp *http.Response | 
|  | err  error | 
|  | s    *Server | 
|  | ) | 
|  |  | 
|  | BeforeEach(func() { | 
|  | s = NewServer() | 
|  | }) | 
|  |  | 
|  | AfterEach(func() { | 
|  | s.Close() | 
|  | }) | 
|  |  | 
|  | Describe("Resetting the server", func() { | 
|  | BeforeEach(func() { | 
|  | s.RouteToHandler("GET", "/", func(w http.ResponseWriter, req *http.Request) {}) | 
|  | s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {}) | 
|  | http.Get(s.URL() + "/") | 
|  |  | 
|  | Ω(s.ReceivedRequests()).Should(HaveLen(1)) | 
|  | }) | 
|  |  | 
|  | It("clears all handlers and call counts", func() { | 
|  | s.Reset() | 
|  | Ω(s.ReceivedRequests()).Should(HaveLen(0)) | 
|  | Ω(func() { s.GetHandler(0) }).Should(Panic()) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("closing client connections", func() { | 
|  | It("closes", func() { | 
|  | s.RouteToHandler("GET", "/", | 
|  | func(w http.ResponseWriter, req *http.Request) { | 
|  | io.WriteString(w, req.RemoteAddr) | 
|  | }, | 
|  | ) | 
|  | client := http.Client{Transport: &http.Transport{DisableKeepAlives: true}} | 
|  | resp, err := client.Get(s.URL()) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(resp.StatusCode).Should(Equal(200)) | 
|  |  | 
|  | body, err := ioutil.ReadAll(resp.Body) | 
|  | resp.Body.Close() | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | s.CloseClientConnections() | 
|  |  | 
|  | resp, err = client.Get(s.URL()) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(resp.StatusCode).Should(Equal(200)) | 
|  |  | 
|  | body2, err := ioutil.ReadAll(resp.Body) | 
|  | resp.Body.Close() | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(body2).ShouldNot(Equal(body)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("closing server mulitple times", func() { | 
|  | It("should not fail", func() { | 
|  | s.Close() | 
|  | Ω(s.Close).ShouldNot(Panic()) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("allowing unhandled requests", func() { | 
|  | Context("when true", func() { | 
|  | BeforeEach(func() { | 
|  | s.AllowUnhandledRequests = true | 
|  | s.UnhandledRequestStatusCode = http.StatusForbidden | 
|  | resp, err = http.Get(s.URL() + "/foo") | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should allow unhandled requests and respond with the passed in status code", func() { | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusForbidden)) | 
|  |  | 
|  | data, err := ioutil.ReadAll(resp.Body) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(data).Should(BeEmpty()) | 
|  | }) | 
|  |  | 
|  | It("should record the requests", func() { | 
|  | Ω(s.ReceivedRequests()).Should(HaveLen(1)) | 
|  | Ω(s.ReceivedRequests()[0].URL.Path).Should(Equal("/foo")) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when false", func() { | 
|  | It("should fail when attempting a request", func() { | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Get(s.URL() + "/foo") | 
|  | }) | 
|  |  | 
|  | Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request")) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("Managing Handlers", func() { | 
|  | var called []string | 
|  | BeforeEach(func() { | 
|  | called = []string{} | 
|  | s.RouteToHandler("GET", "/routed", func(w http.ResponseWriter, req *http.Request) { | 
|  | called = append(called, "r1") | 
|  | }) | 
|  | s.RouteToHandler("POST", regexp.MustCompile(`/routed\d`), func(w http.ResponseWriter, req *http.Request) { | 
|  | called = append(called, "r2") | 
|  | }) | 
|  | s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) { | 
|  | called = append(called, "A") | 
|  | }, func(w http.ResponseWriter, req *http.Request) { | 
|  | called = append(called, "B") | 
|  | }) | 
|  | }) | 
|  |  | 
|  | It("should prefer routed handlers if there is a match", func() { | 
|  | http.Get(s.URL() + "/routed") | 
|  | http.Post(s.URL()+"/routed7", "application/json", nil) | 
|  | http.Get(s.URL() + "/foo") | 
|  | http.Get(s.URL() + "/routed") | 
|  | http.Post(s.URL()+"/routed9", "application/json", nil) | 
|  | http.Get(s.URL() + "/bar") | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Get(s.URL() + "/foo") | 
|  | http.Get(s.URL() + "/routed/not/a/match") | 
|  | http.Get(s.URL() + "/routed7") | 
|  | http.Post(s.URL()+"/routed", "application/json", nil) | 
|  | }) | 
|  |  | 
|  | Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request")) | 
|  | Ω(failures).Should(HaveLen(4)) | 
|  |  | 
|  | http.Post(s.URL()+"/routed3", "application/json", nil) | 
|  |  | 
|  | Ω(called).Should(Equal([]string{"r1", "r2", "A", "r1", "r2", "B", "r2"})) | 
|  | }) | 
|  |  | 
|  | It("should override routed handlers when reregistered", func() { | 
|  | s.RouteToHandler("GET", "/routed", func(w http.ResponseWriter, req *http.Request) { | 
|  | called = append(called, "r3") | 
|  | }) | 
|  | s.RouteToHandler("POST", regexp.MustCompile(`/routed\d`), func(w http.ResponseWriter, req *http.Request) { | 
|  | called = append(called, "r4") | 
|  | }) | 
|  |  | 
|  | http.Get(s.URL() + "/routed") | 
|  | http.Post(s.URL()+"/routed7", "application/json", nil) | 
|  |  | 
|  | Ω(called).Should(Equal([]string{"r3", "r4"})) | 
|  | }) | 
|  |  | 
|  | It("should call the appended handlers, in order, as requests come in", func() { | 
|  | http.Get(s.URL() + "/foo") | 
|  | Ω(called).Should(Equal([]string{"A"})) | 
|  |  | 
|  | http.Get(s.URL() + "/foo") | 
|  | Ω(called).Should(Equal([]string{"A", "B"})) | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Get(s.URL() + "/foo") | 
|  | }) | 
|  |  | 
|  | Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request")) | 
|  | }) | 
|  |  | 
|  | Describe("Overwriting an existing handler", func() { | 
|  | BeforeEach(func() { | 
|  | s.SetHandler(0, func(w http.ResponseWriter, req *http.Request) { | 
|  | called = append(called, "C") | 
|  | }) | 
|  | }) | 
|  |  | 
|  | It("should override the specified handler", func() { | 
|  | http.Get(s.URL() + "/foo") | 
|  | http.Get(s.URL() + "/foo") | 
|  | Ω(called).Should(Equal([]string{"C", "B"})) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("Getting an existing handler", func() { | 
|  | It("should return the handler func", func() { | 
|  | s.GetHandler(1)(nil, nil) | 
|  | Ω(called).Should(Equal([]string{"B"})) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("Wrapping an existing handler", func() { | 
|  | BeforeEach(func() { | 
|  | s.WrapHandler(0, func(w http.ResponseWriter, req *http.Request) { | 
|  | called = append(called, "C") | 
|  | }) | 
|  | }) | 
|  |  | 
|  | It("should wrap the existing handler in a new handler", func() { | 
|  | http.Get(s.URL() + "/foo") | 
|  | http.Get(s.URL() + "/foo") | 
|  | Ω(called).Should(Equal([]string{"A", "C", "B"})) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("When a handler fails", func() { | 
|  | BeforeEach(func() { | 
|  | s.UnhandledRequestStatusCode = http.StatusForbidden //just to be clear that 500s aren't coming from unhandled requests | 
|  | }) | 
|  |  | 
|  | Context("because the handler has panicked", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) { | 
|  | panic("bam") | 
|  | }) | 
|  | }) | 
|  |  | 
|  | It("should respond with a 500 and make a failing assertion", func() { | 
|  | var resp *http.Response | 
|  | var err error | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | resp, err = http.Get(s.URL()) | 
|  | }) | 
|  |  | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) | 
|  | Ω(failures).Should(ConsistOf(ContainSubstring("Handler Panicked"))) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("because an assertion has failed", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) { | 
|  | // Ω(true).Should(BeFalse()) <-- would be nice to do it this way, but the test just can't be written this way | 
|  |  | 
|  | By("We're cheating a bit here -- we're throwing a GINKGO_PANIC which simulates a failed assertion") | 
|  | panic(GINKGO_PANIC) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | It("should respond with a 500 and *not* make a failing assertion, instead relying on Ginkgo to have already been notified of the error", func() { | 
|  | resp, err := http.Get(s.URL()) | 
|  |  | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("Logging to the Writer", func() { | 
|  | var buf *gbytes.Buffer | 
|  | BeforeEach(func() { | 
|  | buf = gbytes.NewBuffer() | 
|  | s.Writer = buf | 
|  | s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {}) | 
|  | s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {}) | 
|  | }) | 
|  |  | 
|  | It("should write to the buffer when a request comes in", func() { | 
|  | http.Get(s.URL() + "/foo") | 
|  | Ω(buf).Should(gbytes.Say("GHTTP Received Request: GET - /foo\n")) | 
|  |  | 
|  | http.Post(s.URL()+"/bar", "", nil) | 
|  | Ω(buf).Should(gbytes.Say("GHTTP Received Request: POST - /bar\n")) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("Request Handlers", func() { | 
|  | Describe("VerifyRequest", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(VerifyRequest("GET", "/foo")) | 
|  | }) | 
|  |  | 
|  | It("should verify the method, path", func() { | 
|  | resp, err = http.Get(s.URL() + "/foo?baz=bar") | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should verify the method, path", func() { | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Get(s.URL() + "/foo2") | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  |  | 
|  | It("should verify the method, path", func() { | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  |  | 
|  | Context("when passed a rawQuery", func() { | 
|  | It("should also be possible to verify the rawQuery", func() { | 
|  | s.SetHandler(0, VerifyRequest("GET", "/foo", "baz=bar")) | 
|  | resp, err = http.Get(s.URL() + "/foo?baz=bar") | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should match irregardless of query parameter ordering", func() { | 
|  | s.SetHandler(0, VerifyRequest("GET", "/foo", "type=get&name=money")) | 
|  | u, _ := url.Parse(s.URL() + "/foo") | 
|  | u.RawQuery = url.Values{ | 
|  | "type": []string{"get"}, | 
|  | "name": []string{"money"}, | 
|  | }.Encode() | 
|  |  | 
|  | resp, err = http.Get(u.String()) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when passed a matcher for path", func() { | 
|  | It("should apply the matcher", func() { | 
|  | s.SetHandler(0, VerifyRequest("GET", MatchRegexp(`/foo/[a-f]*/3`))) | 
|  | resp, err = http.Get(s.URL() + "/foo/abcdefa/3") | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("VerifyContentType", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("GET", "/foo"), | 
|  | VerifyContentType("application/octet-stream"), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should verify the content type", func() { | 
|  | req, err := http.NewRequest("GET", s.URL()+"/foo", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | req.Header.Set("Content-Type", "application/octet-stream") | 
|  |  | 
|  | resp, err = http.DefaultClient.Do(req) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should verify the content type", func() { | 
|  | req, err := http.NewRequest("GET", s.URL()+"/foo", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | req.Header.Set("Content-Type", "application/json") | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.DefaultClient.Do(req) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("Verify BasicAuth", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("GET", "/foo"), | 
|  | VerifyBasicAuth("bob", "password"), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should verify basic auth", func() { | 
|  | req, err := http.NewRequest("GET", s.URL()+"/foo", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | req.SetBasicAuth("bob", "password") | 
|  |  | 
|  | resp, err = http.DefaultClient.Do(req) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should verify basic auth", func() { | 
|  | req, err := http.NewRequest("GET", s.URL()+"/foo", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | req.SetBasicAuth("bob", "bassword") | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.DefaultClient.Do(req) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  |  | 
|  | It("should require basic auth header", func() { | 
|  | req, err := http.NewRequest("GET", s.URL()+"/foo", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.DefaultClient.Do(req) | 
|  | }) | 
|  | Ω(failures).Should(ContainElement(ContainSubstring("Authorization header must be specified"))) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("VerifyHeader", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("GET", "/foo"), | 
|  | VerifyHeader(http.Header{ | 
|  | "accept":        []string{"jpeg", "png"}, | 
|  | "cache-control": []string{"omicron"}, | 
|  | "Return-Path":   []string{"hobbiton"}, | 
|  | }), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should verify the headers", func() { | 
|  | req, err := http.NewRequest("GET", s.URL()+"/foo", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | req.Header.Add("Accept", "jpeg") | 
|  | req.Header.Add("Accept", "png") | 
|  | req.Header.Add("Cache-Control", "omicron") | 
|  | req.Header.Add("return-path", "hobbiton") | 
|  |  | 
|  | resp, err = http.DefaultClient.Do(req) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should verify the headers", func() { | 
|  | req, err := http.NewRequest("GET", s.URL()+"/foo", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | req.Header.Add("Schmaccept", "jpeg") | 
|  | req.Header.Add("Schmaccept", "png") | 
|  | req.Header.Add("Cache-Control", "omicron") | 
|  | req.Header.Add("return-path", "hobbiton") | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.DefaultClient.Do(req) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("VerifyHeaderKV", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("GET", "/foo"), | 
|  | VerifyHeaderKV("accept", "jpeg", "png"), | 
|  | VerifyHeaderKV("cache-control", "omicron"), | 
|  | VerifyHeaderKV("Return-Path", "hobbiton"), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should verify the headers", func() { | 
|  | req, err := http.NewRequest("GET", s.URL()+"/foo", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | req.Header.Add("Accept", "jpeg") | 
|  | req.Header.Add("Accept", "png") | 
|  | req.Header.Add("Cache-Control", "omicron") | 
|  | req.Header.Add("return-path", "hobbiton") | 
|  |  | 
|  | resp, err = http.DefaultClient.Do(req) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should verify the headers", func() { | 
|  | req, err := http.NewRequest("GET", s.URL()+"/foo", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | req.Header.Add("Accept", "jpeg") | 
|  | req.Header.Add("Cache-Control", "omicron") | 
|  | req.Header.Add("return-path", "hobbiton") | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.DefaultClient.Do(req) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("VerifyBody", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | VerifyBody([]byte("some body")), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should verify the body", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("some body"))) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should verify the body", func() { | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("wrong body"))) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("VerifyJSON", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | VerifyJSON(`{"a":3, "b":2}`), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should verify the json body and the content type", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":3}`))) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should verify the json body and the content type", func() { | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":4}`))) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  |  | 
|  | It("should verify the json body and the content type", func() { | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Post(s.URL()+"/foo", "application/not-json", bytes.NewReader([]byte(`{"b":2, "a":3}`))) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("VerifyJSONRepresenting", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | VerifyJSONRepresenting([]int{1, 3, 5}), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should verify the json body and the content type", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3,5]`))) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should verify the json body and the content type", func() { | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3]`))) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("VerifyForm", func() { | 
|  | var formValues url.Values | 
|  |  | 
|  | BeforeEach(func() { | 
|  | formValues = make(url.Values) | 
|  | formValues.Add("users", "user1") | 
|  | formValues.Add("users", "user2") | 
|  | formValues.Add("group", "users") | 
|  | }) | 
|  |  | 
|  | Context("when encoded in the URL", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("GET", "/foo"), | 
|  | VerifyForm(url.Values{ | 
|  | "users": []string{"user1", "user2"}, | 
|  | "group": []string{"users"}, | 
|  | }), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should verify form values", func() { | 
|  | resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should ignore extra values", func() { | 
|  | formValues.Add("extra", "value") | 
|  | resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("fail on missing values", func() { | 
|  | formValues.Del("group") | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  |  | 
|  | It("fail on incorrect values", func() { | 
|  | formValues.Set("group", "wheel") | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode()) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when present in the body", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | VerifyForm(url.Values{ | 
|  | "users": []string{"user1", "user2"}, | 
|  | "group": []string{"users"}, | 
|  | }), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should verify form values", func() { | 
|  | resp, err = http.PostForm(s.URL()+"/foo", formValues) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should ignore extra values", func() { | 
|  | formValues.Add("extra", "value") | 
|  | resp, err = http.PostForm(s.URL()+"/foo", formValues) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("fail on missing values", func() { | 
|  | formValues.Del("group") | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | resp, err = http.PostForm(s.URL()+"/foo", formValues) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  |  | 
|  | It("fail on incorrect values", func() { | 
|  | formValues.Set("group", "wheel") | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | resp, err = http.PostForm(s.URL()+"/foo", formValues) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("VerifyFormKV", func() { | 
|  | Context("when encoded in the URL", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("GET", "/foo"), | 
|  | VerifyFormKV("users", "user1", "user2"), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("verifies the form value", func() { | 
|  | resp, err = http.Get(s.URL() + "/foo?users=user1&users=user2") | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("verifies the form value", func() { | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | resp, err = http.Get(s.URL() + "/foo?users=user1") | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when present in the body", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | VerifyFormKV("users", "user1", "user2"), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("verifies the form value", func() { | 
|  | resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1", "user2"}}) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("verifies the form value", func() { | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1"}}) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("VerifyProtoRepresenting", func() { | 
|  | var message *protobuf.SimpleMessage | 
|  |  | 
|  | BeforeEach(func() { | 
|  | message = new(protobuf.SimpleMessage) | 
|  | message.Description = proto.String("A description") | 
|  | message.Id = proto.Int32(0) | 
|  |  | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/proto"), | 
|  | VerifyProtoRepresenting(message), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("verifies the proto body and the content type", func() { | 
|  | serialized, err := proto.Marshal(message) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized)) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should verify the proto body and the content type", func() { | 
|  | serialized, err := proto.Marshal(&protobuf.SimpleMessage{ | 
|  | Description: proto.String("A description"), | 
|  | Id:          proto.Int32(0), | 
|  | Metadata:    proto.String("some metadata"), | 
|  | }) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized)) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  |  | 
|  | It("should verify the proto body and the content type", func() { | 
|  | serialized, err := proto.Marshal(message) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | http.Post(s.URL()+"/proto", "application/not-x-protobuf", bytes.NewReader(serialized)) | 
|  | }) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("RespondWith", func() { | 
|  | Context("without headers", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWith(http.StatusCreated, "sweet"), | 
|  | ), CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWith(http.StatusOK, []byte("sour")), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should return the response", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) | 
|  |  | 
|  | body, err := ioutil.ReadAll(resp.Body) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(body).Should(Equal([]byte("sweet"))) | 
|  |  | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusOK)) | 
|  |  | 
|  | body, err = ioutil.ReadAll(resp.Body) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(body).Should(Equal([]byte("sour"))) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("with headers", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWith(http.StatusCreated, "sweet", http.Header{"X-Custom-Header": []string{"my header"}}), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should return the headers too", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) | 
|  | Ω(ioutil.ReadAll(resp.Body)).Should(Equal([]byte("sweet"))) | 
|  | Ω(resp.Header.Get("X-Custom-Header")).Should(Equal("my header")) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("RespondWithPtr", func() { | 
|  | var code int | 
|  | var byteBody []byte | 
|  | var stringBody string | 
|  | BeforeEach(func() { | 
|  | code = http.StatusOK | 
|  | byteBody = []byte("sweet") | 
|  | stringBody = "sour" | 
|  |  | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWithPtr(&code, &byteBody), | 
|  | ), CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWithPtr(&code, &stringBody), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should return the response", func() { | 
|  | code = http.StatusCreated | 
|  | byteBody = []byte("tasty") | 
|  | stringBody = "treat" | 
|  |  | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) | 
|  |  | 
|  | body, err := ioutil.ReadAll(resp.Body) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(body).Should(Equal([]byte("tasty"))) | 
|  |  | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) | 
|  |  | 
|  | body, err = ioutil.ReadAll(resp.Body) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(body).Should(Equal([]byte("treat"))) | 
|  | }) | 
|  |  | 
|  | Context("when passed a nil body", func() { | 
|  | BeforeEach(func() { | 
|  | s.SetHandler(0, CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWithPtr(&code, nil), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should return an empty body and not explode", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  |  | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusOK)) | 
|  | body, err := ioutil.ReadAll(resp.Body) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(body).Should(BeEmpty()) | 
|  |  | 
|  | Ω(s.ReceivedRequests()).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("RespondWithJSON", func() { | 
|  | Context("when no optional headers are set", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWithJSONEncoded(http.StatusCreated, []int{1, 2, 3}), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should return the response", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) | 
|  |  | 
|  | body, err := ioutil.ReadAll(resp.Body) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(body).Should(MatchJSON("[1,2,3]")) | 
|  | }) | 
|  |  | 
|  | It("should set the Content-Type header to application/json", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when optional headers are set", func() { | 
|  | var headers http.Header | 
|  | BeforeEach(func() { | 
|  | headers = http.Header{"Stuff": []string{"things"}} | 
|  | }) | 
|  |  | 
|  | JustBeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWithJSONEncoded(http.StatusCreated, []int{1, 2, 3}, headers), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should preserve those headers", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"})) | 
|  | }) | 
|  |  | 
|  | It("should set the Content-Type header to application/json", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) | 
|  | }) | 
|  |  | 
|  | Context("when setting the Content-Type explicitly", func() { | 
|  | BeforeEach(func() { | 
|  | headers["Content-Type"] = []string{"not-json"} | 
|  | }) | 
|  |  | 
|  | It("should use the Content-Type header that was explicitly set", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"})) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("RespondWithJSONPtr", func() { | 
|  | type testObject struct { | 
|  | Key   string | 
|  | Value string | 
|  | } | 
|  |  | 
|  | var code int | 
|  | var object testObject | 
|  |  | 
|  | Context("when no optional headers are set", func() { | 
|  | BeforeEach(func() { | 
|  | code = http.StatusOK | 
|  | object = testObject{} | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWithJSONEncodedPtr(&code, &object), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should return the response", func() { | 
|  | code = http.StatusCreated | 
|  | object = testObject{ | 
|  | Key:   "Jim", | 
|  | Value: "Codes", | 
|  | } | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) | 
|  |  | 
|  | body, err := ioutil.ReadAll(resp.Body) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | Ω(body).Should(MatchJSON(`{"Key": "Jim", "Value": "Codes"}`)) | 
|  | }) | 
|  |  | 
|  | It("should set the Content-Type header to application/json", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when optional headers are set", func() { | 
|  | var headers http.Header | 
|  | BeforeEach(func() { | 
|  | headers = http.Header{"Stuff": []string{"things"}} | 
|  | }) | 
|  |  | 
|  | JustBeforeEach(func() { | 
|  | code = http.StatusOK | 
|  | object = testObject{} | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/foo"), | 
|  | RespondWithJSONEncodedPtr(&code, &object, headers), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should preserve those headers", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"})) | 
|  | }) | 
|  |  | 
|  | It("should set the Content-Type header to application/json", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"})) | 
|  | }) | 
|  |  | 
|  | Context("when setting the Content-Type explicitly", func() { | 
|  | BeforeEach(func() { | 
|  | headers["Content-Type"] = []string{"not-json"} | 
|  | }) | 
|  |  | 
|  | It("should use the Content-Type header that was explicitly set", func() { | 
|  | resp, err = http.Post(s.URL()+"/foo", "application/json", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"})) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("RespondWithProto", func() { | 
|  | var message *protobuf.SimpleMessage | 
|  |  | 
|  | BeforeEach(func() { | 
|  | message = new(protobuf.SimpleMessage) | 
|  | message.Description = proto.String("A description") | 
|  | message.Id = proto.Int32(99) | 
|  | }) | 
|  |  | 
|  | Context("when no optional headers are set", func() { | 
|  | BeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/proto"), | 
|  | RespondWithProto(http.StatusCreated, message), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should return the response", func() { | 
|  | resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.StatusCode).Should(Equal(http.StatusCreated)) | 
|  |  | 
|  | var received protobuf.SimpleMessage | 
|  | body, err := ioutil.ReadAll(resp.Body) | 
|  | err = proto.Unmarshal(body, &received) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | It("should set the Content-Type header to application/x-protobuf", func() { | 
|  | resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"})) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when optional headers are set", func() { | 
|  | var headers http.Header | 
|  | BeforeEach(func() { | 
|  | headers = http.Header{"Stuff": []string{"things"}} | 
|  | }) | 
|  |  | 
|  | JustBeforeEach(func() { | 
|  | s.AppendHandlers(CombineHandlers( | 
|  | VerifyRequest("POST", "/proto"), | 
|  | RespondWithProto(http.StatusCreated, message, headers), | 
|  | )) | 
|  | }) | 
|  |  | 
|  | It("should preserve those headers", func() { | 
|  | resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"})) | 
|  | }) | 
|  |  | 
|  | It("should set the Content-Type header to application/x-protobuf", func() { | 
|  | resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"})) | 
|  | }) | 
|  |  | 
|  | Context("when setting the Content-Type explicitly", func() { | 
|  | BeforeEach(func() { | 
|  | headers["Content-Type"] = []string{"not-x-protobuf"} | 
|  | }) | 
|  |  | 
|  | It("should use the Content-Type header that was explicitly set", func() { | 
|  | resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-x-protobuf"})) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  | }) | 
|  | }) |