diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index d148af9b8..e7af303e6 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -37,7 +37,6 @@ import ( "bytes" "fmt" "io" - "reflect" "github.com/prometheus/common/expfmt" @@ -125,39 +124,49 @@ func CollectAndCompare(c prometheus.Collector, expected io.Reader, metricNames . // exposition format. If any metricNames are provided, only metrics with those // names are compared. func GatherAndCompare(g prometheus.Gatherer, expected io.Reader, metricNames ...string) error { - metrics, err := g.Gather() + got, err := g.Gather() if err != nil { return fmt.Errorf("gathering metrics failed: %s", err) } if metricNames != nil { - metrics = filterMetrics(metrics, metricNames) + got = filterMetrics(got, metricNames) } var tp expfmt.TextParser - expectedMetrics, err := tp.TextToMetricFamilies(expected) + wantRaw, err := tp.TextToMetricFamilies(expected) if err != nil { return fmt.Errorf("parsing expected metrics failed: %s", err) } + want := internal.NormalizeMetricFamilies(wantRaw) - if !reflect.DeepEqual(metrics, internal.NormalizeMetricFamilies(expectedMetrics)) { - // Encode the gathered output to the readable text format for comparison. - var buf1 bytes.Buffer - enc := expfmt.NewEncoder(&buf1, expfmt.FmtText) - for _, mf := range metrics { - if err := enc.Encode(mf); err != nil { - return fmt.Errorf("encoding result failed: %s", err) - } + if len(got) != len(want) { + return notMatchingError(got, want) + } + for i := range got { + if got[i].String() != want[i].String() { + return notMatchingError(got, want) } - // Encode normalized expected metrics again to generate them in the same ordering - // the registry does to spot differences more easily. - var buf2 bytes.Buffer - enc = expfmt.NewEncoder(&buf2, expfmt.FmtText) - for _, mf := range internal.NormalizeMetricFamilies(expectedMetrics) { - if err := enc.Encode(mf); err != nil { - return fmt.Errorf("encoding result failed: %s", err) - } + } + return nil +} + +// notMatchingError encodes both provided slices of metric families into the +// text format and creates a readable error message from the result. +func notMatchingError(got, want []*dto.MetricFamily) error { + var gotBuf, wantBuf bytes.Buffer + enc := expfmt.NewEncoder(&gotBuf, expfmt.FmtText) + for _, mf := range got { + if err := enc.Encode(mf); err != nil { + return fmt.Errorf("encoding gathered metrics failed: %s", err) + } + } + enc = expfmt.NewEncoder(&wantBuf, expfmt.FmtText) + for _, mf := range want { + if err := enc.Encode(mf); err != nil { + return fmt.Errorf("encoding expected metrics failed: %s", err) } + } - return fmt.Errorf(` + return fmt.Errorf(` metric output does not match expectation; want: %s @@ -165,9 +174,7 @@ metric output does not match expectation; want: got: %s -`, buf2.String(), buf1.String()) - } - return nil +`, wantBuf.String(), gotBuf.String()) } func filterMetrics(metrics []*dto.MetricFamily, names []string) []*dto.MetricFamily { diff --git a/prometheus/testutil/testutil_test.go b/prometheus/testutil/testutil_test.go index e25b1306f..0b8cf0934 100644 --- a/prometheus/testutil/testutil_test.go +++ b/prometheus/testutil/testutil_test.go @@ -143,6 +143,28 @@ func TestCollectAndCompare(t *testing.T) { } } +func TestCollectAndCompareNoLabel(t *testing.T) { + const metadata = ` + # HELP some_total A value that represents a counter. + # TYPE some_total counter + ` + + c := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "some_total", + Help: "A value that represents a counter.", + }) + c.Inc() + + expected := ` + + some_total 1 + ` + + if err := CollectAndCompare(c, strings.NewReader(metadata+expected), "some_total"); err != nil { + t.Errorf("unexpected collecting result:\n%s", err) + } +} + func TestNoMetricFilter(t *testing.T) { const metadata = ` # HELP some_total A value that represents a counter.