cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.10.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/promapi/range_test.go

332lines · modecode

1package promapi_test
2
3import (
4 "context"
5 "net/http"
6 "net/http/httptest"
7 "strconv"
8 "sync"
9 "testing"
10 "time"
11
12 "github.com/prometheus/common/model"
13 "github.com/stretchr/testify/assert"
14
15 "github.com/cloudflare/pint/internal/promapi"
16)
17
18func TestRange(t *testing.T) {
19 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
20 err := r.ParseForm()
21 if err != nil {
22 t.Fatal(err)
23 }
24 query := r.Form.Get("query")
25
26 switch query {
27 case "empty":
28 w.WriteHeader(200)
29 w.Header().Set("Content-Type", "application/json")
30 _, _ = w.Write([]byte(`{"status":"success","data":{"resultType":"matrix","result":[]}}`))
31 case "single_result":
32 w.WriteHeader(200)
33 w.Header().Set("Content-Type", "application/json")
34 _, _ = w.Write([]byte(`{"status":"success","data":{"resultType":"matrix","result":[
35 {"metric":{"instance":"1"},"values":[
36 [1614859502.068,"0"],
37 [1614859562.068,"1"],
38 [1614859622.068,"3"],
39 [1614859682.068,"4"],
40 [1614859742.068,"11"]
41 ]}
42 ]}}`))
43 case "vector":
44 w.WriteHeader(200)
45 w.Header().Set("Content-Type", "application/json")
46 _, _ = w.Write([]byte(`{
47 "status":"success",
48 "data":{
49 "resultType":"vector",
50 "result":[{"metric":{},"value":[1614859502.068,"1"]}]
51 }
52 }`))
53 case "slow":
54 w.WriteHeader(200)
55 time.Sleep(time.Second)
56 w.Header().Set("Content-Type", "application/json")
57 _, _ = w.Write([]byte(`{"status":"success","data":{"resultType":"matrix","result":[]}}`))
58 case "too_many_samples":
59 start, _ := strconv.ParseFloat(r.Form.Get("start"), 64)
60 end, _ := strconv.ParseFloat(r.Form.Get("end"), 64)
61 diff := time.Unix(int64(end), 0).Sub(time.Unix(int64(start), 0))
62 t.Log(diff.String())
63 switch diff.String() {
64 case "168h0m0s", "42h0m0s", "10h30m0s", "2h37m30s", "39m23s", "9m51s":
65 w.WriteHeader(422)
66 w.Header().Set("Content-Type", "application/json")
67 _, _ = w.Write([]byte(`{
68 "status":"error",
69 "errorType":"execution",
70 "error":"query processing would load too many samples into memory in query execution"
71 }`))
72 default:
73 t.Errorf("invalid too_many_samples diff: %s", diff)
74 w.WriteHeader(500)
75 w.Header().Set("Content-Type", "application/json")
76 _, _ = w.Write([]byte(`unknown start/end`))
77 }
78 case "retry_until_success":
79 start, _ := strconv.ParseFloat(r.Form.Get("start"), 64)
80 end, _ := strconv.ParseFloat(r.Form.Get("end"), 64)
81 diff := time.Unix(int64(end), 0).Sub(time.Unix(int64(start), 0))
82 t.Log(diff.String())
83 switch diff.String() {
84 case "168h0m0s", "42h0m0s", "10h30m0s", "2h37m30s":
85 w.WriteHeader(422)
86 w.Header().Set("Content-Type", "application/json")
87 _, _ = w.Write([]byte(`{
88 "status":"error",
89 "errorType":"execution",
90 "error":"query processing would load too many samples into memory in query execution"
91 }`))
92 case "39m23s":
93 w.WriteHeader(200)
94 w.Header().Set("Content-Type", "application/json")
95 _, _ = w.Write([]byte(`{"status":"success","data":{"resultType":"matrix","result":[
96 {"metric":{"instance":"1"},"values":[
97 [1614859502.068,"0"],
98 [1614859562.068,"1"],
99 [1614859622.068,"3"],
100 [1614859682.068,"4"],
101 [1614859742.068,"11"]
102 ]}
103 ]}}`))
104 default:
105 t.Errorf("invalid too_many_samples diff: %s", diff)
106 w.WriteHeader(500)
107 w.Header().Set("Content-Type", "application/json")
108 _, _ = w.Write([]byte(`unknown start/end`))
109 }
110 default:
111 w.WriteHeader(400)
112 w.Header().Set("Content-Type", "application/json")
113 _, _ = w.Write([]byte(`{"status":"error","errorType":"bad_data","error":"unhandled path"}`))
114 }
115 }))
116 defer srv.Close()
117
118 type argsFactory func() (time.Time, time.Time, time.Duration)
119
120 type testCaseT struct {
121 query string
122 args argsFactory
123 timeout time.Duration
124 samples []*model.SampleStream
125 err string
126 runs int
127 }
128
129 now := time.Now()
130
131 testCases := []testCaseT{
132 // cache hit
133 {
134 query: "empty",
135 args: func() (time.Time, time.Time, time.Duration) {
136 return now, now, time.Minute
137 },
138 timeout: time.Second,
139 samples: []*model.SampleStream{},
140 runs: 5,
141 },
142 // cache miss
143 {
144 query: "empty",
145 args: func() (time.Time, time.Time, time.Duration) {
146 return time.Now(), time.Now(), time.Minute
147 },
148 timeout: time.Second,
149 samples: []*model.SampleStream{},
150 runs: 5,
151 },
152 // cache hit
153 {
154 query: "single_result",
155 args: func() (time.Time, time.Time, time.Duration) {
156 return now, now, time.Minute
157 },
158 timeout: time.Second,
159 samples: []*model.SampleStream{
160 {
161 Metric: model.Metric{"instance": "1"},
162 Values: []model.SamplePair{
163 {Timestamp: 1614859502068, Value: 0},
164 {Timestamp: 1614859562068, Value: 1},
165 {Timestamp: 1614859622068, Value: 3},
166 {Timestamp: 1614859682068, Value: 4},
167 {Timestamp: 1614859742068, Value: 11},
168 },
169 },
170 },
171 runs: 5,
172 },
173 // cache miss
174 {
175 query: "single_result",
176 args: func() (time.Time, time.Time, time.Duration) {
177 return time.Now(), time.Now(), time.Minute
178 },
179 timeout: time.Second,
180 samples: []*model.SampleStream{
181 {
182 Metric: model.Metric{"instance": "1"},
183 Values: []model.SamplePair{
184 {Timestamp: 1614859502068, Value: 0},
185 {Timestamp: 1614859562068, Value: 1},
186 {Timestamp: 1614859622068, Value: 3},
187 {Timestamp: 1614859682068, Value: 4},
188 {Timestamp: 1614859742068, Value: 11},
189 },
190 },
191 },
192 runs: 5,
193 },
194 // cache hit
195 {
196 query: "error",
197 args: func() (time.Time, time.Time, time.Duration) {
198 return now, now, time.Minute
199 },
200 timeout: time.Second,
201 err: "bad_data: unhandled path",
202 runs: 5,
203 },
204 // cache miss
205 {
206 query: "error",
207 args: func() (time.Time, time.Time, time.Duration) {
208 return time.Now(), time.Now(), time.Minute
209 },
210 timeout: time.Second,
211 err: "bad_data: unhandled path",
212 runs: 5,
213 },
214 // cache hit
215 {
216 query: "vector",
217 args: func() (time.Time, time.Time, time.Duration) {
218 return now, now, time.Minute
219 },
220 timeout: time.Second,
221 err: "unknown result type: vector",
222 runs: 5,
223 },
224 // cache miss
225 {
226 query: "vector",
227 args: func() (time.Time, time.Time, time.Duration) {
228 return time.Now(), time.Now(), time.Minute
229 },
230 timeout: time.Second,
231 err: "unknown result type: vector",
232 runs: 5,
233 },
234 // give up after all the retries
235 {
236 query: "too_many_samples",
237 args: func() (time.Time, time.Time, time.Duration) {
238 start := time.Unix(1577836800, 0)
239 end := time.Unix(1578441600, 0)
240 return start, end, time.Minute * 5
241 },
242 timeout: time.Second,
243 err: "no more retries possible",
244 runs: 5,
245 },
246 // retry timeouts
247 {
248 query: "slow",
249 args: func() (time.Time, time.Time, time.Duration) {
250 start := time.Unix(1577836800, 0)
251 end := time.Unix(1578441600, 0)
252 return start, end, time.Minute * 5
253 },
254 timeout: time.Millisecond * 20,
255 err: "no more retries possible",
256 runs: 5,
257 },
258 // cache hit
259 {
260 query: "retry_until_success",
261 args: func() (time.Time, time.Time, time.Duration) {
262 start := time.Unix(1577836800, 0)
263 end := time.Unix(1578441600, 0)
264 return start, end, time.Minute * 5
265 },
266 timeout: time.Second,
267 samples: []*model.SampleStream{
268 {
269 Metric: model.Metric{"instance": "1"},
270 Values: []model.SamplePair{
271 {Timestamp: 1614859502068, Value: 0},
272 {Timestamp: 1614859562068, Value: 1},
273 {Timestamp: 1614859622068, Value: 3},
274 {Timestamp: 1614859682068, Value: 4},
275 {Timestamp: 1614859742068, Value: 11},
276 },
277 },
278 },
279 runs: 5,
280 },
281 // cache miss
282 {
283 query: "retry_until_success",
284 args: func() (time.Time, time.Time, time.Duration) {
285 start := time.Unix(1577836800, 0)
286 end := time.Unix(1578441600, 0)
287 return start, end, time.Minute * 5
288 },
289 timeout: time.Second,
290 samples: []*model.SampleStream{
291 {
292 Metric: model.Metric{"instance": "1"},
293 Values: []model.SamplePair{
294 {Timestamp: 1614859502068, Value: 0},
295 {Timestamp: 1614859562068, Value: 1},
296 {Timestamp: 1614859622068, Value: 3},
297 {Timestamp: 1614859682068, Value: 4},
298 {Timestamp: 1614859742068, Value: 11},
299 },
300 },
301 },
302 runs: 5,
303 },
304 }
305
306 for _, tc := range testCases {
307 t.Run(tc.query, func(t *testing.T) {
308 assert := assert.New(t)
309
310 prom := promapi.NewPrometheus("test", srv.URL, tc.timeout)
311
312 wg := sync.WaitGroup{}
313 wg.Add(tc.runs)
314 for i := 1; i <= tc.runs; i++ {
315 go func() {
316 start, end, step := tc.args()
317 qr, err := prom.RangeQuery(context.Background(), tc.query, start, end, step)
318 if tc.err != "" {
319 assert.EqualError(err, tc.err, tc)
320 } else {
321 assert.NoError(err)
322 }
323 if qr != nil {
324 assert.Equal(qr.Samples, tc.samples, tc)
325 }
326 wg.Done()
327 }()
328 }
329 wg.Wait()
330 })
331 }
332}
333