OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / go-kit / kit / transport / http / server_test.go
1 package http_test
2
3 import (
4         "context"
5         "errors"
6         "io/ioutil"
7         "net/http"
8         "net/http/httptest"
9         "strings"
10         "testing"
11         "time"
12
13         "github.com/go-kit/kit/endpoint"
14         httptransport "github.com/go-kit/kit/transport/http"
15 )
16
17 func TestServerBadDecode(t *testing.T) {
18         handler := httptransport.NewServer(
19                 func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil },
20                 func(context.Context, *http.Request) (interface{}, error) { return struct{}{}, errors.New("dang") },
21                 func(context.Context, http.ResponseWriter, interface{}) error { return nil },
22         )
23         server := httptest.NewServer(handler)
24         defer server.Close()
25         resp, _ := http.Get(server.URL)
26         if want, have := http.StatusInternalServerError, resp.StatusCode; want != have {
27                 t.Errorf("want %d, have %d", want, have)
28         }
29 }
30
31 func TestServerBadEndpoint(t *testing.T) {
32         handler := httptransport.NewServer(
33                 func(context.Context, interface{}) (interface{}, error) { return struct{}{}, errors.New("dang") },
34                 func(context.Context, *http.Request) (interface{}, error) { return struct{}{}, nil },
35                 func(context.Context, http.ResponseWriter, interface{}) error { return nil },
36         )
37         server := httptest.NewServer(handler)
38         defer server.Close()
39         resp, _ := http.Get(server.URL)
40         if want, have := http.StatusInternalServerError, resp.StatusCode; want != have {
41                 t.Errorf("want %d, have %d", want, have)
42         }
43 }
44
45 func TestServerBadEncode(t *testing.T) {
46         handler := httptransport.NewServer(
47                 func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil },
48                 func(context.Context, *http.Request) (interface{}, error) { return struct{}{}, nil },
49                 func(context.Context, http.ResponseWriter, interface{}) error { return errors.New("dang") },
50         )
51         server := httptest.NewServer(handler)
52         defer server.Close()
53         resp, _ := http.Get(server.URL)
54         if want, have := http.StatusInternalServerError, resp.StatusCode; want != have {
55                 t.Errorf("want %d, have %d", want, have)
56         }
57 }
58
59 func TestServerErrorEncoder(t *testing.T) {
60         errTeapot := errors.New("teapot")
61         code := func(err error) int {
62                 if err == errTeapot {
63                         return http.StatusTeapot
64                 }
65                 return http.StatusInternalServerError
66         }
67         handler := httptransport.NewServer(
68                 func(context.Context, interface{}) (interface{}, error) { return struct{}{}, errTeapot },
69                 func(context.Context, *http.Request) (interface{}, error) { return struct{}{}, nil },
70                 func(context.Context, http.ResponseWriter, interface{}) error { return nil },
71                 httptransport.ServerErrorEncoder(func(_ context.Context, err error, w http.ResponseWriter) { w.WriteHeader(code(err)) }),
72         )
73         server := httptest.NewServer(handler)
74         defer server.Close()
75         resp, _ := http.Get(server.URL)
76         if want, have := http.StatusTeapot, resp.StatusCode; want != have {
77                 t.Errorf("want %d, have %d", want, have)
78         }
79 }
80
81 func TestServerHappyPath(t *testing.T) {
82         step, response := testServer(t)
83         step()
84         resp := <-response
85         defer resp.Body.Close()
86         buf, _ := ioutil.ReadAll(resp.Body)
87         if want, have := http.StatusOK, resp.StatusCode; want != have {
88                 t.Errorf("want %d, have %d (%s)", want, have, buf)
89         }
90 }
91
92 func TestMultipleServerBefore(t *testing.T) {
93         var (
94                 headerKey    = "X-Henlo-Lizer"
95                 headerVal    = "Helllo you stinky lizard"
96                 statusCode   = http.StatusTeapot
97                 responseBody = "go eat a fly ugly\n"
98                 done         = make(chan struct{})
99         )
100         handler := httptransport.NewServer(
101                 endpoint.Nop,
102                 func(context.Context, *http.Request) (interface{}, error) {
103                         return struct{}{}, nil
104                 },
105                 func(_ context.Context, w http.ResponseWriter, _ interface{}) error {
106                         w.Header().Set(headerKey, headerVal)
107                         w.WriteHeader(statusCode)
108                         w.Write([]byte(responseBody))
109                         return nil
110                 },
111                 httptransport.ServerBefore(func(ctx context.Context, r *http.Request) context.Context {
112                         ctx = context.WithValue(ctx, "one", 1)
113
114                         return ctx
115                 }),
116                 httptransport.ServerBefore(func(ctx context.Context, r *http.Request) context.Context {
117                         if _, ok := ctx.Value("one").(int); !ok {
118                                 t.Error("Value was not set properly when multiple ServerBefores are used")
119                         }
120
121                         close(done)
122                         return ctx
123                 }),
124         )
125
126         server := httptest.NewServer(handler)
127         defer server.Close()
128         go http.Get(server.URL)
129
130         select {
131         case <-done:
132         case <-time.After(time.Second):
133                 t.Fatal("timeout waiting for finalizer")
134         }
135 }
136
137 func TestMultipleServerAfter(t *testing.T) {
138         var (
139                 headerKey    = "X-Henlo-Lizer"
140                 headerVal    = "Helllo you stinky lizard"
141                 statusCode   = http.StatusTeapot
142                 responseBody = "go eat a fly ugly\n"
143                 done         = make(chan struct{})
144         )
145         handler := httptransport.NewServer(
146                 endpoint.Nop,
147                 func(context.Context, *http.Request) (interface{}, error) {
148                         return struct{}{}, nil
149                 },
150                 func(_ context.Context, w http.ResponseWriter, _ interface{}) error {
151                         w.Header().Set(headerKey, headerVal)
152                         w.WriteHeader(statusCode)
153                         w.Write([]byte(responseBody))
154                         return nil
155                 },
156                 httptransport.ServerAfter(func(ctx context.Context, w http.ResponseWriter) context.Context {
157                         ctx = context.WithValue(ctx, "one", 1)
158
159                         return ctx
160                 }),
161                 httptransport.ServerAfter(func(ctx context.Context, w http.ResponseWriter) context.Context {
162                         if _, ok := ctx.Value("one").(int); !ok {
163                                 t.Error("Value was not set properly when multiple ServerAfters are used")
164                         }
165
166                         close(done)
167                         return ctx
168                 }),
169         )
170
171         server := httptest.NewServer(handler)
172         defer server.Close()
173         go http.Get(server.URL)
174
175         select {
176         case <-done:
177         case <-time.After(time.Second):
178                 t.Fatal("timeout waiting for finalizer")
179         }
180 }
181
182 func TestServerFinalizer(t *testing.T) {
183         var (
184                 headerKey    = "X-Henlo-Lizer"
185                 headerVal    = "Helllo you stinky lizard"
186                 statusCode   = http.StatusTeapot
187                 responseBody = "go eat a fly ugly\n"
188                 done         = make(chan struct{})
189         )
190         handler := httptransport.NewServer(
191                 endpoint.Nop,
192                 func(context.Context, *http.Request) (interface{}, error) {
193                         return struct{}{}, nil
194                 },
195                 func(_ context.Context, w http.ResponseWriter, _ interface{}) error {
196                         w.Header().Set(headerKey, headerVal)
197                         w.WriteHeader(statusCode)
198                         w.Write([]byte(responseBody))
199                         return nil
200                 },
201                 httptransport.ServerFinalizer(func(ctx context.Context, code int, _ *http.Request) {
202                         if want, have := statusCode, code; want != have {
203                                 t.Errorf("StatusCode: want %d, have %d", want, have)
204                         }
205
206                         responseHeader := ctx.Value(httptransport.ContextKeyResponseHeaders).(http.Header)
207                         if want, have := headerVal, responseHeader.Get(headerKey); want != have {
208                                 t.Errorf("%s: want %q, have %q", headerKey, want, have)
209                         }
210
211                         responseSize := ctx.Value(httptransport.ContextKeyResponseSize).(int64)
212                         if want, have := int64(len(responseBody)), responseSize; want != have {
213                                 t.Errorf("response size: want %d, have %d", want, have)
214                         }
215
216                         close(done)
217                 }),
218         )
219
220         server := httptest.NewServer(handler)
221         defer server.Close()
222         go http.Get(server.URL)
223
224         select {
225         case <-done:
226         case <-time.After(time.Second):
227                 t.Fatal("timeout waiting for finalizer")
228         }
229 }
230
231 type enhancedResponse struct {
232         Foo string `json:"foo"`
233 }
234
235 func (e enhancedResponse) StatusCode() int      { return http.StatusPaymentRequired }
236 func (e enhancedResponse) Headers() http.Header { return http.Header{"X-Edward": []string{"Snowden"}} }
237
238 func TestEncodeJSONResponse(t *testing.T) {
239         handler := httptransport.NewServer(
240                 func(context.Context, interface{}) (interface{}, error) { return enhancedResponse{Foo: "bar"}, nil },
241                 func(context.Context, *http.Request) (interface{}, error) { return struct{}{}, nil },
242                 httptransport.EncodeJSONResponse,
243         )
244
245         server := httptest.NewServer(handler)
246         defer server.Close()
247
248         resp, err := http.Get(server.URL)
249         if err != nil {
250                 t.Fatal(err)
251         }
252         if want, have := http.StatusPaymentRequired, resp.StatusCode; want != have {
253                 t.Errorf("StatusCode: want %d, have %d", want, have)
254         }
255         if want, have := "Snowden", resp.Header.Get("X-Edward"); want != have {
256                 t.Errorf("X-Edward: want %q, have %q", want, have)
257         }
258         buf, _ := ioutil.ReadAll(resp.Body)
259         if want, have := `{"foo":"bar"}`, strings.TrimSpace(string(buf)); want != have {
260                 t.Errorf("Body: want %s, have %s", want, have)
261         }
262 }
263
264 type noContentResponse struct{}
265
266 func (e noContentResponse) StatusCode() int { return http.StatusNoContent }
267
268 func TestEncodeNoContent(t *testing.T) {
269         handler := httptransport.NewServer(
270                 func(context.Context, interface{}) (interface{}, error) { return noContentResponse{}, nil },
271                 func(context.Context, *http.Request) (interface{}, error) { return struct{}{}, nil },
272                 httptransport.EncodeJSONResponse,
273         )
274
275         server := httptest.NewServer(handler)
276         defer server.Close()
277
278         resp, err := http.Get(server.URL)
279         if err != nil {
280                 t.Fatal(err)
281         }
282         if want, have := http.StatusNoContent, resp.StatusCode; want != have {
283                 t.Errorf("StatusCode: want %d, have %d", want, have)
284         }
285         buf, _ := ioutil.ReadAll(resp.Body)
286         if want, have := 0, len(buf); want != have {
287                 t.Errorf("Body: want no content, have %d bytes", have)
288         }
289 }
290
291 type enhancedError struct{}
292
293 func (e enhancedError) Error() string                { return "enhanced error" }
294 func (e enhancedError) StatusCode() int              { return http.StatusTeapot }
295 func (e enhancedError) MarshalJSON() ([]byte, error) { return []byte(`{"err":"enhanced"}`), nil }
296 func (e enhancedError) Headers() http.Header         { return http.Header{"X-Enhanced": []string{"1"}} }
297
298 func TestEnhancedError(t *testing.T) {
299         handler := httptransport.NewServer(
300                 func(context.Context, interface{}) (interface{}, error) { return nil, enhancedError{} },
301                 func(context.Context, *http.Request) (interface{}, error) { return struct{}{}, nil },
302                 func(_ context.Context, w http.ResponseWriter, _ interface{}) error { return nil },
303         )
304
305         server := httptest.NewServer(handler)
306         defer server.Close()
307
308         resp, err := http.Get(server.URL)
309         if err != nil {
310                 t.Fatal(err)
311         }
312         defer resp.Body.Close()
313         if want, have := http.StatusTeapot, resp.StatusCode; want != have {
314                 t.Errorf("StatusCode: want %d, have %d", want, have)
315         }
316         if want, have := "1", resp.Header.Get("X-Enhanced"); want != have {
317                 t.Errorf("X-Enhanced: want %q, have %q", want, have)
318         }
319         buf, _ := ioutil.ReadAll(resp.Body)
320         if want, have := `{"err":"enhanced"}`, strings.TrimSpace(string(buf)); want != have {
321                 t.Errorf("Body: want %s, have %s", want, have)
322         }
323 }
324
325 func testServer(t *testing.T) (step func(), resp <-chan *http.Response) {
326         var (
327                 stepch   = make(chan bool)
328                 endpoint = func(context.Context, interface{}) (interface{}, error) { <-stepch; return struct{}{}, nil }
329                 response = make(chan *http.Response)
330                 handler  = httptransport.NewServer(
331                         endpoint,
332                         func(context.Context, *http.Request) (interface{}, error) { return struct{}{}, nil },
333                         func(context.Context, http.ResponseWriter, interface{}) error { return nil },
334                         httptransport.ServerBefore(func(ctx context.Context, r *http.Request) context.Context { return ctx }),
335                         httptransport.ServerAfter(func(ctx context.Context, w http.ResponseWriter) context.Context { return ctx }),
336                 )
337         )
338         go func() {
339                 server := httptest.NewServer(handler)
340                 defer server.Close()
341                 resp, err := http.Get(server.URL)
342                 if err != nil {
343                         t.Error(err)
344                         return
345                 }
346                 response <- resp
347         }()
348         return func() { stepch <- true }, response
349 }