1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
14 "git.curoverse.com/arvados.git/sdk/go/arvadostest"
15 "github.com/prometheus/client_golang/prometheus"
16 check "gopkg.in/check.v1"
19 var _ = check.Suite(&MountsSuite{})
21 type MountsSuite struct {
26 func (s *MountsSuite) SetUpTest(c *check.C) {
27 s.vm = MakeTestVolumeManager(2)
29 theConfig = DefaultConfig()
30 theConfig.systemAuthToken = arvadostest.DataManagerToken
31 theConfig.ManagementToken = arvadostest.ManagementToken
32 r := prometheus.NewRegistry()
34 s.rtr = MakeRESTRouter(testCluster, r)
37 func (s *MountsSuite) TearDownTest(c *check.C) {
40 theConfig = DefaultConfig()
41 theConfig.Start(prometheus.NewRegistry())
44 func (s *MountsSuite) TestMounts(c *check.C) {
45 vols := s.vm.AllWritable()
46 vols[0].Put(context.Background(), TestHash, TestBlock)
47 vols[1].Put(context.Background(), TestHash2, TestBlock2)
49 resp := s.call("GET", "/mounts", "", nil)
50 c.Check(resp.Code, check.Equals, http.StatusOK)
51 var mntList []struct {
52 UUID string `json:"uuid"`
53 DeviceID string `json:"device_id"`
54 ReadOnly bool `json:"read_only"`
55 Replication int `json:"replication"`
56 StorageClasses []string `json:"storage_classes"`
58 err := json.Unmarshal(resp.Body.Bytes(), &mntList)
59 c.Assert(err, check.IsNil)
60 c.Assert(len(mntList), check.Equals, 2)
61 for _, m := range mntList {
62 c.Check(len(m.UUID), check.Equals, 27)
63 c.Check(m.UUID[:12], check.Equals, "zzzzz-ivpuk-")
64 c.Check(m.DeviceID, check.Equals, "mock-device-id")
65 c.Check(m.ReadOnly, check.Equals, false)
66 c.Check(m.Replication, check.Equals, 1)
67 c.Check(m.StorageClasses, check.DeepEquals, []string{"default"})
69 c.Check(mntList[0].UUID, check.Not(check.Equals), mntList[1].UUID)
72 for _, tok := range []string{"", "xyzzy"} {
73 resp = s.call("GET", "/mounts/"+mntList[1].UUID+"/blocks", tok, nil)
74 c.Check(resp.Code, check.Equals, http.StatusUnauthorized)
75 c.Check(resp.Body.String(), check.Equals, "Unauthorized\n")
78 tok := arvadostest.DataManagerToken
80 // Nonexistent mount UUID
81 resp = s.call("GET", "/mounts/X/blocks", tok, nil)
82 c.Check(resp.Code, check.Equals, http.StatusNotFound)
83 c.Check(resp.Body.String(), check.Equals, "mount not found\n")
85 // Complete index of first mount
86 resp = s.call("GET", "/mounts/"+mntList[0].UUID+"/blocks", tok, nil)
87 c.Check(resp.Code, check.Equals, http.StatusOK)
88 c.Check(resp.Body.String(), check.Matches, TestHash+`\+[0-9]+ [0-9]+\n\n`)
90 // Partial index of first mount (one block matches prefix)
91 resp = s.call("GET", "/mounts/"+mntList[0].UUID+"/blocks?prefix="+TestHash[:2], tok, nil)
92 c.Check(resp.Code, check.Equals, http.StatusOK)
93 c.Check(resp.Body.String(), check.Matches, TestHash+`\+[0-9]+ [0-9]+\n\n`)
95 // Complete index of second mount (note trailing slash)
96 resp = s.call("GET", "/mounts/"+mntList[1].UUID+"/blocks/", tok, nil)
97 c.Check(resp.Code, check.Equals, http.StatusOK)
98 c.Check(resp.Body.String(), check.Matches, TestHash2+`\+[0-9]+ [0-9]+\n\n`)
100 // Partial index of second mount (no blocks match prefix)
101 resp = s.call("GET", "/mounts/"+mntList[1].UUID+"/blocks/?prefix="+TestHash[:2], tok, nil)
102 c.Check(resp.Code, check.Equals, http.StatusOK)
103 c.Check(resp.Body.String(), check.Equals, "\n")
106 func (s *MountsSuite) TestMetrics(c *check.C) {
107 s.call("PUT", "/"+TestHash, "", TestBlock)
108 s.call("PUT", "/"+TestHash2, "", TestBlock2)
109 resp := s.call("GET", "/metrics.json", "", nil)
110 c.Check(resp.Code, check.Equals, http.StatusUnauthorized)
111 resp = s.call("GET", "/metrics.json", "foobar", nil)
112 c.Check(resp.Code, check.Equals, http.StatusForbidden)
113 resp = s.call("GET", "/metrics.json", arvadostest.ManagementToken, nil)
114 c.Check(resp.Code, check.Equals, http.StatusOK)
125 SampleCount string `json:"sample_count"`
126 SampleSum float64 `json:"sample_sum"`
134 json.NewDecoder(resp.Body).Decode(&j)
135 found := make(map[string]bool)
136 names := map[string]bool{}
137 for _, g := range j {
139 for _, m := range g.Metric {
140 if len(m.Label) == 2 && m.Label[0].Name == "code" && m.Label[0].Value == "200" && m.Label[1].Name == "method" && m.Label[1].Value == "put" {
141 c.Check(m.Summary.SampleCount, check.Equals, "2")
142 c.Check(len(m.Summary.Quantile), check.Not(check.Equals), 0)
143 c.Check(m.Summary.Quantile[0].Value, check.Not(check.Equals), float64(0))
148 c.Check(found["request_duration_seconds"], check.Equals, true)
149 c.Check(found["time_to_status_seconds"], check.Equals, true)
151 metricsNames := []string{
152 "arvados_keepstore_bufferpool_inuse_buffers",
153 "arvados_keepstore_bufferpool_max_buffers",
154 "arvados_keepstore_bufferpool_allocated_bytes",
155 "arvados_keepstore_pull_queue_inprogress_entries",
156 "arvados_keepstore_pull_queue_pending_entries",
157 "arvados_keepstore_concurrent_requests",
158 "arvados_keepstore_max_concurrent_requests",
159 "arvados_keepstore_trash_queue_inprogress_entries",
160 "arvados_keepstore_trash_queue_pending_entries",
161 "request_duration_seconds",
162 "time_to_status_seconds",
164 for _, m := range metricsNames {
166 c.Check(ok, check.Equals, true)
170 func (s *MountsSuite) call(method, path, tok string, body []byte) *httptest.ResponseRecorder {
171 resp := httptest.NewRecorder()
172 req, _ := http.NewRequest(method, path, bytes.NewReader(body))
174 req.Header.Set("Authorization", "Bearer "+tok)
176 s.rtr.ServeHTTP(resp, req)