initial commit
[govpp.git] / vendor / github.com / onsi / gomega / ghttp / test_server_test.go
1 package ghttp_test
2
3 import (
4         "bytes"
5         "io"
6         "io/ioutil"
7         "net/http"
8         "net/url"
9         "regexp"
10
11         "github.com/golang/protobuf/proto"
12         "github.com/onsi/gomega/gbytes"
13         "github.com/onsi/gomega/ghttp/protobuf"
14
15         . "github.com/onsi/ginkgo"
16         . "github.com/onsi/gomega"
17         . "github.com/onsi/gomega/ghttp"
18 )
19
20 var _ = Describe("TestServer", func() {
21         var (
22                 resp *http.Response
23                 err  error
24                 s    *Server
25         )
26
27         BeforeEach(func() {
28                 s = NewServer()
29         })
30
31         AfterEach(func() {
32                 s.Close()
33         })
34
35         Describe("Resetting the server", func() {
36                 BeforeEach(func() {
37                         s.RouteToHandler("GET", "/", func(w http.ResponseWriter, req *http.Request) {})
38                         s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {})
39                         http.Get(s.URL() + "/")
40
41                         Ω(s.ReceivedRequests()).Should(HaveLen(1))
42                 })
43
44                 It("clears all handlers and call counts", func() {
45                         s.Reset()
46                         Ω(s.ReceivedRequests()).Should(HaveLen(0))
47                         Ω(func() { s.GetHandler(0) }).Should(Panic())
48                 })
49         })
50
51         Describe("closing client connections", func() {
52                 It("closes", func() {
53                         s.RouteToHandler("GET", "/",
54                                 func(w http.ResponseWriter, req *http.Request) {
55                                         io.WriteString(w, req.RemoteAddr)
56                                 },
57                         )
58                         client := http.Client{Transport: &http.Transport{DisableKeepAlives: true}}
59                         resp, err := client.Get(s.URL())
60                         Ω(err).ShouldNot(HaveOccurred())
61                         Ω(resp.StatusCode).Should(Equal(200))
62
63                         body, err := ioutil.ReadAll(resp.Body)
64                         resp.Body.Close()
65                         Ω(err).ShouldNot(HaveOccurred())
66
67                         s.CloseClientConnections()
68
69                         resp, err = client.Get(s.URL())
70                         Ω(err).ShouldNot(HaveOccurred())
71                         Ω(resp.StatusCode).Should(Equal(200))
72
73                         body2, err := ioutil.ReadAll(resp.Body)
74                         resp.Body.Close()
75                         Ω(err).ShouldNot(HaveOccurred())
76
77                         Ω(body2).ShouldNot(Equal(body))
78                 })
79         })
80
81         Describe("closing server mulitple times", func() {
82                 It("should not fail", func() {
83                         s.Close()
84                         Ω(s.Close).ShouldNot(Panic())
85                 })
86         })
87
88         Describe("allowing unhandled requests", func() {
89                 Context("when true", func() {
90                         BeforeEach(func() {
91                                 s.AllowUnhandledRequests = true
92                                 s.UnhandledRequestStatusCode = http.StatusForbidden
93                                 resp, err = http.Get(s.URL() + "/foo")
94                                 Ω(err).ShouldNot(HaveOccurred())
95                         })
96
97                         It("should allow unhandled requests and respond with the passed in status code", func() {
98                                 Ω(err).ShouldNot(HaveOccurred())
99                                 Ω(resp.StatusCode).Should(Equal(http.StatusForbidden))
100
101                                 data, err := ioutil.ReadAll(resp.Body)
102                                 Ω(err).ShouldNot(HaveOccurred())
103                                 Ω(data).Should(BeEmpty())
104                         })
105
106                         It("should record the requests", func() {
107                                 Ω(s.ReceivedRequests()).Should(HaveLen(1))
108                                 Ω(s.ReceivedRequests()[0].URL.Path).Should(Equal("/foo"))
109                         })
110                 })
111
112                 Context("when false", func() {
113                         It("should fail when attempting a request", func() {
114                                 failures := InterceptGomegaFailures(func() {
115                                         http.Get(s.URL() + "/foo")
116                                 })
117
118                                 Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request"))
119                         })
120                 })
121         })
122
123         Describe("Managing Handlers", func() {
124                 var called []string
125                 BeforeEach(func() {
126                         called = []string{}
127                         s.RouteToHandler("GET", "/routed", func(w http.ResponseWriter, req *http.Request) {
128                                 called = append(called, "r1")
129                         })
130                         s.RouteToHandler("POST", regexp.MustCompile(`/routed\d`), func(w http.ResponseWriter, req *http.Request) {
131                                 called = append(called, "r2")
132                         })
133                         s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {
134                                 called = append(called, "A")
135                         }, func(w http.ResponseWriter, req *http.Request) {
136                                 called = append(called, "B")
137                         })
138                 })
139
140                 It("should prefer routed handlers if there is a match", func() {
141                         http.Get(s.URL() + "/routed")
142                         http.Post(s.URL()+"/routed7", "application/json", nil)
143                         http.Get(s.URL() + "/foo")
144                         http.Get(s.URL() + "/routed")
145                         http.Post(s.URL()+"/routed9", "application/json", nil)
146                         http.Get(s.URL() + "/bar")
147
148                         failures := InterceptGomegaFailures(func() {
149                                 http.Get(s.URL() + "/foo")
150                                 http.Get(s.URL() + "/routed/not/a/match")
151                                 http.Get(s.URL() + "/routed7")
152                                 http.Post(s.URL()+"/routed", "application/json", nil)
153                         })
154
155                         Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request"))
156                         Ω(failures).Should(HaveLen(4))
157
158                         http.Post(s.URL()+"/routed3", "application/json", nil)
159
160                         Ω(called).Should(Equal([]string{"r1", "r2", "A", "r1", "r2", "B", "r2"}))
161                 })
162
163                 It("should override routed handlers when reregistered", func() {
164                         s.RouteToHandler("GET", "/routed", func(w http.ResponseWriter, req *http.Request) {
165                                 called = append(called, "r3")
166                         })
167                         s.RouteToHandler("POST", regexp.MustCompile(`/routed\d`), func(w http.ResponseWriter, req *http.Request) {
168                                 called = append(called, "r4")
169                         })
170
171                         http.Get(s.URL() + "/routed")
172                         http.Post(s.URL()+"/routed7", "application/json", nil)
173
174                         Ω(called).Should(Equal([]string{"r3", "r4"}))
175                 })
176
177                 It("should call the appended handlers, in order, as requests come in", func() {
178                         http.Get(s.URL() + "/foo")
179                         Ω(called).Should(Equal([]string{"A"}))
180
181                         http.Get(s.URL() + "/foo")
182                         Ω(called).Should(Equal([]string{"A", "B"}))
183
184                         failures := InterceptGomegaFailures(func() {
185                                 http.Get(s.URL() + "/foo")
186                         })
187
188                         Ω(failures[0]).Should(ContainSubstring("Received Unhandled Request"))
189                 })
190
191                 Describe("Overwriting an existing handler", func() {
192                         BeforeEach(func() {
193                                 s.SetHandler(0, func(w http.ResponseWriter, req *http.Request) {
194                                         called = append(called, "C")
195                                 })
196                         })
197
198                         It("should override the specified handler", func() {
199                                 http.Get(s.URL() + "/foo")
200                                 http.Get(s.URL() + "/foo")
201                                 Ω(called).Should(Equal([]string{"C", "B"}))
202                         })
203                 })
204
205                 Describe("Getting an existing handler", func() {
206                         It("should return the handler func", func() {
207                                 s.GetHandler(1)(nil, nil)
208                                 Ω(called).Should(Equal([]string{"B"}))
209                         })
210                 })
211
212                 Describe("Wrapping an existing handler", func() {
213                         BeforeEach(func() {
214                                 s.WrapHandler(0, func(w http.ResponseWriter, req *http.Request) {
215                                         called = append(called, "C")
216                                 })
217                         })
218
219                         It("should wrap the existing handler in a new handler", func() {
220                                 http.Get(s.URL() + "/foo")
221                                 http.Get(s.URL() + "/foo")
222                                 Ω(called).Should(Equal([]string{"A", "C", "B"}))
223                         })
224                 })
225         })
226
227         Describe("When a handler fails", func() {
228                 BeforeEach(func() {
229                         s.UnhandledRequestStatusCode = http.StatusForbidden //just to be clear that 500s aren't coming from unhandled requests
230                 })
231
232                 Context("because the handler has panicked", func() {
233                         BeforeEach(func() {
234                                 s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {
235                                         panic("bam")
236                                 })
237                         })
238
239                         It("should respond with a 500 and make a failing assertion", func() {
240                                 var resp *http.Response
241                                 var err error
242
243                                 failures := InterceptGomegaFailures(func() {
244                                         resp, err = http.Get(s.URL())
245                                 })
246
247                                 Ω(err).ShouldNot(HaveOccurred())
248                                 Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
249                                 Ω(failures).Should(ConsistOf(ContainSubstring("Handler Panicked")))
250                         })
251                 })
252
253                 Context("because an assertion has failed", func() {
254                         BeforeEach(func() {
255                                 s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {
256                                         // Ω(true).Should(BeFalse()) <-- would be nice to do it this way, but the test just can't be written this way
257
258                                         By("We're cheating a bit here -- we're throwing a GINKGO_PANIC which simulates a failed assertion")
259                                         panic(GINKGO_PANIC)
260                                 })
261                         })
262
263                         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() {
264                                 resp, err := http.Get(s.URL())
265
266                                 Ω(err).ShouldNot(HaveOccurred())
267                                 Ω(resp.StatusCode).Should(Equal(http.StatusInternalServerError))
268                         })
269                 })
270         })
271
272         Describe("Logging to the Writer", func() {
273                 var buf *gbytes.Buffer
274                 BeforeEach(func() {
275                         buf = gbytes.NewBuffer()
276                         s.Writer = buf
277                         s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {})
278                         s.AppendHandlers(func(w http.ResponseWriter, req *http.Request) {})
279                 })
280
281                 It("should write to the buffer when a request comes in", func() {
282                         http.Get(s.URL() + "/foo")
283                         Ω(buf).Should(gbytes.Say("GHTTP Received Request: GET - /foo\n"))
284
285                         http.Post(s.URL()+"/bar", "", nil)
286                         Ω(buf).Should(gbytes.Say("GHTTP Received Request: POST - /bar\n"))
287                 })
288         })
289
290         Describe("Request Handlers", func() {
291                 Describe("VerifyRequest", func() {
292                         BeforeEach(func() {
293                                 s.AppendHandlers(VerifyRequest("GET", "/foo"))
294                         })
295
296                         It("should verify the method, path", func() {
297                                 resp, err = http.Get(s.URL() + "/foo?baz=bar")
298                                 Ω(err).ShouldNot(HaveOccurred())
299                         })
300
301                         It("should verify the method, path", func() {
302                                 failures := InterceptGomegaFailures(func() {
303                                         http.Get(s.URL() + "/foo2")
304                                 })
305                                 Ω(failures).Should(HaveLen(1))
306                         })
307
308                         It("should verify the method, path", func() {
309                                 failures := InterceptGomegaFailures(func() {
310                                         http.Post(s.URL()+"/foo", "application/json", nil)
311                                 })
312                                 Ω(failures).Should(HaveLen(1))
313                         })
314
315                         Context("when passed a rawQuery", func() {
316                                 It("should also be possible to verify the rawQuery", func() {
317                                         s.SetHandler(0, VerifyRequest("GET", "/foo", "baz=bar"))
318                                         resp, err = http.Get(s.URL() + "/foo?baz=bar")
319                                         Ω(err).ShouldNot(HaveOccurred())
320                                 })
321
322                                 It("should match irregardless of query parameter ordering", func() {
323                                         s.SetHandler(0, VerifyRequest("GET", "/foo", "type=get&name=money"))
324                                         u, _ := url.Parse(s.URL() + "/foo")
325                                         u.RawQuery = url.Values{
326                                                 "type": []string{"get"},
327                                                 "name": []string{"money"},
328                                         }.Encode()
329
330                                         resp, err = http.Get(u.String())
331                                         Ω(err).ShouldNot(HaveOccurred())
332                                 })
333                         })
334
335                         Context("when passed a matcher for path", func() {
336                                 It("should apply the matcher", func() {
337                                         s.SetHandler(0, VerifyRequest("GET", MatchRegexp(`/foo/[a-f]*/3`)))
338                                         resp, err = http.Get(s.URL() + "/foo/abcdefa/3")
339                                         Ω(err).ShouldNot(HaveOccurred())
340                                 })
341                         })
342                 })
343
344                 Describe("VerifyContentType", func() {
345                         BeforeEach(func() {
346                                 s.AppendHandlers(CombineHandlers(
347                                         VerifyRequest("GET", "/foo"),
348                                         VerifyContentType("application/octet-stream"),
349                                 ))
350                         })
351
352                         It("should verify the content type", func() {
353                                 req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
354                                 Ω(err).ShouldNot(HaveOccurred())
355                                 req.Header.Set("Content-Type", "application/octet-stream")
356
357                                 resp, err = http.DefaultClient.Do(req)
358                                 Ω(err).ShouldNot(HaveOccurred())
359                         })
360
361                         It("should verify the content type", func() {
362                                 req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
363                                 Ω(err).ShouldNot(HaveOccurred())
364                                 req.Header.Set("Content-Type", "application/json")
365
366                                 failures := InterceptGomegaFailures(func() {
367                                         http.DefaultClient.Do(req)
368                                 })
369                                 Ω(failures).Should(HaveLen(1))
370                         })
371                 })
372
373                 Describe("Verify BasicAuth", func() {
374                         BeforeEach(func() {
375                                 s.AppendHandlers(CombineHandlers(
376                                         VerifyRequest("GET", "/foo"),
377                                         VerifyBasicAuth("bob", "password"),
378                                 ))
379                         })
380
381                         It("should verify basic auth", func() {
382                                 req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
383                                 Ω(err).ShouldNot(HaveOccurred())
384                                 req.SetBasicAuth("bob", "password")
385
386                                 resp, err = http.DefaultClient.Do(req)
387                                 Ω(err).ShouldNot(HaveOccurred())
388                         })
389
390                         It("should verify basic auth", func() {
391                                 req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
392                                 Ω(err).ShouldNot(HaveOccurred())
393                                 req.SetBasicAuth("bob", "bassword")
394
395                                 failures := InterceptGomegaFailures(func() {
396                                         http.DefaultClient.Do(req)
397                                 })
398                                 Ω(failures).Should(HaveLen(1))
399                         })
400
401                         It("should require basic auth header", func() {
402                                 req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
403                                 Ω(err).ShouldNot(HaveOccurred())
404
405                                 failures := InterceptGomegaFailures(func() {
406                                         http.DefaultClient.Do(req)
407                                 })
408                                 Ω(failures).Should(ContainElement(ContainSubstring("Authorization header must be specified")))
409                         })
410                 })
411
412                 Describe("VerifyHeader", func() {
413                         BeforeEach(func() {
414                                 s.AppendHandlers(CombineHandlers(
415                                         VerifyRequest("GET", "/foo"),
416                                         VerifyHeader(http.Header{
417                                                 "accept":        []string{"jpeg", "png"},
418                                                 "cache-control": []string{"omicron"},
419                                                 "Return-Path":   []string{"hobbiton"},
420                                         }),
421                                 ))
422                         })
423
424                         It("should verify the headers", func() {
425                                 req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
426                                 Ω(err).ShouldNot(HaveOccurred())
427                                 req.Header.Add("Accept", "jpeg")
428                                 req.Header.Add("Accept", "png")
429                                 req.Header.Add("Cache-Control", "omicron")
430                                 req.Header.Add("return-path", "hobbiton")
431
432                                 resp, err = http.DefaultClient.Do(req)
433                                 Ω(err).ShouldNot(HaveOccurred())
434                         })
435
436                         It("should verify the headers", func() {
437                                 req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
438                                 Ω(err).ShouldNot(HaveOccurred())
439                                 req.Header.Add("Schmaccept", "jpeg")
440                                 req.Header.Add("Schmaccept", "png")
441                                 req.Header.Add("Cache-Control", "omicron")
442                                 req.Header.Add("return-path", "hobbiton")
443
444                                 failures := InterceptGomegaFailures(func() {
445                                         http.DefaultClient.Do(req)
446                                 })
447                                 Ω(failures).Should(HaveLen(1))
448                         })
449                 })
450
451                 Describe("VerifyHeaderKV", func() {
452                         BeforeEach(func() {
453                                 s.AppendHandlers(CombineHandlers(
454                                         VerifyRequest("GET", "/foo"),
455                                         VerifyHeaderKV("accept", "jpeg", "png"),
456                                         VerifyHeaderKV("cache-control", "omicron"),
457                                         VerifyHeaderKV("Return-Path", "hobbiton"),
458                                 ))
459                         })
460
461                         It("should verify the headers", func() {
462                                 req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
463                                 Ω(err).ShouldNot(HaveOccurred())
464                                 req.Header.Add("Accept", "jpeg")
465                                 req.Header.Add("Accept", "png")
466                                 req.Header.Add("Cache-Control", "omicron")
467                                 req.Header.Add("return-path", "hobbiton")
468
469                                 resp, err = http.DefaultClient.Do(req)
470                                 Ω(err).ShouldNot(HaveOccurred())
471                         })
472
473                         It("should verify the headers", func() {
474                                 req, err := http.NewRequest("GET", s.URL()+"/foo", nil)
475                                 Ω(err).ShouldNot(HaveOccurred())
476                                 req.Header.Add("Accept", "jpeg")
477                                 req.Header.Add("Cache-Control", "omicron")
478                                 req.Header.Add("return-path", "hobbiton")
479
480                                 failures := InterceptGomegaFailures(func() {
481                                         http.DefaultClient.Do(req)
482                                 })
483                                 Ω(failures).Should(HaveLen(1))
484                         })
485                 })
486
487                 Describe("VerifyBody", func() {
488                         BeforeEach(func() {
489                                 s.AppendHandlers(CombineHandlers(
490                                         VerifyRequest("POST", "/foo"),
491                                         VerifyBody([]byte("some body")),
492                                 ))
493                         })
494
495                         It("should verify the body", func() {
496                                 resp, err = http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("some body")))
497                                 Ω(err).ShouldNot(HaveOccurred())
498                         })
499
500                         It("should verify the body", func() {
501                                 failures := InterceptGomegaFailures(func() {
502                                         http.Post(s.URL()+"/foo", "", bytes.NewReader([]byte("wrong body")))
503                                 })
504                                 Ω(failures).Should(HaveLen(1))
505                         })
506                 })
507
508                 Describe("VerifyJSON", func() {
509                         BeforeEach(func() {
510                                 s.AppendHandlers(CombineHandlers(
511                                         VerifyRequest("POST", "/foo"),
512                                         VerifyJSON(`{"a":3, "b":2}`),
513                                 ))
514                         })
515
516                         It("should verify the json body and the content type", func() {
517                                 resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":3}`)))
518                                 Ω(err).ShouldNot(HaveOccurred())
519                         })
520
521                         It("should verify the json body and the content type", func() {
522                                 failures := InterceptGomegaFailures(func() {
523                                         http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`{"b":2, "a":4}`)))
524                                 })
525                                 Ω(failures).Should(HaveLen(1))
526                         })
527
528                         It("should verify the json body and the content type", func() {
529                                 failures := InterceptGomegaFailures(func() {
530                                         http.Post(s.URL()+"/foo", "application/not-json", bytes.NewReader([]byte(`{"b":2, "a":3}`)))
531                                 })
532                                 Ω(failures).Should(HaveLen(1))
533                         })
534                 })
535
536                 Describe("VerifyJSONRepresenting", func() {
537                         BeforeEach(func() {
538                                 s.AppendHandlers(CombineHandlers(
539                                         VerifyRequest("POST", "/foo"),
540                                         VerifyJSONRepresenting([]int{1, 3, 5}),
541                                 ))
542                         })
543
544                         It("should verify the json body and the content type", func() {
545                                 resp, err = http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3,5]`)))
546                                 Ω(err).ShouldNot(HaveOccurred())
547                         })
548
549                         It("should verify the json body and the content type", func() {
550                                 failures := InterceptGomegaFailures(func() {
551                                         http.Post(s.URL()+"/foo", "application/json", bytes.NewReader([]byte(`[1,3]`)))
552                                 })
553                                 Ω(failures).Should(HaveLen(1))
554                         })
555                 })
556
557                 Describe("VerifyForm", func() {
558                         var formValues url.Values
559
560                         BeforeEach(func() {
561                                 formValues = make(url.Values)
562                                 formValues.Add("users", "user1")
563                                 formValues.Add("users", "user2")
564                                 formValues.Add("group", "users")
565                         })
566
567                         Context("when encoded in the URL", func() {
568                                 BeforeEach(func() {
569                                         s.AppendHandlers(CombineHandlers(
570                                                 VerifyRequest("GET", "/foo"),
571                                                 VerifyForm(url.Values{
572                                                         "users": []string{"user1", "user2"},
573                                                         "group": []string{"users"},
574                                                 }),
575                                         ))
576                                 })
577
578                                 It("should verify form values", func() {
579                                         resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
580                                         Ω(err).ShouldNot(HaveOccurred())
581                                 })
582
583                                 It("should ignore extra values", func() {
584                                         formValues.Add("extra", "value")
585                                         resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
586                                         Ω(err).ShouldNot(HaveOccurred())
587                                 })
588
589                                 It("fail on missing values", func() {
590                                         formValues.Del("group")
591                                         failures := InterceptGomegaFailures(func() {
592                                                 resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
593                                         })
594                                         Ω(failures).Should(HaveLen(1))
595                                 })
596
597                                 It("fail on incorrect values", func() {
598                                         formValues.Set("group", "wheel")
599                                         failures := InterceptGomegaFailures(func() {
600                                                 resp, err = http.Get(s.URL() + "/foo?" + formValues.Encode())
601                                         })
602                                         Ω(failures).Should(HaveLen(1))
603                                 })
604                         })
605
606                         Context("when present in the body", func() {
607                                 BeforeEach(func() {
608                                         s.AppendHandlers(CombineHandlers(
609                                                 VerifyRequest("POST", "/foo"),
610                                                 VerifyForm(url.Values{
611                                                         "users": []string{"user1", "user2"},
612                                                         "group": []string{"users"},
613                                                 }),
614                                         ))
615                                 })
616
617                                 It("should verify form values", func() {
618                                         resp, err = http.PostForm(s.URL()+"/foo", formValues)
619                                         Ω(err).ShouldNot(HaveOccurred())
620                                 })
621
622                                 It("should ignore extra values", func() {
623                                         formValues.Add("extra", "value")
624                                         resp, err = http.PostForm(s.URL()+"/foo", formValues)
625                                         Ω(err).ShouldNot(HaveOccurred())
626                                 })
627
628                                 It("fail on missing values", func() {
629                                         formValues.Del("group")
630                                         failures := InterceptGomegaFailures(func() {
631                                                 resp, err = http.PostForm(s.URL()+"/foo", formValues)
632                                         })
633                                         Ω(failures).Should(HaveLen(1))
634                                 })
635
636                                 It("fail on incorrect values", func() {
637                                         formValues.Set("group", "wheel")
638                                         failures := InterceptGomegaFailures(func() {
639                                                 resp, err = http.PostForm(s.URL()+"/foo", formValues)
640                                         })
641                                         Ω(failures).Should(HaveLen(1))
642                                 })
643                         })
644                 })
645
646                 Describe("VerifyFormKV", func() {
647                         Context("when encoded in the URL", func() {
648                                 BeforeEach(func() {
649                                         s.AppendHandlers(CombineHandlers(
650                                                 VerifyRequest("GET", "/foo"),
651                                                 VerifyFormKV("users", "user1", "user2"),
652                                         ))
653                                 })
654
655                                 It("verifies the form value", func() {
656                                         resp, err = http.Get(s.URL() + "/foo?users=user1&users=user2")
657                                         Ω(err).ShouldNot(HaveOccurred())
658                                 })
659
660                                 It("verifies the form value", func() {
661                                         failures := InterceptGomegaFailures(func() {
662                                                 resp, err = http.Get(s.URL() + "/foo?users=user1")
663                                         })
664                                         Ω(failures).Should(HaveLen(1))
665                                 })
666                         })
667
668                         Context("when present in the body", func() {
669                                 BeforeEach(func() {
670                                         s.AppendHandlers(CombineHandlers(
671                                                 VerifyRequest("POST", "/foo"),
672                                                 VerifyFormKV("users", "user1", "user2"),
673                                         ))
674                                 })
675
676                                 It("verifies the form value", func() {
677                                         resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1", "user2"}})
678                                         Ω(err).ShouldNot(HaveOccurred())
679                                 })
680
681                                 It("verifies the form value", func() {
682                                         failures := InterceptGomegaFailures(func() {
683                                                 resp, err = http.PostForm(s.URL()+"/foo", url.Values{"users": []string{"user1"}})
684                                         })
685                                         Ω(failures).Should(HaveLen(1))
686                                 })
687                         })
688                 })
689
690                 Describe("VerifyProtoRepresenting", func() {
691                         var message *protobuf.SimpleMessage
692
693                         BeforeEach(func() {
694                                 message = new(protobuf.SimpleMessage)
695                                 message.Description = proto.String("A description")
696                                 message.Id = proto.Int32(0)
697
698                                 s.AppendHandlers(CombineHandlers(
699                                         VerifyRequest("POST", "/proto"),
700                                         VerifyProtoRepresenting(message),
701                                 ))
702                         })
703
704                         It("verifies the proto body and the content type", func() {
705                                 serialized, err := proto.Marshal(message)
706                                 Ω(err).ShouldNot(HaveOccurred())
707
708                                 resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized))
709                                 Ω(err).ShouldNot(HaveOccurred())
710                         })
711
712                         It("should verify the proto body and the content type", func() {
713                                 serialized, err := proto.Marshal(&protobuf.SimpleMessage{
714                                         Description: proto.String("A description"),
715                                         Id:          proto.Int32(0),
716                                         Metadata:    proto.String("some metadata"),
717                                 })
718                                 Ω(err).ShouldNot(HaveOccurred())
719
720                                 failures := InterceptGomegaFailures(func() {
721                                         http.Post(s.URL()+"/proto", "application/x-protobuf", bytes.NewReader(serialized))
722                                 })
723                                 Ω(failures).Should(HaveLen(1))
724                         })
725
726                         It("should verify the proto body and the content type", func() {
727                                 serialized, err := proto.Marshal(message)
728                                 Ω(err).ShouldNot(HaveOccurred())
729
730                                 failures := InterceptGomegaFailures(func() {
731                                         http.Post(s.URL()+"/proto", "application/not-x-protobuf", bytes.NewReader(serialized))
732                                 })
733                                 Ω(failures).Should(HaveLen(1))
734                         })
735                 })
736
737                 Describe("RespondWith", func() {
738                         Context("without headers", func() {
739                                 BeforeEach(func() {
740                                         s.AppendHandlers(CombineHandlers(
741                                                 VerifyRequest("POST", "/foo"),
742                                                 RespondWith(http.StatusCreated, "sweet"),
743                                         ), CombineHandlers(
744                                                 VerifyRequest("POST", "/foo"),
745                                                 RespondWith(http.StatusOK, []byte("sour")),
746                                         ))
747                                 })
748
749                                 It("should return the response", func() {
750                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
751                                         Ω(err).ShouldNot(HaveOccurred())
752
753                                         Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
754
755                                         body, err := ioutil.ReadAll(resp.Body)
756                                         Ω(err).ShouldNot(HaveOccurred())
757                                         Ω(body).Should(Equal([]byte("sweet")))
758
759                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
760                                         Ω(err).ShouldNot(HaveOccurred())
761
762                                         Ω(resp.StatusCode).Should(Equal(http.StatusOK))
763
764                                         body, err = ioutil.ReadAll(resp.Body)
765                                         Ω(err).ShouldNot(HaveOccurred())
766                                         Ω(body).Should(Equal([]byte("sour")))
767                                 })
768                         })
769
770                         Context("with headers", func() {
771                                 BeforeEach(func() {
772                                         s.AppendHandlers(CombineHandlers(
773                                                 VerifyRequest("POST", "/foo"),
774                                                 RespondWith(http.StatusCreated, "sweet", http.Header{"X-Custom-Header": []string{"my header"}}),
775                                         ))
776                                 })
777
778                                 It("should return the headers too", func() {
779                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
780                                         Ω(err).ShouldNot(HaveOccurred())
781
782                                         Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
783                                         Ω(ioutil.ReadAll(resp.Body)).Should(Equal([]byte("sweet")))
784                                         Ω(resp.Header.Get("X-Custom-Header")).Should(Equal("my header"))
785                                 })
786                         })
787                 })
788
789                 Describe("RespondWithPtr", func() {
790                         var code int
791                         var byteBody []byte
792                         var stringBody string
793                         BeforeEach(func() {
794                                 code = http.StatusOK
795                                 byteBody = []byte("sweet")
796                                 stringBody = "sour"
797
798                                 s.AppendHandlers(CombineHandlers(
799                                         VerifyRequest("POST", "/foo"),
800                                         RespondWithPtr(&code, &byteBody),
801                                 ), CombineHandlers(
802                                         VerifyRequest("POST", "/foo"),
803                                         RespondWithPtr(&code, &stringBody),
804                                 ))
805                         })
806
807                         It("should return the response", func() {
808                                 code = http.StatusCreated
809                                 byteBody = []byte("tasty")
810                                 stringBody = "treat"
811
812                                 resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
813                                 Ω(err).ShouldNot(HaveOccurred())
814
815                                 Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
816
817                                 body, err := ioutil.ReadAll(resp.Body)
818                                 Ω(err).ShouldNot(HaveOccurred())
819                                 Ω(body).Should(Equal([]byte("tasty")))
820
821                                 resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
822                                 Ω(err).ShouldNot(HaveOccurred())
823
824                                 Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
825
826                                 body, err = ioutil.ReadAll(resp.Body)
827                                 Ω(err).ShouldNot(HaveOccurred())
828                                 Ω(body).Should(Equal([]byte("treat")))
829                         })
830
831                         Context("when passed a nil body", func() {
832                                 BeforeEach(func() {
833                                         s.SetHandler(0, CombineHandlers(
834                                                 VerifyRequest("POST", "/foo"),
835                                                 RespondWithPtr(&code, nil),
836                                         ))
837                                 })
838
839                                 It("should return an empty body and not explode", func() {
840                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
841
842                                         Ω(err).ShouldNot(HaveOccurred())
843                                         Ω(resp.StatusCode).Should(Equal(http.StatusOK))
844                                         body, err := ioutil.ReadAll(resp.Body)
845                                         Ω(err).ShouldNot(HaveOccurred())
846                                         Ω(body).Should(BeEmpty())
847
848                                         Ω(s.ReceivedRequests()).Should(HaveLen(1))
849                                 })
850                         })
851                 })
852
853                 Describe("RespondWithJSON", func() {
854                         Context("when no optional headers are set", func() {
855                                 BeforeEach(func() {
856                                         s.AppendHandlers(CombineHandlers(
857                                                 VerifyRequest("POST", "/foo"),
858                                                 RespondWithJSONEncoded(http.StatusCreated, []int{1, 2, 3}),
859                                         ))
860                                 })
861
862                                 It("should return the response", func() {
863                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
864                                         Ω(err).ShouldNot(HaveOccurred())
865
866                                         Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
867
868                                         body, err := ioutil.ReadAll(resp.Body)
869                                         Ω(err).ShouldNot(HaveOccurred())
870                                         Ω(body).Should(MatchJSON("[1,2,3]"))
871                                 })
872
873                                 It("should set the Content-Type header to application/json", func() {
874                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
875                                         Ω(err).ShouldNot(HaveOccurred())
876
877                                         Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"}))
878                                 })
879                         })
880
881                         Context("when optional headers are set", func() {
882                                 var headers http.Header
883                                 BeforeEach(func() {
884                                         headers = http.Header{"Stuff": []string{"things"}}
885                                 })
886
887                                 JustBeforeEach(func() {
888                                         s.AppendHandlers(CombineHandlers(
889                                                 VerifyRequest("POST", "/foo"),
890                                                 RespondWithJSONEncoded(http.StatusCreated, []int{1, 2, 3}, headers),
891                                         ))
892                                 })
893
894                                 It("should preserve those headers", func() {
895                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
896                                         Ω(err).ShouldNot(HaveOccurred())
897
898                                         Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"}))
899                                 })
900
901                                 It("should set the Content-Type header to application/json", func() {
902                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
903                                         Ω(err).ShouldNot(HaveOccurred())
904
905                                         Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"}))
906                                 })
907
908                                 Context("when setting the Content-Type explicitly", func() {
909                                         BeforeEach(func() {
910                                                 headers["Content-Type"] = []string{"not-json"}
911                                         })
912
913                                         It("should use the Content-Type header that was explicitly set", func() {
914                                                 resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
915                                                 Ω(err).ShouldNot(HaveOccurred())
916
917                                                 Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"}))
918                                         })
919                                 })
920                         })
921                 })
922
923                 Describe("RespondWithJSONPtr", func() {
924                         type testObject struct {
925                                 Key   string
926                                 Value string
927                         }
928
929                         var code int
930                         var object testObject
931
932                         Context("when no optional headers are set", func() {
933                                 BeforeEach(func() {
934                                         code = http.StatusOK
935                                         object = testObject{}
936                                         s.AppendHandlers(CombineHandlers(
937                                                 VerifyRequest("POST", "/foo"),
938                                                 RespondWithJSONEncodedPtr(&code, &object),
939                                         ))
940                                 })
941
942                                 It("should return the response", func() {
943                                         code = http.StatusCreated
944                                         object = testObject{
945                                                 Key:   "Jim",
946                                                 Value: "Codes",
947                                         }
948                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
949                                         Ω(err).ShouldNot(HaveOccurred())
950
951                                         Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
952
953                                         body, err := ioutil.ReadAll(resp.Body)
954                                         Ω(err).ShouldNot(HaveOccurred())
955                                         Ω(body).Should(MatchJSON(`{"Key": "Jim", "Value": "Codes"}`))
956                                 })
957
958                                 It("should set the Content-Type header to application/json", func() {
959                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
960                                         Ω(err).ShouldNot(HaveOccurred())
961
962                                         Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"}))
963                                 })
964                         })
965
966                         Context("when optional headers are set", func() {
967                                 var headers http.Header
968                                 BeforeEach(func() {
969                                         headers = http.Header{"Stuff": []string{"things"}}
970                                 })
971
972                                 JustBeforeEach(func() {
973                                         code = http.StatusOK
974                                         object = testObject{}
975                                         s.AppendHandlers(CombineHandlers(
976                                                 VerifyRequest("POST", "/foo"),
977                                                 RespondWithJSONEncodedPtr(&code, &object, headers),
978                                         ))
979                                 })
980
981                                 It("should preserve those headers", func() {
982                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
983                                         Ω(err).ShouldNot(HaveOccurred())
984
985                                         Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"}))
986                                 })
987
988                                 It("should set the Content-Type header to application/json", func() {
989                                         resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
990                                         Ω(err).ShouldNot(HaveOccurred())
991
992                                         Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/json"}))
993                                 })
994
995                                 Context("when setting the Content-Type explicitly", func() {
996                                         BeforeEach(func() {
997                                                 headers["Content-Type"] = []string{"not-json"}
998                                         })
999
1000                                         It("should use the Content-Type header that was explicitly set", func() {
1001                                                 resp, err = http.Post(s.URL()+"/foo", "application/json", nil)
1002                                                 Ω(err).ShouldNot(HaveOccurred())
1003
1004                                                 Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-json"}))
1005                                         })
1006                                 })
1007                         })
1008                 })
1009
1010                 Describe("RespondWithProto", func() {
1011                         var message *protobuf.SimpleMessage
1012
1013                         BeforeEach(func() {
1014                                 message = new(protobuf.SimpleMessage)
1015                                 message.Description = proto.String("A description")
1016                                 message.Id = proto.Int32(99)
1017                         })
1018
1019                         Context("when no optional headers are set", func() {
1020                                 BeforeEach(func() {
1021                                         s.AppendHandlers(CombineHandlers(
1022                                                 VerifyRequest("POST", "/proto"),
1023                                                 RespondWithProto(http.StatusCreated, message),
1024                                         ))
1025                                 })
1026
1027                                 It("should return the response", func() {
1028                                         resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
1029                                         Ω(err).ShouldNot(HaveOccurred())
1030
1031                                         Ω(resp.StatusCode).Should(Equal(http.StatusCreated))
1032
1033                                         var received protobuf.SimpleMessage
1034                                         body, err := ioutil.ReadAll(resp.Body)
1035                                         err = proto.Unmarshal(body, &received)
1036                                         Ω(err).ShouldNot(HaveOccurred())
1037                                 })
1038
1039                                 It("should set the Content-Type header to application/x-protobuf", func() {
1040                                         resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
1041                                         Ω(err).ShouldNot(HaveOccurred())
1042
1043                                         Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"}))
1044                                 })
1045                         })
1046
1047                         Context("when optional headers are set", func() {
1048                                 var headers http.Header
1049                                 BeforeEach(func() {
1050                                         headers = http.Header{"Stuff": []string{"things"}}
1051                                 })
1052
1053                                 JustBeforeEach(func() {
1054                                         s.AppendHandlers(CombineHandlers(
1055                                                 VerifyRequest("POST", "/proto"),
1056                                                 RespondWithProto(http.StatusCreated, message, headers),
1057                                         ))
1058                                 })
1059
1060                                 It("should preserve those headers", func() {
1061                                         resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
1062                                         Ω(err).ShouldNot(HaveOccurred())
1063
1064                                         Ω(resp.Header["Stuff"]).Should(Equal([]string{"things"}))
1065                                 })
1066
1067                                 It("should set the Content-Type header to application/x-protobuf", func() {
1068                                         resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
1069                                         Ω(err).ShouldNot(HaveOccurred())
1070
1071                                         Ω(resp.Header["Content-Type"]).Should(Equal([]string{"application/x-protobuf"}))
1072                                 })
1073
1074                                 Context("when setting the Content-Type explicitly", func() {
1075                                         BeforeEach(func() {
1076                                                 headers["Content-Type"] = []string{"not-x-protobuf"}
1077                                         })
1078
1079                                         It("should use the Content-Type header that was explicitly set", func() {
1080                                                 resp, err = http.Post(s.URL()+"/proto", "application/x-protobuf", nil)
1081                                                 Ω(err).ShouldNot(HaveOccurred())
1082
1083                                                 Ω(resp.Header["Content-Type"]).Should(Equal([]string{"not-x-protobuf"}))
1084                                         })
1085                                 })
1086                         })
1087                 })
1088         })
1089 })