diff --git a/prometheus/testutil/testutil.go b/prometheus/testutil/testutil.go index 82d4a54..269f564 100644 --- a/prometheus/testutil/testutil.go +++ b/prometheus/testutil/testutil.go @@ -47,6 +47,7 @@ import ( "github.com/davecgh/go-spew/spew" dto "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" + "google.golang.org/protobuf/proto" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/internal" @@ -230,6 +231,20 @@ func convertReaderToMetricFamily(reader io.Reader) ([]*dto.MetricFamily, error) return nil, fmt.Errorf("converting reader to metric families failed: %w", err) } + // The text protocol handles empty help fields inconsistently. When + // encoding, any non-nil value, include the empty string, produces a + // "# HELP" line. But when decoding, the help field is only set to a + // non-nil value if the "# HELP" line contains a non-empty value. + // + // Because metrics in a registry always have non-nil help fields, populate + // any nil help fields in the parsed metrics with the empty string so that + // when we compare text encodings, the results are consistent. + for _, metric := range notNormalized { + if metric.Help == nil { + metric.Help = proto.String("") + } + } + return internal.NormalizeMetricFamilies(notNormalized), nil } diff --git a/prometheus/testutil/testutil_test.go b/prometheus/testutil/testutil_test.go index ab2fdb0..f2e1cba 100644 --- a/prometheus/testutil/testutil_test.go +++ b/prometheus/testutil/testutil_test.go @@ -168,6 +168,26 @@ func TestCollectAndCompareNoLabel(t *testing.T) { } } +func TestCollectAndCompareNoHelp(t *testing.T) { + const metadata = ` + # TYPE some_total counter + ` + + c := prometheus.NewCounter(prometheus.CounterOpts{ + Name: "some_total", + }) + 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 TestCollectAndCompareHistogram(t *testing.T) { inputs := []struct { name string