From 1db43792dbc2308747636f201649e6e7ede4ff6d Mon Sep 17 00:00:00 2001 From: beorn7 Date: Tue, 13 Nov 2018 15:48:48 +0100 Subject: [PATCH 1/2] Expose bug #494 Signed-off-by: beorn7 --- prometheus/testutil/testutil_test.go | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/prometheus/testutil/testutil_test.go b/prometheus/testutil/testutil_test.go index e25b130..0b8cf09 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. From 86702ea6b427ab178f0353345fc69cfd80b63d8f Mon Sep 17 00:00:00 2001 From: beorn7 Date: Tue, 13 Nov 2018 16:16:43 +0100 Subject: [PATCH 2/2] Fix metric comparison for empty labels reflect.DeepEqual is not suitable for zero occurrences of repeated proto messages. This changes the comparison to act on the string representation of proto messages. Signed-off-by: beorn7 --- prometheus/testutil/testutil.go | 57 ++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index d148af9..e7af303 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) - } - } - // 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) - } + if len(got) != len(want) { + return notMatchingError(got, want) + } + for i := range got { + if got[i].String() != want[i].String() { + return notMatchingError(got, want) } + } + return nil +} - return fmt.Errorf(` +// 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(` 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 {