19192: Add a few bytes to MemorySize to account for data structures.
[arvados.git] / services / keep-web / cache_test.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package keepweb
6
7 import (
8         "bytes"
9
10         "git.arvados.org/arvados.git/sdk/go/arvados"
11         "git.arvados.org/arvados.git/sdk/go/arvadosclient"
12         "git.arvados.org/arvados.git/sdk/go/arvadostest"
13         "git.arvados.org/arvados.git/sdk/go/ctxlog"
14         "github.com/prometheus/client_golang/prometheus"
15         "github.com/prometheus/common/expfmt"
16         "gopkg.in/check.v1"
17 )
18
19 func (s *UnitSuite) checkCacheMetrics(c *check.C, reg *prometheus.Registry, regs ...string) {
20         mfs, err := reg.Gather()
21         c.Check(err, check.IsNil)
22         buf := &bytes.Buffer{}
23         enc := expfmt.NewEncoder(buf, expfmt.FmtText)
24         for _, mf := range mfs {
25                 c.Check(enc.Encode(mf), check.IsNil)
26         }
27         mm := buf.String()
28         for _, reg := range regs {
29                 c.Check(mm, check.Matches, `(?ms).*collectioncache_`+reg+`\n.*`)
30         }
31 }
32
33 func (s *UnitSuite) TestCache(c *check.C) {
34         arv, err := arvadosclient.MakeArvadosClient()
35         c.Assert(err, check.Equals, nil)
36
37         cache := &cache{
38                 cluster:  s.cluster,
39                 logger:   ctxlog.TestLogger(c),
40                 registry: prometheus.NewRegistry(),
41         }
42
43         // Hit the same collection 5 times using the same token. Only
44         // the first req should cause an API call; the next 4 should
45         // hit all caches.
46         arv.ApiToken = arvadostest.AdminToken
47         var coll *arvados.Collection
48         for i := 0; i < 5; i++ {
49                 coll, err = cache.Get(arv, arvadostest.FooCollection, false)
50                 c.Check(err, check.Equals, nil)
51                 c.Assert(coll, check.NotNil)
52                 c.Check(coll.PortableDataHash, check.Equals, arvadostest.FooCollectionPDH)
53                 c.Check(coll.ManifestText[:2], check.Equals, ". ")
54         }
55         s.checkCacheMetrics(c, cache.registry,
56                 "requests 5",
57                 "hits 4",
58                 "pdh_hits 4",
59                 "api_calls 1")
60
61         // Hit the same collection 2 more times, this time requesting
62         // it by PDH and using a different token. The first req should
63         // miss the permission cache and fetch the new manifest; the
64         // second should hit the Collection cache and skip the API
65         // lookup.
66         arv.ApiToken = arvadostest.ActiveToken
67
68         coll2, err := cache.Get(arv, arvadostest.FooCollectionPDH, false)
69         c.Check(err, check.Equals, nil)
70         c.Assert(coll2, check.NotNil)
71         c.Check(coll2.PortableDataHash, check.Equals, arvadostest.FooCollectionPDH)
72         c.Check(coll2.ManifestText[:2], check.Equals, ". ")
73         c.Check(coll2.ManifestText, check.Not(check.Equals), coll.ManifestText)
74
75         s.checkCacheMetrics(c, cache.registry,
76                 "requests 6",
77                 "hits 4",
78                 "pdh_hits 4",
79                 "api_calls 2")
80
81         coll2, err = cache.Get(arv, arvadostest.FooCollectionPDH, false)
82         c.Check(err, check.Equals, nil)
83         c.Assert(coll2, check.NotNil)
84         c.Check(coll2.PortableDataHash, check.Equals, arvadostest.FooCollectionPDH)
85         c.Check(coll2.ManifestText[:2], check.Equals, ". ")
86
87         s.checkCacheMetrics(c, cache.registry,
88                 "requests 7",
89                 "hits 5",
90                 "pdh_hits 4",
91                 "api_calls 2")
92
93         // Alternating between two collections N times should produce
94         // only 2 more API calls.
95         arv.ApiToken = arvadostest.AdminToken
96         for i := 0; i < 20; i++ {
97                 var target string
98                 if i%2 == 0 {
99                         target = arvadostest.HelloWorldCollection
100                 } else {
101                         target = arvadostest.FooBarDirCollection
102                 }
103                 _, err := cache.Get(arv, target, false)
104                 c.Check(err, check.Equals, nil)
105         }
106         s.checkCacheMetrics(c, cache.registry,
107                 "requests 27",
108                 "hits 23",
109                 "pdh_hits 22",
110                 "api_calls 4")
111 }
112
113 func (s *UnitSuite) TestCacheForceReloadByPDH(c *check.C) {
114         arv, err := arvadosclient.MakeArvadosClient()
115         c.Assert(err, check.Equals, nil)
116
117         cache := &cache{
118                 cluster:  s.cluster,
119                 logger:   ctxlog.TestLogger(c),
120                 registry: prometheus.NewRegistry(),
121         }
122
123         for _, forceReload := range []bool{false, true, false, true} {
124                 _, err := cache.Get(arv, arvadostest.FooCollectionPDH, forceReload)
125                 c.Check(err, check.Equals, nil)
126         }
127
128         s.checkCacheMetrics(c, cache.registry,
129                 "requests 4",
130                 "hits 3",
131                 "pdh_hits 0",
132                 "api_calls 1")
133 }
134
135 func (s *UnitSuite) TestCacheForceReloadByUUID(c *check.C) {
136         arv, err := arvadosclient.MakeArvadosClient()
137         c.Assert(err, check.Equals, nil)
138
139         cache := &cache{
140                 cluster:  s.cluster,
141                 logger:   ctxlog.TestLogger(c),
142                 registry: prometheus.NewRegistry(),
143         }
144
145         for _, forceReload := range []bool{false, true, false, true} {
146                 _, err := cache.Get(arv, arvadostest.FooCollection, forceReload)
147                 c.Check(err, check.Equals, nil)
148         }
149
150         s.checkCacheMetrics(c, cache.registry,
151                 "requests 4",
152                 "hits 3",
153                 "pdh_hits 3",
154                 "api_calls 3")
155 }