github.com/onsi/gomega@v1.32.0/ghttp/test_server_test.go (about) 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) //just to be clear that 500s aren't coming from unhandled requests 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 // Expect(true).Should(BeFalse()) <-- would be nice to do it this way, but the test just can't be written this way 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 })