Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
aos
GitHub Repository: aos/grafana-agent
Path: blob/main/component/phlare/scrape/scrape_loop_test.go
4096 views
1
package scrape
2
3
import (
4
"context"
5
"net/http"
6
"net/http/httptest"
7
"net/url"
8
"sort"
9
"strings"
10
"testing"
11
"time"
12
13
"github.com/grafana/agent/component/discovery"
14
"github.com/grafana/agent/component/phlare"
15
"github.com/grafana/agent/pkg/util"
16
"github.com/prometheus/common/model"
17
"github.com/prometheus/prometheus/discovery/targetgroup"
18
"github.com/prometheus/prometheus/model/labels"
19
"github.com/stretchr/testify/require"
20
"go.uber.org/atomic"
21
"go.uber.org/goleak"
22
)
23
24
func TestScrapePool(t *testing.T) {
25
defer goleak.VerifyNone(t, goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"))
26
27
args := NewDefaultArguments()
28
args.Targets = []discovery.Target{
29
{"instance": "foo"},
30
}
31
args.ProfilingConfig.Block.Enabled = false
32
args.ProfilingConfig.Goroutine.Enabled = false
33
args.ProfilingConfig.Memory.Enabled = false
34
35
p, err := newScrapePool(args, phlare.AppendableFunc(
36
func(ctx context.Context, labels labels.Labels, samples []*phlare.RawSample) error {
37
return nil
38
}),
39
util.TestLogger(t))
40
require.NoError(t, err)
41
42
defer p.stop()
43
44
for _, tt := range []struct {
45
name string
46
groups []*targetgroup.Group
47
expected []*Target
48
}{
49
{
50
name: "no targets",
51
groups: []*targetgroup.Group{},
52
expected: []*Target{},
53
},
54
{
55
name: "targets",
56
groups: []*targetgroup.Group{
57
{
58
Targets: []model.LabelSet{
59
{model.AddressLabel: "localhost:9090"},
60
{model.AddressLabel: "localhost:8080"},
61
},
62
Labels: model.LabelSet{"foo": "bar"},
63
},
64
},
65
expected: []*Target{
66
NewTarget(
67
labels.FromStrings("instance", "localhost:8080", "foo", "bar", model.AddressLabel, "localhost:8080", model.MetricNameLabel, pprofMutex, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/mutex"),
68
labels.FromStrings("foo", "bar", model.AddressLabel, "localhost:8080", model.MetricNameLabel, pprofMutex, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/mutex"),
69
url.Values{},
70
),
71
NewTarget(
72
labels.FromStrings("instance", "localhost:8080", "foo", "bar", model.AddressLabel, "localhost:8080", model.MetricNameLabel, pprofProcessCPU, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/profile"),
73
labels.FromStrings("foo", "bar", model.AddressLabel, "localhost:8080", model.MetricNameLabel, pprofProcessCPU, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/profile"),
74
url.Values{"seconds": []string{"14"}},
75
),
76
NewTarget(
77
labels.FromStrings("instance", "localhost:9090", "foo", "bar", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofMutex, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/mutex"),
78
labels.FromStrings("foo", "bar", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofMutex, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/mutex"),
79
url.Values{},
80
),
81
NewTarget(
82
labels.FromStrings("instance", "localhost:9090", "foo", "bar", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofProcessCPU, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/profile"),
83
labels.FromStrings("foo", "bar", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofProcessCPU, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/profile"),
84
url.Values{"seconds": []string{"14"}},
85
),
86
},
87
},
88
{
89
name: "Remove targets",
90
groups: []*targetgroup.Group{
91
{
92
Targets: []model.LabelSet{
93
{model.AddressLabel: "localhost:9090"},
94
},
95
},
96
},
97
expected: []*Target{
98
NewTarget(
99
labels.FromStrings("instance", "localhost:9090", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofMutex, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/mutex"),
100
labels.FromStrings(model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofMutex, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/mutex"),
101
url.Values{},
102
),
103
NewTarget(
104
labels.FromStrings("instance", "localhost:9090", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofProcessCPU, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/profile"),
105
labels.FromStrings(model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofProcessCPU, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/profile"),
106
url.Values{"seconds": []string{"14"}},
107
),
108
},
109
},
110
{
111
name: "Sync targets",
112
groups: []*targetgroup.Group{
113
{
114
Targets: []model.LabelSet{
115
{model.AddressLabel: "localhost:9090", "__type__": "foo"},
116
},
117
},
118
},
119
expected: []*Target{
120
NewTarget(
121
labels.FromStrings("instance", "localhost:9090", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofMutex, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/mutex"),
122
labels.FromStrings("__type__", "foo", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofMutex, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/mutex"),
123
url.Values{},
124
),
125
NewTarget(
126
labels.FromStrings("instance", "localhost:9090", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofProcessCPU, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/profile"),
127
labels.FromStrings("__type__", "foo", model.AddressLabel, "localhost:9090", model.MetricNameLabel, pprofProcessCPU, model.SchemeLabel, "http", ProfilePath, "/debug/pprof/profile"),
128
url.Values{"seconds": []string{"14"}},
129
),
130
},
131
},
132
} {
133
tt := tt
134
t.Run(tt.name, func(t *testing.T) {
135
p.sync(tt.groups)
136
actual := p.ActiveTargets()
137
sort.Sort(Targets(actual))
138
sort.Sort(Targets(tt.expected))
139
require.Equal(t, tt.expected, actual)
140
require.Empty(t, p.DroppedTargets())
141
})
142
}
143
144
// reload the cfg
145
args.ScrapeTimeout = 1 * time.Second
146
args.ScrapeInterval = 2 * time.Second
147
p.reload(args)
148
for _, ta := range p.activeTargets {
149
require.Equal(t, 1*time.Second, ta.timeout)
150
require.Equal(t, 2*time.Second, ta.interval)
151
}
152
}
153
154
func TestScrapeLoop(t *testing.T) {
155
defer goleak.VerifyNone(t, goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"))
156
157
down := atomic.NewBool(false)
158
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
159
// The test was failing on Windows, as the scrape loop was too fast for
160
// the Windows timer resolution.
161
// This used to lead the `t.lastScrapeDuration = time.Since(start)` to
162
// be recorded as zero. The small delay here allows the timer to record
163
// the time since the last scrape properly.
164
time.Sleep(2 * time.Millisecond)
165
if down.Load() {
166
w.WriteHeader(http.StatusInternalServerError)
167
}
168
w.Write([]byte("ok"))
169
}))
170
defer server.Close()
171
appendTotal := atomic.NewInt64(0)
172
173
loop := newScrapeLoop(
174
NewTarget(
175
labels.FromStrings(
176
model.SchemeLabel, "http",
177
model.AddressLabel, strings.TrimPrefix(server.URL, "http://"),
178
ProfilePath, "/debug/pprof/profile",
179
), labels.FromStrings(), url.Values{
180
"seconds": []string{"1"},
181
}),
182
server.Client(),
183
phlare.AppendableFunc(func(_ context.Context, labels labels.Labels, samples []*phlare.RawSample) error {
184
appendTotal.Inc()
185
require.Equal(t, []byte("ok"), samples[0].RawProfile)
186
return nil
187
}),
188
200*time.Millisecond, 30*time.Second, util.TestLogger(t))
189
defer loop.stop(true)
190
191
require.Equal(t, HealthUnknown, loop.Health())
192
loop.start()
193
require.Eventually(t, func() bool { return appendTotal.Load() > 3 }, 5000*time.Millisecond, 100*time.Millisecond)
194
require.Equal(t, HealthGood, loop.Health())
195
196
down.Store(true)
197
require.Eventually(t, func() bool {
198
return HealthBad == loop.Health()
199
}, time.Second, 100*time.Millisecond)
200
201
require.Error(t, loop.LastError())
202
require.WithinDuration(t, time.Now(), loop.LastScrape(), 1*time.Second)
203
require.NotEmpty(t, loop.LastScrapeDuration())
204
}
205
206