cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.33.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/promapi/cache_test.go

336lines · modecode

1package promapi
2
3import (
4 "errors"
5 "fmt"
6 "strings"
7 "testing"
8 "time"
9
10 "github.com/prometheus/client_golang/prometheus/testutil"
11 "github.com/stretchr/testify/require"
12)
13
14func TestQueryCacheOnlySet(t *testing.T) {
15 const maxSize = 100
16 mockErr := errors.New("Fake Error")
17 cache := newQueryCache(maxSize)
18
19 var i uint64
20 for i = 1; i <= maxSize; i++ {
21 cache.set(i, queryResult{err: mockErr}, 0, 1, "/foo")
22 }
23
24 require.Equal(t, maxSize, cache.cost)
25 require.Equal(t, 100, len(cache.entries))
26 require.Equal(t, 0, cache.evictions)
27}
28
29func TestQueryCacheReplace(t *testing.T) {
30 const maxSize = 100
31 mockErr := errors.New("Fake Error")
32 cache := newQueryCache(maxSize)
33
34 cache.set(6, queryResult{err: mockErr}, 0, 7, "/foo")
35 cache.set(6, queryResult{err: mockErr}, 0, 7, "/foo")
36 cache.set(6, queryResult{err: mockErr}, 0, 7, "/foo")
37
38 require.Equal(t, 7, cache.cost)
39 require.Equal(t, 1, len(cache.entries))
40 require.Equal(t, 0, cache.evictions)
41}
42
43func TestQueryCacheGetAndSet(t *testing.T) {
44 const maxSize = 100
45 mockErr := errors.New("Fake Error")
46 cache := newQueryCache(maxSize)
47
48 var i uint64
49 for i = 1; i <= maxSize; i++ {
50 // first get
51 v, ok := cache.get(i, "/foo")
52 require.Equal(t, false, ok, "should be missing from cache on first get")
53 require.Zero(t, v)
54
55 // first set
56 cache.set(i, queryResult{err: mockErr}, time.Minute, 2, "/foo")
57
58 // second get, should be in cache now
59 v, ok = cache.get(i, "/foo")
60 require.Equal(t, true, ok, "should be present in cache on third get")
61 require.NotZero(t, v)
62 require.Equal(t, mockErr, v.err)
63 }
64
65 require.Equal(t, 100, cache.cost)
66 require.Equal(t, 50, len(cache.entries))
67 require.Equal(t, 100, cache.stats["/foo"].hits)
68 require.Equal(t, 100, cache.stats["/foo"].misses)
69 require.Equal(t, 50, cache.evictions)
70
71 cache.gc()
72 require.Equal(t, 100, cache.cost)
73 require.Equal(t, 50, len(cache.entries))
74 require.Equal(t, 100, cache.stats["/foo"].hits)
75 require.Equal(t, 100, cache.stats["/foo"].misses)
76 require.Equal(t, 50, cache.evictions)
77}
78
79func TestQueryCachePurgeMaxCost(t *testing.T) {
80 const maxSize = 460
81 mockErr := errors.New("Fake Error")
82 cache := newQueryCache(maxSize)
83
84 var i uint64
85 for i = 1; i <= 100; i++ {
86 cost := int(i % 10)
87 if cost == 0 {
88 cost = 1
89 }
90 cache.set(i, queryResult{err: mockErr}, 0, cost, "/foo")
91 _, _ = cache.get(i, "/foo")
92 }
93
94 require.Equal(t, cache.maxCost, cache.cost)
95 require.Equal(t, 100, len(cache.entries))
96 require.Equal(t, 0, cache.evictions)
97
98 for i = 101; i <= 110; i++ {
99 cost := int(i % 10)
100 if cost == 0 {
101 cost = 1
102 }
103 cost++
104 cache.set(i, queryResult{err: mockErr}, 0, cost, "/bar")
105 _, _ = cache.get(i, "/foo")
106 }
107 require.Equal(t, 459, cache.cost)
108 require.Equal(t, 74, len(cache.entries))
109 require.Equal(t, 36, cache.evictions)
110}
111
112func TestQueryCachePurgeZeroTTL(t *testing.T) {
113 const maxSize = 100
114 mockErr := errors.New("Fake Error")
115 cache := newQueryCache(maxSize)
116
117 var i uint64
118 for i = 1; i <= maxSize; i++ {
119 cache.set(i, queryResult{err: mockErr}, 0, 1, "/foo")
120 _, _ = cache.get(i, "/foo")
121 }
122 require.Equal(t, 100, cache.cost)
123 require.Equal(t, 100, len(cache.entries))
124 require.Equal(t, 0, cache.evictions)
125
126 time.Sleep(time.Second)
127
128 cache.gc()
129 require.Equal(t, 100, cache.cost)
130 require.Equal(t, 100, len(cache.entries))
131 require.Equal(t, 0, cache.evictions)
132}
133
134func TestQueryCachePurgeExpired(t *testing.T) {
135 const maxSize = 100
136 mockErr := errors.New("Fake Error")
137 cache := newQueryCache(maxSize)
138
139 var i uint64
140 for i = 1; i <= maxSize; i++ {
141 _, _ = cache.get(i, "/foo")
142 _, _ = cache.get(i, "/foo")
143 cache.set(i, queryResult{err: mockErr}, time.Second, 1, "/foo")
144 _, _ = cache.get(i, "/foo")
145 }
146 require.Equal(t, 100, cache.cost)
147 require.Equal(t, 100, len(cache.entries))
148 require.Equal(t, 0, cache.evictions)
149
150 for i = 1; i <= maxSize/2; i++ {
151 cache.entries[i].expiresAt = time.Now().Add(time.Second * -1)
152 }
153
154 cache.gc()
155 require.Equal(t, 50, cache.cost)
156 require.Equal(t, 50, len(cache.entries))
157 require.Equal(t, 50, cache.evictions)
158}
159
160func TestQueryCacheOverrideExpired(t *testing.T) {
161 const maxSize = 100
162 mockErr := errors.New("Fake Error")
163 cache := newQueryCache(maxSize)
164
165 var i uint64
166 for i = 1; i <= maxSize; i++ {
167 cache.set(i, queryResult{err: mockErr}, time.Second, 1, "/foo")
168 _, _ = cache.get(i, "/foo")
169 }
170 require.Equal(t, 100, cache.cost)
171 require.Equal(t, 100, len(cache.entries))
172 require.Equal(t, 0, cache.evictions)
173
174 cache.entries[maxSize/2].expiresAt = time.Now().Add(time.Second * -1)
175
176 cache.set(maxSize+1, queryResult{err: mockErr}, time.Second, 1, "/foo")
177 _, _ = cache.get(maxSize+1, "/foo")
178
179 require.Equal(t, 100, cache.cost)
180 require.Equal(t, 100, len(cache.entries))
181 require.Equal(t, 1, cache.evictions)
182}
183
184func TestQueryCachePurgeOldLastGet(t *testing.T) {
185 const maxSize = 100
186 mockErr := errors.New("Fake Error")
187 cache := newQueryCache(maxSize)
188
189 var i uint64
190 for i = 1; i <= maxSize; i++ {
191 cache.set(i, queryResult{err: mockErr}, time.Second, 1, "/foo")
192 _, _ = cache.get(i, "/foo")
193 }
194 require.Equal(t, 100, cache.cost)
195 require.Equal(t, 100, len(cache.entries))
196 require.Equal(t, 0, cache.evictions)
197
198 cache.gc()
199 require.Equal(t, 100, cache.cost)
200 require.Equal(t, 100, len(cache.entries))
201 require.Equal(t, 0, cache.evictions)
202
203 time.Sleep(time.Millisecond * 500)
204 for i = 1; i <= maxSize/2; i++ {
205 _, _ = cache.get(i, "/foo")
206 }
207 cache.gc()
208 require.Equal(t, 100, cache.cost)
209 require.Equal(t, 100, len(cache.entries))
210 require.Equal(t, 0, cache.evictions)
211
212 time.Sleep(time.Millisecond * 2600)
213 for i = 1; i <= maxSize/2; i++ {
214 cache.entries[i].expiresAt = time.Now().Add(time.Minute)
215 _, _ = cache.get(i, "/foo")
216 }
217 cache.gc()
218 require.Equal(t, 50, cache.cost)
219 require.Equal(t, 50, len(cache.entries))
220 require.Equal(t, 50, cache.evictions)
221}
222
223func TestCacheCollector(t *testing.T) {
224 const maxSize = 100
225 cache := newQueryCache(maxSize)
226
227 names := []string{
228 "pint_prometheus_cache_size",
229 "pint_prometheus_cache_hits_total",
230 "pint_prometheus_cache_miss_total",
231 "pint_prometheus_cache_evictions_total",
232 }
233
234 collector := newCacheCollector(cache, "prom")
235 require.NoError(t, testutil.CollectAndCompare(
236 collector, strings.NewReader(`
237# HELP pint_prometheus_cache_evictions_total Total number of times an entry was evicted from query cache due to size limit or TTL
238# TYPE pint_prometheus_cache_evictions_total counter
239pint_prometheus_cache_evictions_total{name="prom"} 0
240# HELP pint_prometheus_cache_size Total number of entries currently stored in Prometheus query cache
241# TYPE pint_prometheus_cache_size gauge
242pint_prometheus_cache_size{name="prom"} 0
243`),
244 names...,
245 ))
246
247 var i uint64
248 for i = 1; i <= maxSize; i++ {
249 endpoint := fmt.Sprintf("/foo/%d", i%10)
250 _, _ = cache.get(i, endpoint)
251 _, _ = cache.get(i, endpoint)
252 cache.set(i, queryResult{}, time.Minute, 1, endpoint)
253 _, _ = cache.get(i, endpoint)
254 cache.set(i, queryResult{}, time.Minute, 1, endpoint)
255 _, _ = cache.get(i, endpoint)
256 }
257
258 require.NoError(t, testutil.CollectAndCompare(
259 collector, strings.NewReader(`
260# HELP pint_prometheus_cache_evictions_total Total number of times an entry was evicted from query cache due to size limit or TTL
261# TYPE pint_prometheus_cache_evictions_total counter
262pint_prometheus_cache_evictions_total{name="prom"} 0
263# HELP pint_prometheus_cache_hits_total Total number of query cache hits
264# TYPE pint_prometheus_cache_hits_total counter
265pint_prometheus_cache_hits_total{endpoint="/foo/0",name="prom"} 20
266pint_prometheus_cache_hits_total{endpoint="/foo/1",name="prom"} 20
267pint_prometheus_cache_hits_total{endpoint="/foo/2",name="prom"} 20
268pint_prometheus_cache_hits_total{endpoint="/foo/3",name="prom"} 20
269pint_prometheus_cache_hits_total{endpoint="/foo/4",name="prom"} 20
270pint_prometheus_cache_hits_total{endpoint="/foo/5",name="prom"} 20
271pint_prometheus_cache_hits_total{endpoint="/foo/6",name="prom"} 20
272pint_prometheus_cache_hits_total{endpoint="/foo/7",name="prom"} 20
273pint_prometheus_cache_hits_total{endpoint="/foo/8",name="prom"} 20
274pint_prometheus_cache_hits_total{endpoint="/foo/9",name="prom"} 20
275# HELP pint_prometheus_cache_miss_total Total number of query cache misses
276# TYPE pint_prometheus_cache_miss_total counter
277pint_prometheus_cache_miss_total{endpoint="/foo/0",name="prom"} 20
278pint_prometheus_cache_miss_total{endpoint="/foo/1",name="prom"} 20
279pint_prometheus_cache_miss_total{endpoint="/foo/2",name="prom"} 20
280pint_prometheus_cache_miss_total{endpoint="/foo/3",name="prom"} 20
281pint_prometheus_cache_miss_total{endpoint="/foo/4",name="prom"} 20
282pint_prometheus_cache_miss_total{endpoint="/foo/5",name="prom"} 20
283pint_prometheus_cache_miss_total{endpoint="/foo/6",name="prom"} 20
284pint_prometheus_cache_miss_total{endpoint="/foo/7",name="prom"} 20
285pint_prometheus_cache_miss_total{endpoint="/foo/8",name="prom"} 20
286pint_prometheus_cache_miss_total{endpoint="/foo/9",name="prom"} 20
287# HELP pint_prometheus_cache_size Total number of entries currently stored in Prometheus query cache
288# TYPE pint_prometheus_cache_size gauge
289pint_prometheus_cache_size{name="prom"} 100
290`),
291 names...,
292 ))
293
294 for i = maxSize + 1; i <= maxSize+10; i++ {
295 endpoint := fmt.Sprintf("/foo/%d", i%10)
296 _, _ = cache.get(i, endpoint)
297 _, _ = cache.get(i, endpoint)
298 cache.set(i, queryResult{}, time.Minute, 1, endpoint)
299 }
300
301 require.NoError(t, testutil.CollectAndCompare(
302 collector, strings.NewReader(`
303# HELP pint_prometheus_cache_evictions_total Total number of times an entry was evicted from query cache due to size limit or TTL
304# TYPE pint_prometheus_cache_evictions_total counter
305pint_prometheus_cache_evictions_total{name="prom"} 10
306# HELP pint_prometheus_cache_hits_total Total number of query cache hits
307# TYPE pint_prometheus_cache_hits_total counter
308pint_prometheus_cache_hits_total{endpoint="/foo/0",name="prom"} 20
309pint_prometheus_cache_hits_total{endpoint="/foo/1",name="prom"} 20
310pint_prometheus_cache_hits_total{endpoint="/foo/2",name="prom"} 20
311pint_prometheus_cache_hits_total{endpoint="/foo/3",name="prom"} 20
312pint_prometheus_cache_hits_total{endpoint="/foo/4",name="prom"} 20
313pint_prometheus_cache_hits_total{endpoint="/foo/5",name="prom"} 20
314pint_prometheus_cache_hits_total{endpoint="/foo/6",name="prom"} 20
315pint_prometheus_cache_hits_total{endpoint="/foo/7",name="prom"} 20
316pint_prometheus_cache_hits_total{endpoint="/foo/8",name="prom"} 20
317pint_prometheus_cache_hits_total{endpoint="/foo/9",name="prom"} 20
318# HELP pint_prometheus_cache_miss_total Total number of query cache misses
319# TYPE pint_prometheus_cache_miss_total counter
320pint_prometheus_cache_miss_total{endpoint="/foo/0",name="prom"} 22
321pint_prometheus_cache_miss_total{endpoint="/foo/1",name="prom"} 22
322pint_prometheus_cache_miss_total{endpoint="/foo/2",name="prom"} 22
323pint_prometheus_cache_miss_total{endpoint="/foo/3",name="prom"} 22
324pint_prometheus_cache_miss_total{endpoint="/foo/4",name="prom"} 22
325pint_prometheus_cache_miss_total{endpoint="/foo/5",name="prom"} 22
326pint_prometheus_cache_miss_total{endpoint="/foo/6",name="prom"} 22
327pint_prometheus_cache_miss_total{endpoint="/foo/7",name="prom"} 22
328pint_prometheus_cache_miss_total{endpoint="/foo/8",name="prom"} 22
329pint_prometheus_cache_miss_total{endpoint="/foo/9",name="prom"} 22
330# HELP pint_prometheus_cache_size Total number of entries currently stored in Prometheus query cache
331# TYPE pint_prometheus_cache_size gauge
332pint_prometheus_cache_size{name="prom"} 100
333`),
334 names...,
335 ))
336}
337