Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/pkg/agentctl/walstats_test.go
4094 views
1
package agentctl
2
3
import (
4
"fmt"
5
"path/filepath"
6
"testing"
7
8
"github.com/go-kit/log"
9
"github.com/prometheus/client_golang/prometheus"
10
"github.com/prometheus/prometheus/model/labels"
11
"github.com/prometheus/prometheus/model/timestamp"
12
"github.com/prometheus/prometheus/tsdb/chunks"
13
"github.com/prometheus/prometheus/tsdb/record"
14
"github.com/prometheus/prometheus/tsdb/wlog"
15
"github.com/stretchr/testify/require"
16
)
17
18
func TestWALStats(t *testing.T) {
19
walDir := setupTestWAL(t)
20
stats, err := CalculateStats(walDir)
21
require.NoError(t, err)
22
23
// Test From, To separately since comparing time.Time objects can be flaky
24
require.Equal(t, int64(1), timestamp.FromTime(stats.From))
25
require.Equal(t, int64(20), timestamp.FromTime(stats.To))
26
27
require.Equal(t, WALStats{
28
From: stats.From,
29
To: stats.To,
30
CheckpointNumber: 1,
31
FirstSegment: 0,
32
LastSegment: 3,
33
HashCollisions: 1,
34
InvalidRefs: 1,
35
Targets: []WALTargetStats{{
36
Instance: "test-instance",
37
Job: "test-job",
38
Samples: 20,
39
Series: 21,
40
}},
41
}, stats)
42
}
43
44
// setupTestWAL creates a test WAL with consistent sample data.
45
// The WAL will be deleted when the test finishes.
46
//
47
// The directory the WAL is in is returned.
48
func setupTestWAL(t *testing.T) string {
49
l := log.NewNopLogger()
50
51
walDir := t.TempDir()
52
53
reg := prometheus.NewRegistry()
54
w, err := wlog.NewSize(log.NewNopLogger(), reg, filepath.Join(walDir, "wal"), wlog.DefaultSegmentSize, true)
55
require.NoError(t, err)
56
defer w.Close()
57
58
// First, create a few series of 10 metrics. Each metric will have a
59
// cardinality of 2, for a total of 20 series.
60
var series []record.RefSeries
61
addSeries := func(name string) {
62
baseLabels := []string{"__name__", name, "job", "test-job", "instance", "test-instance"}
63
labelsInitial := append(baseLabels, "initial", "yes")
64
labelsNotInitial := append(baseLabels, "initial", "no")
65
66
series = append(
67
series,
68
record.RefSeries{Ref: chunks.HeadSeriesRef(len(series)) + 1, Labels: labels.FromStrings(labelsInitial...)},
69
record.RefSeries{Ref: chunks.HeadSeriesRef(len(series)) + 2, Labels: labels.FromStrings(labelsNotInitial...)},
70
)
71
}
72
for i := 0; i < 10; i++ {
73
addSeries(fmt.Sprintf("metric_%d", i))
74
}
75
// Force in a duplicate hash
76
series = append(series, record.RefSeries{
77
Ref: 99,
78
Labels: labels.FromStrings("__name__", "metric_1", "job", "test-job", "instance", "test-instance", "initial", "yes"),
79
})
80
81
nextSegment := func(w *wlog.WL) error {
82
_, err := w.NextSegment()
83
return err
84
}
85
86
// Encode the samples to the WAL and create a new segment.
87
var encoder record.Encoder
88
buf := encoder.Series(series, nil)
89
err = w.Log(buf)
90
require.NoError(t, err)
91
require.NoError(t, nextSegment(w))
92
93
// Checkpoint the previous segment.
94
_, err = wlog.Checkpoint(l, w, 0, 1, func(_ chunks.HeadSeriesRef) bool { return true }, 0)
95
require.NoError(t, err)
96
require.NoError(t, nextSegment(w))
97
98
// Create some samples and then make a new segment.
99
var samples []record.RefSample
100
for i := 0; i < 20; i++ {
101
samples = append(samples, record.RefSample{
102
Ref: chunks.HeadSeriesRef(i + 1),
103
T: int64(i + 1),
104
V: 1,
105
})
106
}
107
// Force in an invalid ref
108
samples = append(samples, record.RefSample{Ref: 404, T: 1, V: 1})
109
110
buf = encoder.Samples(samples, nil)
111
err = w.Log(buf)
112
require.NoError(t, err)
113
require.NoError(t, nextSegment(w))
114
115
return w.Dir()
116
}
117
118