master
go 118 lines 3.31 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package metrix
4
5 import (
6 "testing"
7
8 "github.com/stretchr/testify/require"
9 )
10
11 func TestCollectorStoreRetentionScenarios(t *testing.T) {
12 tests := map[string]struct {
13 run func(t *testing.T)
14 }{
15 "retention aging advances on successful cycles only": {
16 run: func(t *testing.T) {
17 s := NewCollectorStore()
18 sv := collectorStoreViewForTest(t, s)
19 sv.core.retention = collectorRetentionPolicy{
20 expireAfterSuccessCycles: 2,
21 maxSeries: 0,
22 }
23 cc := cycleController(t, s)
24 m := s.Write().SnapshotMeter("collector")
25 g := m.Gauge("g")
26
27 cc.BeginCycle()
28 g.Observe(11)
29 cc.CommitCycleSuccess()
30
31 cc.BeginCycle()
32 cc.AbortCycle()
33
34 cc.BeginCycle()
35 cc.CommitCycleSuccess()
36 mustValue(t, s.Read(ReadRaw()), "collector.g", nil, 11)
37
38 cc.BeginCycle()
39 cc.CommitCycleSuccess()
40 mustNoValue(t, s.Read(ReadRaw()), "collector.g", nil)
41 },
42 },
43 "max-series cap evicts oldest series deterministically": {
44 run: func(t *testing.T) {
45 s := NewCollectorStore()
46 sv := collectorStoreViewForTest(t, s)
47 sv.core.retention = collectorRetentionPolicy{
48 expireAfterSuccessCycles: 0,
49 maxSeries: 2,
50 }
51 cc := cycleController(t, s)
52 m := s.Write().SnapshotMeter("collector")
53 g := m.Gauge("g")
54 lsa := m.LabelSet(Label{Key: "id", Value: "a"})
55 lsb := m.LabelSet(Label{Key: "id", Value: "b"})
56 lsc := m.LabelSet(Label{Key: "id", Value: "c"})
57
58 cc.BeginCycle()
59 g.Observe(1, lsa)
60 g.Observe(2, lsb)
61 cc.CommitCycleSuccess()
62
63 cc.BeginCycle()
64 g.Observe(3, lsc)
65 cc.CommitCycleSuccess()
66
67 mustNoValue(t, s.Read(ReadRaw()), "collector.g", Labels{"id": "a"})
68 mustValue(t, s.Read(ReadRaw()), "collector.g", Labels{"id": "b"}, 2)
69 mustValue(t, s.Read(ReadRaw()), "collector.g", Labels{"id": "c"}, 3)
70 },
71 },
72 "max-series cap tie-break uses stable key order when lastSeen is equal": {
73 run: func(t *testing.T) {
74 s := NewCollectorStore()
75 sv := collectorStoreViewForTest(t, s)
76 sv.core.retention = collectorRetentionPolicy{
77 expireAfterSuccessCycles: 0,
78 maxSeries: 2,
79 }
80 cc := cycleController(t, s)
81 m := s.Write().SnapshotMeter("collector")
82 g := m.Gauge("g")
83 lsa := m.LabelSet(Label{Key: "id", Value: "a"})
84 lsb := m.LabelSet(Label{Key: "id", Value: "b"})
85 lsc := m.LabelSet(Label{Key: "id", Value: "c"})
86
87 // All series are written in the same successful cycle so they share
88 // identical retention age; eviction must be deterministic by key.
89 cc.BeginCycle()
90 g.Observe(1, lsa)
91 g.Observe(2, lsb)
92 g.Observe(3, lsc)
93 cc.CommitCycleSuccess()
94
95 mustNoValue(t, s.Read(ReadRaw()), "collector.g", Labels{"id": "a"})
96 mustValue(t, s.Read(ReadRaw()), "collector.g", Labels{"id": "b"}, 2)
97 mustValue(t, s.Read(ReadRaw()), "collector.g", Labels{"id": "c"}, 3)
98 },
99 },
100 }
101
102 for name, tc := range tests {
103 t.Run(name, tc.run)
104 }
105 }
106
107 func collectorStoreViewForTest(t *testing.T, s CollectorStore) *storeView {
108 t.Helper()
109 v, ok := s.(*storeView)
110 require.True(t, ok, "unexpected collector store implementation: %T", s)
111 return v
112 }
113
114 func mustNoValue(t *testing.T, r Reader, name string, labels Labels) {
115 t.Helper()
116 _, ok := r.Value(name, labels)
117 require.False(t, ok, "expected no value for %s labels=%v", name, labels)
118 }