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