Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/util/testappender/testappender_test.go
4096 views
1
package testappender_test
2
3
import (
4
"fmt"
5
"testing"
6
7
"github.com/grafana/agent/pkg/util/testappender"
8
"github.com/prometheus/prometheus/model/exemplar"
9
"github.com/prometheus/prometheus/model/labels"
10
"github.com/prometheus/prometheus/model/metadata"
11
"github.com/prometheus/prometheus/model/textparse"
12
"github.com/stretchr/testify/require"
13
)
14
15
func Example() {
16
var app testappender.Appender
17
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar"), 60, 1234)
18
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric"), metadata.Metadata{
19
Type: textparse.MetricTypeGauge,
20
})
21
22
expect := `
23
# TYPE example_metric gauge
24
example_metric{foo="bar"} 1234 60
25
`
26
27
_ = app.Commit()
28
families, _ := app.MetricFamilies()
29
30
err := testappender.Compare(families, expect)
31
if err != nil {
32
fmt.Println("Metrics do not match:", err)
33
} else {
34
fmt.Println("Metrics match!")
35
}
36
// Output: Metrics match!
37
}
38
39
// TestAppender_NoOp asserts that not doing anything results in no data.
40
func TestAppender_NoOp(t *testing.T) {
41
var app testappender.Appender
42
requireAppenderData(t, &app, "", false)
43
}
44
45
func TestAppender_Metadata(t *testing.T) {
46
t.Run("No metadata", func(t *testing.T) {
47
var app testappender.Appender
48
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar"), 60, 1234)
49
50
expect := `
51
# TYPE example_metric untyped
52
example_metric{foo="bar"} 1234 60
53
`
54
requireAppenderData(t, &app, expect, false)
55
})
56
57
t.Run("Has metadata", func(t *testing.T) {
58
var app testappender.Appender
59
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar"), 60, 1234)
60
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric"), metadata.Metadata{
61
Type: textparse.MetricTypeGauge,
62
Help: "example metric",
63
})
64
65
expect := `
66
# HELP example_metric example metric
67
# TYPE example_metric gauge
68
example_metric{foo="bar"} 1234 60
69
`
70
requireAppenderData(t, &app, expect, false)
71
})
72
73
t.Run("No help field", func(t *testing.T) {
74
var app testappender.Appender
75
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar"), 60, 1234)
76
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric"), metadata.Metadata{
77
Type: textparse.MetricTypeGauge,
78
})
79
80
expect := `
81
# TYPE example_metric gauge
82
example_metric{foo="bar"} 1234 60
83
`
84
requireAppenderData(t, &app, expect, false)
85
})
86
}
87
88
func TestAppender_Types(t *testing.T) {
89
t.Run("Untyped", func(t *testing.T) {
90
var app testappender.Appender
91
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar"), 60, 1234)
92
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric"), metadata.Metadata{
93
Type: textparse.MetricTypeUnknown,
94
})
95
96
expect := `
97
# TYPE example_metric untyped
98
example_metric{foo="bar"} 1234 60
99
`
100
requireAppenderData(t, &app, expect, false)
101
})
102
103
t.Run("Counter", func(t *testing.T) {
104
var app testappender.Appender
105
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar"), 60, 1234)
106
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric"), metadata.Metadata{
107
Type: textparse.MetricTypeCounter,
108
})
109
110
expect := `
111
# TYPE example_metric counter
112
example_metric{foo="bar"} 1234 60
113
`
114
requireAppenderData(t, &app, expect, false)
115
})
116
117
t.Run("Gauge", func(t *testing.T) {
118
var app testappender.Appender
119
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar"), 60, 1234)
120
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric"), metadata.Metadata{
121
Type: textparse.MetricTypeGauge,
122
})
123
124
expect := `
125
# TYPE example_metric gauge
126
example_metric{foo="bar"} 1234 60
127
`
128
requireAppenderData(t, &app, expect, false)
129
})
130
131
t.Run("Summary", func(t *testing.T) {
132
var app testappender.Appender
133
134
// Summaries have quantiles from 0 to 1, counts, and sums. Append the
135
// metadata first and then append all the various samples.
136
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric"), metadata.Metadata{
137
Type: textparse.MetricTypeSummary,
138
})
139
140
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar", "quantile", "0"), 10, 10)
141
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar", "quantile", "0.25"), 10, 10)
142
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar", "quantile", "0.50"), 10, 10)
143
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar", "quantile", "0.75"), 10, 10)
144
app.Append(0, labels.FromStrings("__name__", "example_metric", "foo", "bar", "quantile", "1"), 10, 10)
145
app.Append(0, labels.FromStrings("__name__", "example_metric_count", "foo", "bar"), 10, 5)
146
app.Append(0, labels.FromStrings("__name__", "example_metric_sum", "foo", "bar"), 10, 50)
147
148
expect := `
149
# TYPE example_metric summary
150
example_metric{foo="bar",quantile="0"} 10 10
151
example_metric{foo="bar",quantile="0.25"} 10 10
152
example_metric{foo="bar",quantile="0.5"} 10 10
153
example_metric{foo="bar",quantile="0.75"} 10 10
154
example_metric{foo="bar",quantile="1"} 10 10
155
example_metric_sum{foo="bar"} 50 10
156
example_metric_count{foo="bar"} 5 10
157
`
158
requireAppenderData(t, &app, expect, false)
159
})
160
161
t.Run("Histogram", func(t *testing.T) {
162
var app testappender.Appender
163
164
// Histograms have buckets, counts, and sums. Append the metadata first and
165
// then append all the various samples.
166
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric"), metadata.Metadata{
167
Type: textparse.MetricTypeHistogram,
168
})
169
170
app.Append(0, labels.FromStrings("__name__", "example_metric_bucket", "foo", "bar", "le", "0.5"), 10, 10)
171
app.Append(0, labels.FromStrings("__name__", "example_metric_bucket", "foo", "bar", "le", "0.75"), 10, 20)
172
app.Append(0, labels.FromStrings("__name__", "example_metric_bucket", "foo", "bar", "le", "1"), 10, 30)
173
app.Append(0, labels.FromStrings("__name__", "example_metric_bucket", "foo", "bar", "le", "+Inf"), 10, 40)
174
app.Append(0, labels.FromStrings("__name__", "example_metric_count", "foo", "bar"), 10, 4)
175
app.Append(0, labels.FromStrings("__name__", "example_metric_sum", "foo", "bar"), 10, 100)
176
177
expect := `
178
# TYPE example_metric histogram
179
example_metric_bucket{foo="bar",le="0.5"} 10 10
180
example_metric_bucket{foo="bar",le="0.75"} 20 10
181
example_metric_bucket{foo="bar",le="1"} 30 10
182
example_metric_bucket{foo="bar",le="+Inf"} 40 10
183
example_metric_sum{foo="bar"} 100 10
184
example_metric_count{foo="bar"} 4 10
185
`
186
requireAppenderData(t, &app, expect, false)
187
})
188
}
189
190
func TestAppender_Exemplars(t *testing.T) {
191
// These tests are the only tests where we explicitly test the OpenMetrics
192
// exposition format since OpenMetrics is the only text exposition format
193
// that supports exemplars.
194
195
t.Run("Counter", func(t *testing.T) {
196
var app testappender.Appender
197
app.Append(0, labels.FromStrings("__name__", "example_metric_total", "foo", "bar"), 60, 1234)
198
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric_total"), metadata.Metadata{
199
Type: textparse.MetricTypeCounter,
200
})
201
app.AppendExemplar(0, labels.FromStrings("__name__", "example_metric_total", "foo", "bar"), exemplar.Exemplar{
202
Labels: labels.FromStrings("hello", "world"),
203
Value: 1337,
204
Ts: 30,
205
HasTs: true,
206
})
207
208
expect := `
209
# TYPE example_metric counter
210
example_metric_total{foo="bar"} 1234.0 0.06 # {hello="world"} 1337.0 0.03
211
`
212
requireAppenderData(t, &app, expect, true)
213
})
214
215
t.Run("Histogram", func(t *testing.T) {
216
var app testappender.Appender
217
218
// Histograms have buckets, counts, and sums. Append the metadata first and
219
// then append all the various samples.
220
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric"), metadata.Metadata{
221
Type: textparse.MetricTypeHistogram,
222
})
223
224
app.Append(0, labels.FromStrings("__name__", "example_metric_bucket", "foo", "bar", "le", "0.5"), 10, 10)
225
app.Append(0, labels.FromStrings("__name__", "example_metric_bucket", "foo", "bar", "le", "0.75"), 10, 20)
226
app.Append(0, labels.FromStrings("__name__", "example_metric_bucket", "foo", "bar", "le", "1"), 10, 30)
227
app.Append(0, labels.FromStrings("__name__", "example_metric_bucket", "foo", "bar", "le", "+Inf"), 10, 40)
228
app.Append(0, labels.FromStrings("__name__", "example_metric_count", "foo", "bar"), 10, 4)
229
app.Append(0, labels.FromStrings("__name__", "example_metric_sum", "foo", "bar"), 10, 100)
230
231
// Exemplars must be attached to a specific bucket.
232
app.AppendExemplar(0, labels.FromStrings("__name__", "example_metric_bucket", "foo", "bar", "le", "0.75"), exemplar.Exemplar{
233
Labels: labels.FromStrings("hello", "world"),
234
Value: 1337,
235
Ts: 30,
236
HasTs: true,
237
})
238
239
expect := `
240
# TYPE example_metric histogram
241
example_metric_bucket{foo="bar",le="0.5"} 10 0.01
242
example_metric_bucket{foo="bar",le="0.75"} 20 0.01 # {hello="world"} 1337.0 0.03
243
example_metric_bucket{foo="bar",le="1.0"} 30 0.01
244
example_metric_bucket{foo="bar",le="+Inf"} 40 0.01
245
example_metric_sum{foo="bar"} 100.0 0.01
246
example_metric_count{foo="bar"} 4 0.01
247
`
248
requireAppenderData(t, &app, expect, true)
249
})
250
}
251
252
// TestAppender_MultipleMetrics tests that multiple metrics, where some have
253
// metadata and others don't, works as expected.
254
func TestAppender_MultipleMetrics(t *testing.T) {
255
var app testappender.Appender
256
257
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric_a"), metadata.Metadata{
258
Type: textparse.MetricTypeCounter,
259
})
260
app.UpdateMetadata(0, labels.FromStrings("__name__", "example_metric_b"), metadata.Metadata{
261
Type: textparse.MetricTypeGauge,
262
})
263
264
app.Append(0, labels.FromStrings("__name__", "example_metric_a", "foo", "bar"), 10, 10)
265
app.Append(0, labels.FromStrings("__name__", "example_metric_a", "foo", "rab"), 10, 20)
266
app.Append(0, labels.FromStrings("__name__", "example_metric_b", "fizz", "buzz"), 10, 30)
267
app.Append(0, labels.FromStrings("__name__", "example_metric_b", "fizz", "zzub"), 10, 40)
268
app.Append(0, labels.FromStrings("__name__", "example_metric_c", "hello", "world"), 10, 50)
269
app.Append(0, labels.FromStrings("__name__", "example_metric_c", "hello", "dlrow"), 10, 60)
270
271
expect := `
272
# TYPE example_metric_a counter
273
example_metric_a{foo="bar"} 10 10
274
example_metric_a{foo="rab"} 20 10
275
# TYPE example_metric_b gauge
276
example_metric_b{fizz="buzz"} 30 10
277
example_metric_b{fizz="zzub"} 40 10
278
# TYPE example_metric_c untyped
279
example_metric_c{hello="dlrow"} 60 10
280
example_metric_c{hello="world"} 50 10
281
`
282
requireAppenderData(t, &app, expect, false)
283
}
284
285
// requireAppenderData commits the appender and asserts that its resulting data
286
// matches the Prometheus Exposition Format string specified by expect.
287
func requireAppenderData(t *testing.T, app *testappender.Appender, expect string, openMetrics bool) {
288
t.Helper()
289
290
require.NoError(t, app.Commit(), "commit should not have failed")
291
292
families, err := app.MetricFamilies()
293
require.NoError(t, err, "failed to get metric families")
294
295
var c testappender.Comparer
296
c.OpenMetrics = openMetrics
297
require.NoError(t, c.Compare(families, expect))
298
}
299
300