From c61e654cd492385ed602a4f5b9b37e1b890c74a7 Mon Sep 17 00:00:00 2001 From: Bruno Rafael Date: Tue, 6 Apr 2021 20:40:12 -0300 Subject: [PATCH] Refactor prometheus exporter tests to match file headers as well (#1470) Co-authored-by: Tyler Yahn --- .../metric/prometheus/prometheus_test.go | 120 +++++++++++------- 1 file changed, 72 insertions(+), 48 deletions(-) diff --git a/exporters/metric/prometheus/prometheus_test.go b/exporters/metric/prometheus/prometheus_test.go index 58edce70996..1c4d895b5e2 100644 --- a/exporters/metric/prometheus/prometheus_test.go +++ b/exporters/metric/prometheus/prometheus_test.go @@ -15,10 +15,8 @@ package prometheus_test import ( - "bytes" "context" - "io/ioutil" - "net/http" + "fmt" "net/http/httptest" "sort" "strings" @@ -33,11 +31,54 @@ import ( "go.opentelemetry.io/otel/sdk/resource" ) +type expectedMetric struct { + kind string + name string + help string + values []string +} + +func (e *expectedMetric) lines() []string { + ret := []string{ + fmt.Sprintf("# HELP %s %s", e.name, e.help), + fmt.Sprintf("# TYPE %s %s", e.name, e.kind), + } + + ret = append(ret, e.values...) + + return ret +} + +func expectCounterWithHelp(name, help, value string) expectedMetric { + return expectedMetric{ + kind: "counter", + name: name, + help: help, + values: []string{value}, + } +} + +func expectCounter(name, value string) expectedMetric { + return expectCounterWithHelp(name, "", value) +} + +func expectGauge(name, value string) expectedMetric { + return expectedMetric{ + kind: "gauge", + name: name, + values: []string{value}, + } +} + +func expectHistogram(name string, values ...string) expectedMetric { + return expectedMetric{ + kind: "histogram", + name: name, + values: values, + } +} + func TestPrometheusExporter(t *testing.T) { - // #TODO: This test does not adequately verify the type of - // prometheus metric exported for all types - for example, - // it does not verify that an UpDown- counter is exported - // as a gauge. To be improved. exporter, err := prometheus.NewExportPipeline( prometheus.Config{ DefaultHistogramBoundaries: []float64{-0.5, 1}, @@ -58,40 +99,42 @@ func TestPrometheusExporter(t *testing.T) { } ctx := context.Background() - var expected []string + var expected []expectedMetric counter.Add(ctx, 10, labels...) counter.Add(ctx, 5.3, labels...) - expected = append(expected, `counter{A="B",C="D",R="V"} 15.3`) + expected = append(expected, expectCounter("counter", `counter{A="B",C="D",R="V"} 15.3`)) _ = metric.Must(meter).NewInt64ValueObserver("intobserver", func(_ context.Context, result metric.Int64ObserverResult) { result.Observe(1, labels...) }) - expected = append(expected, `intobserver{A="B",C="D",R="V"} 1`) + expected = append(expected, expectGauge("intobserver", `intobserver{A="B",C="D",R="V"} 1`)) valuerecorder.Record(ctx, -0.6, labels...) valuerecorder.Record(ctx, -0.4, labels...) valuerecorder.Record(ctx, 0.6, labels...) valuerecorder.Record(ctx, 20, labels...) - expected = append(expected, `valuerecorder_bucket{A="B",C="D",R="V",le="+Inf"} 4`) - expected = append(expected, `valuerecorder_bucket{A="B",C="D",R="V",le="-0.5"} 1`) - expected = append(expected, `valuerecorder_bucket{A="B",C="D",R="V",le="1"} 3`) - expected = append(expected, `valuerecorder_count{A="B",C="D",R="V"} 4`) - expected = append(expected, `valuerecorder_sum{A="B",C="D",R="V"} 19.6`) + expected = append(expected, expectHistogram("valuerecorder", + `valuerecorder_bucket{A="B",C="D",R="V",le="-0.5"} 1`, + `valuerecorder_bucket{A="B",C="D",R="V",le="1"} 3`, + `valuerecorder_bucket{A="B",C="D",R="V",le="+Inf"} 4`, + `valuerecorder_sum{A="B",C="D",R="V"} 19.6`, + `valuerecorder_count{A="B",C="D",R="V"} 4`, + )) upDownCounter.Add(ctx, 10, labels...) upDownCounter.Add(ctx, -3.2, labels...) - expected = append(expected, `updowncounter{A="B",C="D",R="V"} 6.8`) + expected = append(expected, expectGauge("updowncounter", `updowncounter{A="B",C="D",R="V"} 6.8`)) compareExport(t, exporter, expected) compareExport(t, exporter, expected) } -func compareExport(t *testing.T, exporter *prometheus.Exporter, expected []string) { +func compareExport(t *testing.T, exporter *prometheus.Exporter, expected []expectedMetric) { rec := httptest.NewRecorder() req := httptest.NewRequest("GET", "/metrics", nil) exporter.ServeHTTP(rec, req) @@ -99,17 +142,15 @@ func compareExport(t *testing.T, exporter *prometheus.Exporter, expected []strin output := rec.Body.String() lines := strings.Split(output, "\n") - var metricsOnly []string - for _, line := range lines { - if !strings.HasPrefix(line, "#") && line != "" { - metricsOnly = append(metricsOnly, line) - } + expectedLines := []string{""} + for _, v := range expected { + expectedLines = append(expectedLines, v.lines()...) } - sort.Strings(metricsOnly) - sort.Strings(expected) + sort.Strings(lines) + sort.Strings(expectedLines) - require.Equal(t, strings.Join(expected, "\n"), strings.Join(metricsOnly, "\n")) + require.Equal(t, expectedLines, lines) } func TestPrometheusStatefulness(t *testing.T) { @@ -123,20 +164,6 @@ func TestPrometheusStatefulness(t *testing.T) { meter := exporter.MeterProvider().Meter("test") - // GET the HTTP endpoint - scrape := func() string { - var input bytes.Buffer - resp := httptest.NewRecorder() - req, err := http.NewRequest("GET", "/", &input) - require.NoError(t, err) - - exporter.ServeHTTP(resp, req) - data, err := ioutil.ReadAll(resp.Result().Body) - require.NoError(t, err) - - return string(data) - } - ctx := context.Background() counter := metric.Must(meter).NewInt64Counter( @@ -146,16 +173,13 @@ func TestPrometheusStatefulness(t *testing.T) { counter.Add(ctx, 100, attribute.String("key", "value")) - require.Equal(t, `# HELP a_counter Counts things -# TYPE a_counter counter -a_counter{key="value"} 100 -`, scrape()) + compareExport(t, exporter, []expectedMetric{ + expectCounterWithHelp("a_counter", "Counts things", `a_counter{key="value"} 100`), + }) counter.Add(ctx, 100, attribute.String("key", "value")) - require.Equal(t, `# HELP a_counter Counts things -# TYPE a_counter counter -a_counter{key="value"} 200 -`, scrape()) - + compareExport(t, exporter, []expectedMetric{ + expectCounterWithHelp("a_counter", "Counts things", `a_counter{key="value"} 200`), + }) }