Merge branch '21606-keep-web-output-buffer'
[arvados.git] / sdk / go / httpserver / inspect_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: Apache-2.0
4
5 package httpserver
6
7 import (
8         "context"
9         "encoding/json"
10         "net/http"
11         "net/http/httptest"
12         "strings"
13         "time"
14
15         "github.com/prometheus/client_golang/prometheus"
16         "github.com/prometheus/client_golang/prometheus/promhttp"
17         check "gopkg.in/check.v1"
18 )
19
20 func (s *Suite) TestInspect(c *check.C) {
21         reg := prometheus.NewRegistry()
22         h := newTestHandler()
23         mh := Inspect(reg, "abcd", h)
24         handlerReturned := make(chan struct{})
25         reqctx, reqcancel := context.WithCancel(context.Background())
26         longreq := httptest.NewRequest("GET", "/test", nil).WithContext(reqctx)
27         go func() {
28                 mh.ServeHTTP(httptest.NewRecorder(), longreq)
29                 close(handlerReturned)
30         }()
31         <-h.inHandler
32
33         resp := httptest.NewRecorder()
34         req := httptest.NewRequest("GET", "/_inspect/requests", nil)
35         mh.ServeHTTP(resp, req)
36         c.Check(resp.Code, check.Equals, http.StatusUnauthorized)
37         c.Check(resp.Body.String(), check.Equals, `{"errors":["unauthorized"]}`+"\n")
38
39         resp = httptest.NewRecorder()
40         req.Header.Set("Authorization", "Bearer abcde")
41         mh.ServeHTTP(resp, req)
42         c.Check(resp.Code, check.Equals, http.StatusUnauthorized)
43
44         resp = httptest.NewRecorder()
45         req.Header.Set("Authorization", "Bearer abcd")
46         mh.ServeHTTP(resp, req)
47         c.Check(resp.Code, check.Equals, http.StatusOK)
48         reqs := []map[string]interface{}{}
49         err := json.NewDecoder(resp.Body).Decode(&reqs)
50         c.Check(err, check.IsNil)
51         c.Check(reqs, check.HasLen, 1)
52         c.Check(reqs[0]["URL"], check.Equals, "/test")
53
54         // Request is active, so we should see active request age > 0
55         resp = httptest.NewRecorder()
56         mreq := httptest.NewRequest("GET", "/metrics", nil)
57         promhttp.HandlerFor(reg, promhttp.HandlerOpts{}).ServeHTTP(resp, mreq)
58         c.Check(resp.Code, check.Equals, http.StatusOK)
59         c.Check(resp.Body.String(), check.Matches, `(?ms).*\narvados_max_active_request_age_seconds [0\.]*[1-9][-\d\.e]*\n.*`)
60         c.Check(resp.Body.String(), check.Matches, `(?ms).*\narvados_max_abandoned_request_age_seconds 0\n.*`)
61
62         reqcancel()
63
64         // Request context is canceled but handler hasn't returned, so
65         // we should see max abandoned request age > 0 and active ==
66         // 0. We might need to wait a short time for the cancel to
67         // propagate.
68         for deadline := time.Now().Add(time.Second); time.Now().Before(deadline); time.Sleep(time.Second / 100) {
69                 resp = httptest.NewRecorder()
70                 promhttp.HandlerFor(reg, promhttp.HandlerOpts{}).ServeHTTP(resp, mreq)
71                 c.Assert(resp.Code, check.Equals, http.StatusOK)
72                 if strings.Contains(resp.Body.String(), "\narvados_max_active_request_age_seconds 0\n") {
73                         break
74                 }
75         }
76         c.Check(resp.Body.String(), check.Matches, `(?ms).*\narvados_max_active_request_age_seconds 0\n.*`)
77         c.Check(resp.Body.String(), check.Matches, `(?ms).*\narvados_max_abandoned_request_age_seconds [0\.]*[1-9][-\d\.e]*\n.*`)
78
79         h.okToProceed <- struct{}{}
80         <-handlerReturned
81
82         // Handler has returned, so we should see max abandoned
83         // request age == max active request age == 0
84         resp = httptest.NewRecorder()
85         promhttp.HandlerFor(reg, promhttp.HandlerOpts{}).ServeHTTP(resp, mreq)
86         c.Check(resp.Code, check.Equals, http.StatusOK)
87         c.Check(resp.Body.String(), check.Matches, `(?ms).*\narvados_max_active_request_age_seconds 0\n.*`)
88         c.Check(resp.Body.String(), check.Matches, `(?ms).*\narvados_max_abandoned_request_age_seconds 0\n.*`)
89
90         // ...and no active requests at the /_monitor endpoint
91         resp = httptest.NewRecorder()
92         mh.ServeHTTP(resp, req)
93         c.Check(resp.Code, check.Equals, http.StatusOK)
94         reqs = nil
95         err = json.NewDecoder(resp.Body).Decode(&reqs)
96         c.Check(err, check.IsNil)
97         c.Assert(reqs, check.HasLen, 0)
98 }