master
go 224 lines 6.6 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 TestGaugeStoreScenarios(t *testing.T) {
12 tests := map[string]struct {
13 run func(t *testing.T)
14 }{
15 "snapshot gauge freshness and raw visibility": {
16 run: func(t *testing.T) {
17 s := NewCollectorStore()
18 cc := cycleController(t, s)
19 g := s.Write().SnapshotMeter("apache").Gauge("workers_busy")
20
21 cc.BeginCycle()
22 g.Observe(10)
23 cc.CommitCycleSuccess()
24 mustValue(t, s.Read(), "apache.workers_busy", nil, 10)
25
26 cc.BeginCycle()
27 cc.CommitCycleSuccess()
28
29 _, ok := s.Read().Value("apache.workers_busy", nil)
30 require.False(t, ok, "expected snapshot gauge hidden after successful cycle with no sample")
31 mustValue(t, s.Read(ReadRaw()), "apache.workers_busy", nil, 10)
32 },
33 },
34 "stateful gauge set and add semantics": {
35 run: func(t *testing.T) {
36 s := NewCollectorStore()
37 cc := cycleController(t, s)
38 g := s.Write().StatefulMeter("runtime").Gauge("heap_bytes")
39
40 cc.BeginCycle()
41 g.Set(5)
42 cc.CommitCycleSuccess()
43 mustValue(t, s.Read(), "runtime.heap_bytes", nil, 5)
44
45 cc.BeginCycle()
46 g.Add(2)
47 cc.CommitCycleSuccess()
48 mustValue(t, s.Read(), "runtime.heap_bytes", nil, 7)
49
50 cc.BeginCycle()
51 g.Add(3)
52 g.Add(4)
53 cc.CommitCycleSuccess()
54 mustValue(t, s.Read(), "runtime.heap_bytes", nil, 14)
55
56 cc.BeginCycle()
57 g.Set(1)
58 g.Add(2)
59 cc.CommitCycleSuccess()
60 mustValue(t, s.Read(), "runtime.heap_bytes", nil, 3)
61
62 cc.BeginCycle()
63 cc.CommitCycleSuccess()
64 mustValue(t, s.Read(), "runtime.heap_bytes", nil, 3)
65 },
66 },
67 "abort keeps committed data and marks failed attempt": {
68 run: func(t *testing.T) {
69 s := NewCollectorStore()
70 cc := cycleController(t, s)
71 g := s.Write().SnapshotMeter("svc").Gauge("load")
72
73 cc.BeginCycle()
74 g.Observe(11)
75 cc.CommitCycleSuccess()
76 mustValue(t, s.Read(), "svc.load", nil, 11)
77
78 cc.BeginCycle()
79 g.Observe(20)
80 cc.AbortCycle()
81
82 meta := s.Read().CollectMeta()
83 require.Equal(t, CollectStatusFailed, meta.LastAttemptStatus, "unexpected collect meta after abort: %#v", meta)
84 require.Equal(t, uint64(2), meta.LastAttemptSeq, "unexpected collect meta after abort: %#v", meta)
85 require.Equal(t, uint64(1), meta.LastSuccessSeq, "unexpected collect meta after abort: %#v", meta)
86 _, ok := s.Read().Value("svc.load", nil)
87 require.False(t, ok, "expected snapshot gauge hidden after failed attempt")
88 mustValue(t, s.Read(ReadRaw()), "svc.load", nil, 11)
89 },
90 },
91 "commit updates collect metadata on successful cycles": {
92 run: func(t *testing.T) {
93 s := NewCollectorStore()
94 cc := cycleController(t, s)
95 g := s.Write().SnapshotMeter("svc").Gauge("load")
96
97 cc.BeginCycle()
98 g.Observe(3)
99 cc.CommitCycleSuccess()
100
101 meta := s.Read().CollectMeta()
102 require.Equal(t, CollectStatusSuccess, meta.LastAttemptStatus, "unexpected collect meta after first success: %#v", meta)
103 require.Equal(t, uint64(1), meta.LastAttemptSeq, "unexpected collect meta after first success: %#v", meta)
104 require.Equal(t, uint64(1), meta.LastSuccessSeq, "unexpected collect meta after first success: %#v", meta)
105
106 cc.BeginCycle()
107 g.Observe(4)
108 cc.CommitCycleSuccess()
109
110 meta = s.Read().CollectMeta()
111 require.Equal(t, CollectStatusSuccess, meta.LastAttemptStatus, "unexpected collect meta after second success: %#v", meta)
112 require.Equal(t, uint64(2), meta.LastAttemptSeq, "unexpected collect meta after second success: %#v", meta)
113 require.Equal(t, uint64(2), meta.LastSuccessSeq, "unexpected collect meta after second success: %#v", meta)
114 },
115 },
116 "mode mixing snapshot and stateful panics": {
117 run: func(t *testing.T) {
118 s := NewCollectorStore()
119 s.Write().SnapshotMeter("mixed").Gauge("metric")
120 expectPanic(t, func() {
121 _ = s.Write().StatefulMeter("mixed").Gauge("metric")
122 })
123 },
124 },
125 "write outside cycle panics": {
126 run: func(t *testing.T) {
127 s := NewCollectorStore()
128 g := s.Write().SnapshotMeter("panic").Gauge("outside")
129 expectPanic(t, func() {
130 g.Observe(1)
131 })
132 },
133 },
134 "label set validation and merging": {
135 run: func(t *testing.T) {
136 s := NewCollectorStore()
137 cc := cycleController(t, s)
138 sm := s.Write().SnapshotMeter("apache").WithLabels(Label{Key: "instance", Value: "a"})
139 g := sm.Gauge("workers")
140
141 cc.BeginCycle()
142 g.Observe(3)
143 cc.CommitCycleSuccess()
144 mustValue(t, s.Read(), "apache.workers", Labels{"instance": "a"}, 3)
145
146 cc.BeginCycle()
147 ls := sm.LabelSet(Label{Key: "role", Value: "primary"})
148 g.Observe(9, ls)
149 cc.CommitCycleSuccess()
150 mustValue(t, s.Read(), "apache.workers", Labels{"instance": "a", "role": "primary"}, 9)
151
152 cc.BeginCycle()
153 dup := sm.LabelSet(Label{Key: "instance", Value: "b"})
154 expectPanic(t, func() {
155 g.Observe(1, dup)
156 })
157 cc.AbortCycle()
158 },
159 },
160 "foreign label set panics": {
161 run: func(t *testing.T) {
162 s1 := NewCollectorStore()
163 s2 := NewCollectorStore()
164 cc := cycleController(t, s1)
165 g := s1.Write().SnapshotMeter("svc").Gauge("reqs")
166 foreign := s2.Write().SnapshotMeter("svc").LabelSet(Label{Key: "instance", Value: "x"})
167
168 cc.BeginCycle()
169 expectPanic(t, func() {
170 g.Observe(1, foreign)
171 })
172 cc.AbortCycle()
173 },
174 },
175 "published snapshot labels stay stable across later commits": {
176 run: func(t *testing.T) {
177 s := NewCollectorStore()
178 cc := cycleController(t, s)
179 sm := s.Write().SnapshotMeter("apache").WithLabels(Label{Key: "instance", Value: "a"})
180 g := sm.Gauge("workers")
181 role := sm.LabelSet(Label{Key: "role", Value: "primary"})
182
183 cc.BeginCycle()
184 g.Observe(10, role)
185 cc.CommitCycleSuccess()
186
187 oldReader := s.Read(ReadRaw())
188 assertSingleSeries := func(r Reader, wantValue SampleValue, wantLabels map[string]string) {
189 count := 0
190 r.ForEachByName("apache.workers", func(labels LabelView, v SampleValue) {
191 count++
192 require.Equal(t, wantValue, v)
193 require.Equal(t, wantLabels, labels.CloneMap())
194 })
195 require.Equal(t, 1, count, "unexpected series count")
196 }
197
198 assertSingleSeries(oldReader, 10, map[string]string{
199 "instance": "a",
200 "role": "primary",
201 })
202
203 cc.BeginCycle()
204 g.Observe(20, role)
205 cc.CommitCycleSuccess()
206
207 // Old reader snapshot must stay immutable after later commits.
208 assertSingleSeries(oldReader, 10, map[string]string{
209 "instance": "a",
210 "role": "primary",
211 })
212
213 assertSingleSeries(s.Read(ReadRaw()), 20, map[string]string{
214 "instance": "a",
215 "role": "primary",
216 })
217 },
218 },
219 }
220
221 for name, tc := range tests {
222 t.Run(name, tc.run)
223 }
224 }