12 "git.curoverse.com/arvados.git/sdk/go/arvados"
13 "git.curoverse.com/arvados.git/sdk/go/arvadostest"
17 type AggregatorSuite struct {
20 resp *httptest.ResponseRecorder
23 // Gocheck boilerplate
24 var _ = check.Suite(&AggregatorSuite{})
26 func (s *AggregatorSuite) TestInterface(c *check.C) {
27 var _ http.Handler = &Aggregator{}
30 func (s *AggregatorSuite) SetUpTest(c *check.C) {
31 s.handler = &Aggregator{Config: &arvados.Config{
32 Clusters: map[string]arvados.Cluster{
34 ManagementToken: arvadostest.ManagementToken,
35 SystemNodes: map[string]arvados.SystemNode{},
39 s.req = httptest.NewRequest("GET", "/_health/all", nil)
40 s.req.Header.Set("Authorization", "Bearer "+arvadostest.ManagementToken)
41 s.resp = httptest.NewRecorder()
44 func (s *AggregatorSuite) TestNoAuth(c *check.C) {
45 s.req.Header.Del("Authorization")
46 s.handler.ServeHTTP(s.resp, s.req)
48 c.Check(s.resp.Code, check.Equals, http.StatusUnauthorized)
51 func (s *AggregatorSuite) TestBadAuth(c *check.C) {
52 s.req.Header.Set("Authorization", "xyzzy")
53 s.handler.ServeHTTP(s.resp, s.req)
55 c.Check(s.resp.Code, check.Equals, http.StatusUnauthorized)
58 func (s *AggregatorSuite) TestEmptyConfig(c *check.C) {
59 s.handler.ServeHTTP(s.resp, s.req)
63 func (s *AggregatorSuite) stubServer(handler http.Handler) (*httptest.Server, string) {
64 srv := httptest.NewServer(handler)
66 if parts := strings.Split(srv.URL, ":"); len(parts) < 3 {
69 port = parts[len(parts)-1]
71 return srv, ":" + port
74 type unhealthyHandler struct{}
76 func (*unhealthyHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
77 if req.URL.Path == "/_health/ping" {
78 resp.Write([]byte(`{"health":"ERROR","error":"the bends"}`))
80 http.Error(resp, "not found", http.StatusNotFound)
84 func (s *AggregatorSuite) TestUnhealthy(c *check.C) {
85 srv, listen := s.stubServer(&unhealthyHandler{})
87 s.handler.Config.Clusters["zzzzz"].SystemNodes["localhost"] = arvados.SystemNode{
88 Keepstore: arvados.Keepstore{Listen: listen},
90 s.handler.ServeHTTP(s.resp, s.req)
94 type healthyHandler struct{}
96 func (*healthyHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
97 if req.URL.Path == "/_health/ping" {
98 resp.Write([]byte(`{"health":"OK"}`))
100 http.Error(resp, "not found", http.StatusNotFound)
104 func (s *AggregatorSuite) TestHealthy(c *check.C) {
105 srv, listen := s.stubServer(&healthyHandler{})
107 _, port, _ := net.SplitHostPort(listen)
108 s.handler.Config.Clusters["zzzzz"].SystemNodes["localhost"] = arvados.SystemNode{
109 Keepstore: arvados.Keepstore{Listen: listen},
111 s.handler.ServeHTTP(s.resp, s.req)
113 ep := resp.Checks[fmt.Sprintf("keepstore+http://localhost:%d/_health/ping", port)]
114 c.Check(ep.Health, check.Equals, "OK")
115 c.Check(ep.Status, check.Equals, 200)
118 func (s *AggregatorSuite) TestHealthyAndUnhealthy(c *check.C) {
119 srvH, listenH := s.stubServer(&healthyHandler{})
121 _, portH, _ := net.SplitHostPort(listenH)
122 srvU, listenU := s.stubServer(&unhealthyHandler{})
124 _, portU, _ := net.SplitHostPort(listenU)
125 s.handler.Config.Clusters["zzzzz"].SystemNodes["localhost"] = arvados.SystemNode{
126 Keepstore: arvados.Keepstore{Listen: listenH},
128 s.handler.Config.Clusters["zzzzz"].SystemNodes["127.0.0.1"] = arvados.SystemNode{
129 Keepstore: arvados.Keepstore{Listen: listenU},
131 s.handler.ServeHTTP(s.resp, s.req)
132 resp := s.checkUnhealthy(c)
133 ep := resp.Checks[fmt.Sprintf("keepstore+http://localhost:%d/_health/ping", portH)]
134 c.Check(ep.Health, check.Equals, "OK")
135 c.Check(ep.Status, check.Equals, 200)
136 ep = resp.Checks[fmt.Sprintf("keepstore+http://127.0.0.1:%d/_health/ping", portU)]
137 c.Check(ep.Health, check.Equals, "ERROR")
138 c.Check(ep.Status, check.Equals, 200)
141 func (s *AggregatorSuite) checkError(c *check.C) {
142 c.Check(s.resp.Code, check.Not(check.Equals), http.StatusOK)
143 var resp ClusterHealthResponse
144 err := json.NewDecoder(s.resp.Body).Decode(&resp)
145 c.Check(err, check.IsNil)
146 c.Check(resp.Health, check.Not(check.Equals), "OK")
149 func (s *AggregatorSuite) checkUnhealthy(c *check.C) ClusterHealthResponse {
150 return s.checkResult(c, "ERROR")
153 func (s *AggregatorSuite) checkOK(c *check.C) ClusterHealthResponse {
154 return s.checkResult(c, "OK")
157 func (s *AggregatorSuite) checkResult(c *check.C, health string) ClusterHealthResponse {
158 c.Check(s.resp.Code, check.Equals, http.StatusOK)
159 var resp ClusterHealthResponse
160 err := json.NewDecoder(s.resp.Body).Decode(&resp)
161 c.Check(err, check.IsNil)
162 c.Check(resp.Health, check.Equals, health)
166 type slowHandler struct{}
168 func (*slowHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
169 if req.URL.Path == "/_health/ping" {
170 time.Sleep(3 * time.Second)
171 resp.Write([]byte(`{"health":"OK"}`))
173 http.Error(resp, "not found", http.StatusNotFound)
177 func (s *AggregatorSuite) TestPingTimeout(c *check.C) {
178 s.handler.timeout = arvados.Duration(100 * time.Millisecond)
179 srv, listen := s.stubServer(&slowHandler{})
181 s.handler.Config.Clusters["zzzzz"].SystemNodes["localhost"] = arvados.SystemNode{
182 Keepstore: arvados.Keepstore{Listen: listen},
184 s.handler.ServeHTTP(s.resp, s.req)
185 resp := s.checkUnhealthy(c)
186 ep := resp.Checks["localhost/keepstore/_health/ping"]
187 c.Check(ep.Health, check.Equals, "ERROR")
188 c.Check(ep.Status, check.Equals, 0)
189 rt, err := ep.ResponseTime.Float64()
190 c.Check(err, check.IsNil)
191 c.Check(rt > 0.005, check.Equals, true)