1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
15 "github.com/prometheus/client_golang/prometheus"
16 "github.com/prometheus/client_golang/prometheus/promhttp"
17 check "gopkg.in/check.v1"
20 func (s *Suite) TestInspect(c *check.C) {
21 reg := prometheus.NewRegistry()
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)
28 mh.ServeHTTP(httptest.NewRecorder(), longreq)
29 close(handlerReturned)
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")
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)
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")
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.*`)
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
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") {
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.*`)
79 h.okToProceed <- struct{}{}
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.*`)
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)
95 err = json.NewDecoder(resp.Body).Decode(&reqs)
96 c.Check(err, check.IsNil)
97 c.Assert(reqs, check.HasLen, 0)