Skip to content

Commit c7c7509

Browse files
testutil compareMetricFamilies: make less error-prone (prometheus#1424)
* testutil compareMetricFamilies: make less error-prone The functions `GatherAndCompare`, `ScrapeAndCompare` and others that use `compareMetricFamilies` under the hood can return no error if `metricNames` includes none of the names found in the scraped/gathered results. To avoid false Positves (an error being the negative case), we can return an error if there is is at least one name in `metricNames` that is not in the filtered results. Fixes: prometheus#1351 Signed-off-by: leonnicolas <[email protected]> * Add missing metricNames to error In to see which metric names are missing, we can add them to the error message. Signed-off-by: leonnicolas <[email protected]> * Apply suggestions from code review - remove if nil check - use two nested loops instead of map - use new function `hasMetricByName` for readability Co-authored-by: Bartlomiej Plotka <[email protected]> Signed-off-by: leonnicolas <[email protected]> * prometheus/testutil/testutil_test.go: compare complete error Before we would only compare the error prefix in `TestScrapeAndCompare`. Signed-off-by: leonnicolas <[email protected]> --------- Signed-off-by: leonnicolas <[email protected]> Signed-off-by: leonnicolas <[email protected]> Co-authored-by: Bartlomiej Plotka <[email protected]>
1 parent 36b9f46 commit c7c7509

File tree

2 files changed

+108
-46
lines changed

2 files changed

+108
-46
lines changed

prometheus/testutil/testutil.go

+18
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,15 @@ func compareMetricFamilies(got, expected []*dto.MetricFamily, metricNames ...str
277277
if metricNames != nil {
278278
got = filterMetrics(got, metricNames)
279279
expected = filterMetrics(expected, metricNames)
280+
if len(metricNames) > len(got) {
281+
var missingMetricNames []string
282+
for _, name := range metricNames {
283+
if ok := hasMetricByName(got, name); !ok {
284+
missingMetricNames = append(missingMetricNames, name)
285+
}
286+
}
287+
return fmt.Errorf("expected metric name(s) not found: %v", missingMetricNames)
288+
}
280289
}
281290

282291
return compare(got, expected)
@@ -318,3 +327,12 @@ func filterMetrics(metrics []*dto.MetricFamily, names []string) []*dto.MetricFam
318327
}
319328
return filtered
320329
}
330+
331+
func hasMetricByName(metrics []*dto.MetricFamily, name string) bool {
332+
for _, mf := range metrics {
333+
if mf.GetName() == name {
334+
return true
335+
}
336+
}
337+
return false
338+
}

prometheus/testutil/testutil_test.go

+90-46
Original file line numberDiff line numberDiff line change
@@ -328,27 +328,46 @@ func TestMetricNotFound(t *testing.T) {
328328
}
329329

330330
func TestScrapeAndCompare(t *testing.T) {
331-
const expected = `
331+
scenarios := map[string]struct {
332+
want string
333+
metricNames []string
334+
// expectedErr if empty, means no fail is expected for the comparison.
335+
expectedErr string
336+
}{
337+
"empty metric Names": {
338+
want: `
332339
# HELP some_total A value that represents a counter.
333340
# TYPE some_total counter
334341
335342
some_total{ label1 = "value1" } 1
336-
`
343+
`,
344+
metricNames: []string{},
345+
},
346+
"one metric": {
347+
want: `
348+
# HELP some_total A value that represents a counter.
349+
# TYPE some_total counter
337350
338-
expectedReader := strings.NewReader(expected)
351+
some_total{ label1 = "value1" } 1
352+
`,
353+
metricNames: []string{"some_total"},
354+
},
355+
"multiple expected": {
356+
want: `
357+
# HELP some_total A value that represents a counter.
358+
# TYPE some_total counter
339359
340-
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
341-
fmt.Fprintln(w, expected)
342-
}))
343-
defer ts.Close()
360+
some_total{ label1 = "value1" } 1
344361
345-
if err := ScrapeAndCompare(ts.URL, expectedReader, "some_total"); err != nil {
346-
t.Errorf("unexpected scraping result:\n%s", err)
347-
}
348-
}
362+
# HELP some_total2 A value that represents a counter.
363+
# TYPE some_total2 counter
349364
350-
func TestScrapeAndCompareWithMultipleExpected(t *testing.T) {
351-
const expected = `
365+
some_total2{ label2 = "value2" } 1
366+
`,
367+
metricNames: []string{"some_total2"},
368+
},
369+
"expected metric name is not scraped": {
370+
want: `
352371
# HELP some_total A value that represents a counter.
353372
# TYPE some_total counter
354373
@@ -358,53 +377,78 @@ func TestScrapeAndCompareWithMultipleExpected(t *testing.T) {
358377
# TYPE some_total2 counter
359378
360379
some_total2{ label2 = "value2" } 1
361-
`
362-
363-
expectedReader := strings.NewReader(expected)
380+
`,
381+
metricNames: []string{"some_total3"},
382+
expectedErr: "expected metric name(s) not found: [some_total3]",
383+
},
384+
"one of multiple expected metric names is not scraped": {
385+
want: `
386+
# HELP some_total A value that represents a counter.
387+
# TYPE some_total counter
364388
365-
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
366-
fmt.Fprintln(w, expected)
367-
}))
368-
defer ts.Close()
389+
some_total{ label1 = "value1" } 1
369390
370-
if err := ScrapeAndCompare(ts.URL, expectedReader, "some_total2"); err != nil {
371-
t.Errorf("unexpected scraping result:\n%s", err)
372-
}
373-
}
391+
# HELP some_total2 A value that represents a counter.
392+
# TYPE some_total2 counter
374393
375-
func TestScrapeAndCompareFetchingFail(t *testing.T) {
376-
err := ScrapeAndCompare("some_url", strings.NewReader("some expectation"), "some_total")
377-
if err == nil {
378-
t.Errorf("expected an error but got nil")
394+
some_total2{ label2 = "value2" } 1
395+
`,
396+
metricNames: []string{"some_total1", "some_total3"},
397+
expectedErr: "expected metric name(s) not found: [some_total1 some_total3]",
398+
},
379399
}
380-
if !strings.HasPrefix(err.Error(), "scraping metrics failed") {
381-
t.Errorf("unexpected error happened: %s", err)
400+
for name, scenario := range scenarios {
401+
t.Run(name, func(t *testing.T) {
402+
expectedReader := strings.NewReader(scenario.want)
403+
404+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
405+
fmt.Fprintln(w, scenario.want)
406+
}))
407+
defer ts.Close()
408+
if err := ScrapeAndCompare(ts.URL, expectedReader, scenario.metricNames...); err != nil {
409+
if scenario.expectedErr == "" || err.Error() != scenario.expectedErr {
410+
t.Errorf("unexpected error happened: %s", err)
411+
}
412+
} else if scenario.expectedErr != "" {
413+
t.Errorf("expected an error but got nil")
414+
}
415+
})
382416
}
383-
}
384417

385-
func TestScrapeAndCompareBadStatusCode(t *testing.T) {
386-
const expected = `
418+
t.Run("fetching fail", func(t *testing.T) {
419+
err := ScrapeAndCompare("some_url", strings.NewReader("some expectation"), "some_total")
420+
if err == nil {
421+
t.Errorf("expected an error but got nil")
422+
}
423+
if !strings.HasPrefix(err.Error(), "scraping metrics failed") {
424+
t.Errorf("unexpected error happened: %s", err)
425+
}
426+
})
427+
428+
t.Run("bad status code", func(t *testing.T) {
429+
const expected = `
387430
# HELP some_total A value that represents a counter.
388431
# TYPE some_total counter
389432
390433
some_total{ label1 = "value1" } 1
391434
`
392435

393-
expectedReader := strings.NewReader(expected)
436+
expectedReader := strings.NewReader(expected)
394437

395-
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
396-
w.WriteHeader(http.StatusBadGateway)
397-
fmt.Fprintln(w, expected)
398-
}))
399-
defer ts.Close()
438+
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
439+
w.WriteHeader(http.StatusBadGateway)
440+
fmt.Fprintln(w, expected)
441+
}))
442+
defer ts.Close()
400443

401-
err := ScrapeAndCompare(ts.URL, expectedReader, "some_total")
402-
if err == nil {
403-
t.Errorf("expected an error but got nil")
404-
}
405-
if !strings.HasPrefix(err.Error(), "the scraping target returned a status code other than 200") {
406-
t.Errorf("unexpected error happened: %s", err)
407-
}
444+
err := ScrapeAndCompare(ts.URL, expectedReader, "some_total")
445+
if err == nil {
446+
t.Errorf("expected an error but got nil")
447+
}
448+
if !strings.HasPrefix(err.Error(), "the scraping target returned a status code other than 200") {
449+
t.Errorf("unexpected error happened: %s", err)
450+
}
451+
})
408452
}
409453

410454
func TestCollectAndCount(t *testing.T) {

0 commit comments

Comments
 (0)