...

Source file src/github.com/onsi/gomega/ghttp/test_server_test.go

Documentation: github.com/onsi/gomega/ghttp

     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  })
  1194  

View as plain text