13 "github.com/go-kit/kit/endpoint"
14 httptransport "github.com/go-kit/kit/transport/http"
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 },
23 server := httptest.NewServer(handler)
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)
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 },
37 server := httptest.NewServer(handler)
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)
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") },
51 server := httptest.NewServer(handler)
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)
59 func TestServerErrorEncoder(t *testing.T) {
60 errTeapot := errors.New("teapot")
61 code := func(err error) int {
63 return http.StatusTeapot
65 return http.StatusInternalServerError
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)) }),
73 server := httptest.NewServer(handler)
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)
81 func TestServerHappyPath(t *testing.T) {
82 step, response := testServer(t)
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)
92 func TestMultipleServerBefore(t *testing.T) {
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{})
100 handler := httptransport.NewServer(
102 func(context.Context, *http.Request) (interface{}, error) {
103 return struct{}{}, nil
105 func(_ context.Context, w http.ResponseWriter, _ interface{}) error {
106 w.Header().Set(headerKey, headerVal)
107 w.WriteHeader(statusCode)
108 w.Write([]byte(responseBody))
111 httptransport.ServerBefore(func(ctx context.Context, r *http.Request) context.Context {
112 ctx = context.WithValue(ctx, "one", 1)
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")
126 server := httptest.NewServer(handler)
128 go http.Get(server.URL)
132 case <-time.After(time.Second):
133 t.Fatal("timeout waiting for finalizer")
137 func TestMultipleServerAfter(t *testing.T) {
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{})
145 handler := httptransport.NewServer(
147 func(context.Context, *http.Request) (interface{}, error) {
148 return struct{}{}, nil
150 func(_ context.Context, w http.ResponseWriter, _ interface{}) error {
151 w.Header().Set(headerKey, headerVal)
152 w.WriteHeader(statusCode)
153 w.Write([]byte(responseBody))
156 httptransport.ServerAfter(func(ctx context.Context, w http.ResponseWriter) context.Context {
157 ctx = context.WithValue(ctx, "one", 1)
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")
171 server := httptest.NewServer(handler)
173 go http.Get(server.URL)
177 case <-time.After(time.Second):
178 t.Fatal("timeout waiting for finalizer")
182 func TestServerFinalizer(t *testing.T) {
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{})
190 handler := httptransport.NewServer(
192 func(context.Context, *http.Request) (interface{}, error) {
193 return struct{}{}, nil
195 func(_ context.Context, w http.ResponseWriter, _ interface{}) error {
196 w.Header().Set(headerKey, headerVal)
197 w.WriteHeader(statusCode)
198 w.Write([]byte(responseBody))
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)
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)
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)
220 server := httptest.NewServer(handler)
222 go http.Get(server.URL)
226 case <-time.After(time.Second):
227 t.Fatal("timeout waiting for finalizer")
231 type enhancedResponse struct {
232 Foo string `json:"foo"`
235 func (e enhancedResponse) StatusCode() int { return http.StatusPaymentRequired }
236 func (e enhancedResponse) Headers() http.Header { return http.Header{"X-Edward": []string{"Snowden"}} }
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,
245 server := httptest.NewServer(handler)
248 resp, err := http.Get(server.URL)
252 if want, have := http.StatusPaymentRequired, resp.StatusCode; want != have {
253 t.Errorf("StatusCode: want %d, have %d", want, have)
255 if want, have := "Snowden", resp.Header.Get("X-Edward"); want != have {
256 t.Errorf("X-Edward: want %q, have %q", want, have)
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)
264 type noContentResponse struct{}
266 func (e noContentResponse) StatusCode() int { return http.StatusNoContent }
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,
275 server := httptest.NewServer(handler)
278 resp, err := http.Get(server.URL)
282 if want, have := http.StatusNoContent, resp.StatusCode; want != have {
283 t.Errorf("StatusCode: want %d, have %d", want, have)
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)
291 type enhancedError struct{}
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"}} }
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 },
305 server := httptest.NewServer(handler)
308 resp, err := http.Get(server.URL)
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)
316 if want, have := "1", resp.Header.Get("X-Enhanced"); want != have {
317 t.Errorf("X-Enhanced: want %q, have %q", want, have)
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)
325 func testServer(t *testing.T) (step func(), resp <-chan *http.Response) {
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(
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 }),
339 server := httptest.NewServer(handler)
341 resp, err := http.Get(server.URL)
348 return func() { stepch <- true }, response