// Copyright 2018 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package testutil import ( "strings" "testing" "github.com/prometheus/client_golang/prometheus" ) type untypedCollector struct{} func (u untypedCollector) Describe(c chan<- *prometheus.Desc) { c <- prometheus.NewDesc("name", "help", nil, nil) } func (u untypedCollector) Collect(c chan<- prometheus.Metric) { c <- prometheus.MustNewConstMetric( prometheus.NewDesc("name", "help", nil, nil), prometheus.UntypedValue, 2001, ) } func TestToFloat64(t *testing.T) { gaugeWithAValueSet := prometheus.NewGauge(prometheus.GaugeOpts{}) gaugeWithAValueSet.Set(3.14) counterVecWithOneElement := prometheus.NewCounterVec(prometheus.CounterOpts{}, []string{"foo"}) counterVecWithOneElement.WithLabelValues("bar").Inc() counterVecWithTwoElements := prometheus.NewCounterVec(prometheus.CounterOpts{}, []string{"foo"}) counterVecWithTwoElements.WithLabelValues("bar").Add(42) counterVecWithTwoElements.WithLabelValues("baz").Inc() histogramVecWithOneElement := prometheus.NewHistogramVec(prometheus.HistogramOpts{}, []string{"foo"}) histogramVecWithOneElement.WithLabelValues("bar").Observe(2.7) scenarios := map[string]struct { collector prometheus.Collector panics bool want float64 }{ "simple counter": { collector: prometheus.NewCounter(prometheus.CounterOpts{}), panics: false, want: 0, }, "simple gauge": { collector: prometheus.NewGauge(prometheus.GaugeOpts{}), panics: false, want: 0, }, "simple untyped": { collector: untypedCollector{}, panics: false, want: 2001, }, "simple histogram": { collector: prometheus.NewHistogram(prometheus.HistogramOpts{}), panics: true, }, "simple summary": { collector: prometheus.NewSummary(prometheus.SummaryOpts{}), panics: true, }, "simple gauge with an actual value set": { collector: gaugeWithAValueSet, panics: false, want: 3.14, }, "counter vec with zero elements": { collector: prometheus.NewCounterVec(prometheus.CounterOpts{}, nil), panics: true, }, "counter vec with one element": { collector: counterVecWithOneElement, panics: false, want: 1, }, "counter vec with two elements": { collector: counterVecWithTwoElements, panics: true, }, "histogram vec with one element": { collector: histogramVecWithOneElement, panics: true, }, } for n, s := range scenarios { t.Run(n, func(t *testing.T) { defer func() { r := recover() if r == nil && s.panics { t.Error("expected panic") } else if r != nil && !s.panics { t.Error("unexpected panic: ", r) } // Any other combination is the expected outcome. }() if got := ToFloat64(s.collector); got != s.want { t.Errorf("want %f, got %f", s.want, got) } }) } } func TestCollectAndCompare(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.", ConstLabels: prometheus.Labels{ "label1": "value1", }, }) c.Inc() expected := ` some_total{ label1 = "value1" } 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. # TYPE some_total counter ` c := prometheus.NewCounter(prometheus.CounterOpts{ Name: "some_total", Help: "A value that represents a counter.", ConstLabels: prometheus.Labels{ "label1": "value1", }, }) c.Inc() expected := ` some_total{label1="value1"} 1 ` if err := CollectAndCompare(c, strings.NewReader(metadata+expected)); err != nil { t.Errorf("unexpected collecting result:\n%s", err) } } func TestMetricNotFound(t *testing.T) { const metadata = ` # HELP some_other_metric A value that represents a counter. # TYPE some_other_metric counter ` c := prometheus.NewCounter(prometheus.CounterOpts{ Name: "some_total", Help: "A value that represents a counter.", ConstLabels: prometheus.Labels{ "label1": "value1", }, }) c.Inc() expected := ` some_other_metric{label1="value1"} 1 ` expectedError := ` metric output does not match expectation; want: # HELP some_other_metric A value that represents a counter. # TYPE some_other_metric counter some_other_metric{label1="value1"} 1 got: # HELP some_total A value that represents a counter. # TYPE some_total counter some_total{label1="value1"} 1 ` err := CollectAndCompare(c, strings.NewReader(metadata+expected)) if err == nil { t.Error("Expected error, got no error.") } if err.Error() != expectedError { t.Errorf("Expected\n%#+v\nGot:\n%#+v\n", expectedError, err.Error()) } }