15107: Merge branch 'master' into 15107-rails-bad-redirect
[arvados.git] / sdk / go / health / handler_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package health
6
7 import (
8         "encoding/json"
9         "errors"
10         "net/http"
11         "net/http/httptest"
12         "net/url"
13         "testing"
14
15         check "gopkg.in/check.v1"
16 )
17
18 // Gocheck boilerplate
19 var _ = check.Suite(&Suite{})
20
21 func Test(t *testing.T) {
22         check.TestingT(t)
23 }
24
25 type Suite struct{}
26
27 const (
28         goodToken = "supersecret"
29         badToken  = "pwn"
30 )
31
32 func (s *Suite) TestPassFailRefuse(c *check.C) {
33         h := &Handler{
34                 Token:  goodToken,
35                 Prefix: "/_health/",
36                 Routes: Routes{
37                         "success": func() error { return nil },
38                         "miracle": func() error { return errors.New("unimplemented") },
39                 },
40         }
41
42         resp := httptest.NewRecorder()
43         h.ServeHTTP(resp, s.request("/_health/ping", goodToken))
44         s.checkHealthy(c, resp)
45
46         resp = httptest.NewRecorder()
47         h.ServeHTTP(resp, s.request("/_health/success", goodToken))
48         s.checkHealthy(c, resp)
49
50         resp = httptest.NewRecorder()
51         h.ServeHTTP(resp, s.request("/_health/miracle", goodToken))
52         s.checkUnhealthy(c, resp)
53
54         resp = httptest.NewRecorder()
55         h.ServeHTTP(resp, s.request("/_health/miracle", badToken))
56         c.Check(resp.Code, check.Equals, http.StatusForbidden)
57
58         resp = httptest.NewRecorder()
59         h.ServeHTTP(resp, s.request("/_health/miracle", ""))
60         c.Check(resp.Code, check.Equals, http.StatusUnauthorized)
61
62         resp = httptest.NewRecorder()
63         h.ServeHTTP(resp, s.request("/_health/theperthcountyconspiracy", ""))
64         c.Check(resp.Code, check.Equals, http.StatusNotFound)
65
66         resp = httptest.NewRecorder()
67         h.ServeHTTP(resp, s.request("/x/miracle", ""))
68         c.Check(resp.Code, check.Equals, http.StatusNotFound)
69
70         resp = httptest.NewRecorder()
71         h.ServeHTTP(resp, s.request("/miracle", ""))
72         c.Check(resp.Code, check.Equals, http.StatusNotFound)
73 }
74
75 func (s *Suite) TestPingOverride(c *check.C) {
76         var ok bool
77         h := &Handler{
78                 Token: goodToken,
79                 Routes: Routes{
80                         "ping": func() error {
81                                 ok = !ok
82                                 if ok {
83                                         return nil
84                                 } else {
85                                         return errors.New("good error")
86                                 }
87                         },
88                 },
89         }
90         resp := httptest.NewRecorder()
91         h.ServeHTTP(resp, s.request("/ping", goodToken))
92         s.checkHealthy(c, resp)
93
94         resp = httptest.NewRecorder()
95         h.ServeHTTP(resp, s.request("/ping", goodToken))
96         s.checkUnhealthy(c, resp)
97 }
98
99 func (s *Suite) TestZeroValueIsDisabled(c *check.C) {
100         resp := httptest.NewRecorder()
101         (&Handler{}).ServeHTTP(resp, s.request("/ping", goodToken))
102         c.Check(resp.Code, check.Equals, http.StatusNotFound)
103
104         resp = httptest.NewRecorder()
105         (&Handler{}).ServeHTTP(resp, s.request("/ping", ""))
106         c.Check(resp.Code, check.Equals, http.StatusNotFound)
107 }
108
109 func (s *Suite) request(path, token string) *http.Request {
110         u, _ := url.Parse("http://foo.local" + path)
111         req := &http.Request{
112                 Method:     "GET",
113                 Host:       u.Host,
114                 URL:        u,
115                 RequestURI: u.RequestURI(),
116         }
117         if token != "" {
118                 req.Header = http.Header{
119                         "Authorization": {"Bearer " + token},
120                 }
121         }
122         return req
123 }
124
125 func (s *Suite) checkHealthy(c *check.C, resp *httptest.ResponseRecorder) {
126         c.Check(resp.Code, check.Equals, http.StatusOK)
127         c.Check(resp.Body.String(), check.Equals, `{"health":"OK"}`+"\n")
128 }
129
130 func (s *Suite) checkUnhealthy(c *check.C, resp *httptest.ResponseRecorder) {
131         c.Check(resp.Code, check.Equals, http.StatusOK)
132         var result map[string]interface{}
133         err := json.Unmarshal(resp.Body.Bytes(), &result)
134         c.Assert(err, check.IsNil)
135         c.Check(result["health"], check.Equals, "ERROR")
136         c.Check(result["error"].(string), check.Not(check.Equals), "")
137 }