mirror of https://github.com/prometheus/prometheus
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
299 lines
9.0 KiB
299 lines
9.0 KiB
// Copyright 2024 Prometheus Team
|
|
// 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 rwcommon
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/prometheus/common/model"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/prometheus/prometheus/model/histogram"
|
|
"github.com/prometheus/prometheus/model/labels"
|
|
"github.com/prometheus/prometheus/model/metadata"
|
|
"github.com/prometheus/prometheus/prompb"
|
|
writev2 "github.com/prometheus/prometheus/prompb/io/prometheus/write/v2"
|
|
)
|
|
|
|
func TestToLabels(t *testing.T) {
|
|
expected := labels.FromStrings("__name__", "metric1", "foo", "bar")
|
|
|
|
t.Run("v1", func(t *testing.T) {
|
|
ts := prompb.TimeSeries{Labels: []prompb.Label{{Name: "__name__", Value: "metric1"}, {Name: "foo", Value: "bar"}}}
|
|
b := labels.NewScratchBuilder(2)
|
|
require.Equal(t, expected, ts.ToLabels(&b, nil))
|
|
require.Equal(t, ts.Labels, prompb.FromLabels(expected, nil))
|
|
require.Equal(t, ts.Labels, prompb.FromLabels(expected, ts.Labels))
|
|
})
|
|
t.Run("v2", func(t *testing.T) {
|
|
v2Symbols := []string{"", "__name__", "metric1", "foo", "bar"}
|
|
ts := writev2.TimeSeries{LabelsRefs: []uint32{1, 2, 3, 4}}
|
|
b := labels.NewScratchBuilder(2)
|
|
require.Equal(t, expected, ts.ToLabels(&b, v2Symbols))
|
|
// No need for FromLabels in our prod code as we use symbol table to do so.
|
|
})
|
|
}
|
|
|
|
func TestFromMetadataType(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
desc string
|
|
input model.MetricType
|
|
expectedV1 prompb.MetricMetadata_MetricType
|
|
expectedV2 writev2.Metadata_MetricType
|
|
}{
|
|
{
|
|
desc: "with a single-word metric",
|
|
input: model.MetricTypeCounter,
|
|
expectedV1: prompb.MetricMetadata_COUNTER,
|
|
expectedV2: writev2.Metadata_METRIC_TYPE_COUNTER,
|
|
},
|
|
{
|
|
desc: "with a two-word metric",
|
|
input: model.MetricTypeStateset,
|
|
expectedV1: prompb.MetricMetadata_STATESET,
|
|
expectedV2: writev2.Metadata_METRIC_TYPE_STATESET,
|
|
},
|
|
{
|
|
desc: "with an unknown metric",
|
|
input: "not-known",
|
|
expectedV1: prompb.MetricMetadata_UNKNOWN,
|
|
expectedV2: writev2.Metadata_METRIC_TYPE_UNSPECIFIED,
|
|
},
|
|
} {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
t.Run("v1", func(t *testing.T) {
|
|
require.Equal(t, tc.expectedV1, prompb.FromMetadataType(tc.input))
|
|
})
|
|
t.Run("v2", func(t *testing.T) {
|
|
require.Equal(t, tc.expectedV2, writev2.FromMetadataType(tc.input))
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestToMetadata(t *testing.T) {
|
|
sym := writev2.NewSymbolTable()
|
|
|
|
for _, tc := range []struct {
|
|
input writev2.Metadata
|
|
expected metadata.Metadata
|
|
}{
|
|
{
|
|
input: writev2.Metadata{},
|
|
expected: metadata.Metadata{
|
|
Type: model.MetricTypeUnknown,
|
|
},
|
|
},
|
|
{
|
|
input: writev2.Metadata{
|
|
Type: 12414, // Unknown.
|
|
},
|
|
expected: metadata.Metadata{
|
|
Type: model.MetricTypeUnknown,
|
|
},
|
|
},
|
|
{
|
|
input: writev2.Metadata{
|
|
Type: writev2.Metadata_METRIC_TYPE_COUNTER,
|
|
HelpRef: sym.Symbolize("help1"),
|
|
UnitRef: sym.Symbolize("unit1"),
|
|
},
|
|
expected: metadata.Metadata{
|
|
Type: model.MetricTypeCounter,
|
|
Help: "help1",
|
|
Unit: "unit1",
|
|
},
|
|
},
|
|
{
|
|
input: writev2.Metadata{
|
|
Type: writev2.Metadata_METRIC_TYPE_STATESET,
|
|
HelpRef: sym.Symbolize("help2"),
|
|
},
|
|
expected: metadata.Metadata{
|
|
Type: model.MetricTypeStateset,
|
|
Help: "help2",
|
|
},
|
|
},
|
|
} {
|
|
t.Run("", func(t *testing.T) {
|
|
ts := writev2.TimeSeries{Metadata: tc.input}
|
|
require.Equal(t, tc.expected, ts.ToMetadata(sym.Symbols()))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestToHistogram_Empty(t *testing.T) {
|
|
t.Run("v1", func(t *testing.T) {
|
|
require.NotNilf(t, prompb.Histogram{}.ToIntHistogram(), "")
|
|
require.NotNilf(t, prompb.Histogram{}.ToFloatHistogram(), "")
|
|
})
|
|
t.Run("v2", func(t *testing.T) {
|
|
require.NotNilf(t, writev2.Histogram{}.ToIntHistogram(), "")
|
|
require.NotNilf(t, writev2.Histogram{}.ToFloatHistogram(), "")
|
|
})
|
|
}
|
|
|
|
// NOTE(bwplotka): This is technically not a valid histogram, but it represents
|
|
// important cases to test when copying or converting to/from int/float histograms.
|
|
func testIntHistogram() histogram.Histogram {
|
|
return histogram.Histogram{
|
|
CounterResetHint: histogram.GaugeType,
|
|
Schema: 1,
|
|
Count: 19,
|
|
Sum: 2.7,
|
|
ZeroThreshold: 1e-128,
|
|
PositiveSpans: []histogram.Span{
|
|
{Offset: 0, Length: 4},
|
|
{Offset: 0, Length: 0},
|
|
{Offset: 0, Length: 3},
|
|
},
|
|
PositiveBuckets: []int64{1, 2, -2, 1, -1, 0, 0},
|
|
NegativeSpans: []histogram.Span{
|
|
{Offset: 0, Length: 5},
|
|
{Offset: 1, Length: 0},
|
|
{Offset: 0, Length: 1},
|
|
},
|
|
NegativeBuckets: []int64{1, 2, -2, 1, -1, 0},
|
|
CustomValues: []float64{21421, 523},
|
|
}
|
|
}
|
|
|
|
// NOTE(bwplotka): This is technically not a valid histogram, but it represents
|
|
// important cases to test when copying or converting to/from int/float histograms.
|
|
func testFloatHistogram() histogram.FloatHistogram {
|
|
return histogram.FloatHistogram{
|
|
CounterResetHint: histogram.GaugeType,
|
|
Schema: 1,
|
|
Count: 19,
|
|
Sum: 2.7,
|
|
ZeroThreshold: 1e-128,
|
|
PositiveSpans: []histogram.Span{
|
|
{Offset: 0, Length: 4},
|
|
{Offset: 0, Length: 0},
|
|
{Offset: 0, Length: 3},
|
|
},
|
|
PositiveBuckets: []float64{1, 3, 1, 2, 1, 1, 1},
|
|
NegativeSpans: []histogram.Span{
|
|
{Offset: 0, Length: 5},
|
|
{Offset: 1, Length: 0},
|
|
{Offset: 0, Length: 1},
|
|
},
|
|
NegativeBuckets: []float64{1, 3, 1, 2, 1, 1},
|
|
CustomValues: []float64{21421, 523},
|
|
}
|
|
}
|
|
|
|
func TestFromIntToFloatOrIntHistogram(t *testing.T) {
|
|
t.Run("v1", func(t *testing.T) {
|
|
// v1 does not support nhcb.
|
|
testIntHistWithoutNHCB := testIntHistogram()
|
|
testIntHistWithoutNHCB.CustomValues = nil
|
|
testFloatHistWithoutNHCB := testFloatHistogram()
|
|
testFloatHistWithoutNHCB.CustomValues = nil
|
|
|
|
h := prompb.FromIntHistogram(123, &testIntHistWithoutNHCB)
|
|
require.False(t, h.IsFloatHistogram())
|
|
require.Equal(t, int64(123), h.Timestamp)
|
|
require.Equal(t, testIntHistWithoutNHCB, *h.ToIntHistogram())
|
|
require.Equal(t, testFloatHistWithoutNHCB, *h.ToFloatHistogram())
|
|
})
|
|
t.Run("v2", func(t *testing.T) {
|
|
testIntHist := testIntHistogram()
|
|
testFloatHist := testFloatHistogram()
|
|
|
|
h := writev2.FromIntHistogram(123, &testIntHist)
|
|
require.False(t, h.IsFloatHistogram())
|
|
require.Equal(t, int64(123), h.Timestamp)
|
|
require.Equal(t, testIntHist, *h.ToIntHistogram())
|
|
require.Equal(t, testFloatHist, *h.ToFloatHistogram())
|
|
})
|
|
}
|
|
|
|
func TestFromFloatToFloatHistogram(t *testing.T) {
|
|
t.Run("v1", func(t *testing.T) {
|
|
// v1 does not support nhcb.
|
|
testFloatHistWithoutNHCB := testFloatHistogram()
|
|
testFloatHistWithoutNHCB.CustomValues = nil
|
|
|
|
h := prompb.FromFloatHistogram(123, &testFloatHistWithoutNHCB)
|
|
require.True(t, h.IsFloatHistogram())
|
|
require.Equal(t, int64(123), h.Timestamp)
|
|
require.Nil(t, h.ToIntHistogram())
|
|
require.Equal(t, testFloatHistWithoutNHCB, *h.ToFloatHistogram())
|
|
})
|
|
t.Run("v2", func(t *testing.T) {
|
|
testFloatHist := testFloatHistogram()
|
|
|
|
h := writev2.FromFloatHistogram(123, &testFloatHist)
|
|
require.True(t, h.IsFloatHistogram())
|
|
require.Equal(t, int64(123), h.Timestamp)
|
|
require.Nil(t, h.ToIntHistogram())
|
|
require.Equal(t, testFloatHist, *h.ToFloatHistogram())
|
|
})
|
|
}
|
|
|
|
func TestFromIntOrFloatHistogram_ResetHint(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
input histogram.CounterResetHint
|
|
expectedV1 prompb.Histogram_ResetHint
|
|
expectedV2 writev2.Histogram_ResetHint
|
|
}{
|
|
{
|
|
input: histogram.UnknownCounterReset,
|
|
expectedV1: prompb.Histogram_UNKNOWN,
|
|
expectedV2: writev2.Histogram_RESET_HINT_UNSPECIFIED,
|
|
},
|
|
{
|
|
input: histogram.CounterReset,
|
|
expectedV1: prompb.Histogram_YES,
|
|
expectedV2: writev2.Histogram_RESET_HINT_YES,
|
|
},
|
|
{
|
|
input: histogram.NotCounterReset,
|
|
expectedV1: prompb.Histogram_NO,
|
|
expectedV2: writev2.Histogram_RESET_HINT_NO,
|
|
},
|
|
{
|
|
input: histogram.GaugeType,
|
|
expectedV1: prompb.Histogram_GAUGE,
|
|
expectedV2: writev2.Histogram_RESET_HINT_GAUGE,
|
|
},
|
|
} {
|
|
t.Run("", func(t *testing.T) {
|
|
t.Run("v1", func(t *testing.T) {
|
|
h := testIntHistogram()
|
|
h.CounterResetHint = tc.input
|
|
got := prompb.FromIntHistogram(1337, &h)
|
|
require.Equal(t, tc.expectedV1, got.GetResetHint())
|
|
|
|
fh := testFloatHistogram()
|
|
fh.CounterResetHint = tc.input
|
|
got2 := prompb.FromFloatHistogram(1337, &fh)
|
|
require.Equal(t, tc.expectedV1, got2.GetResetHint())
|
|
})
|
|
t.Run("v2", func(t *testing.T) {
|
|
h := testIntHistogram()
|
|
h.CounterResetHint = tc.input
|
|
got := writev2.FromIntHistogram(1337, &h)
|
|
require.Equal(t, tc.expectedV2, got.GetResetHint())
|
|
|
|
fh := testFloatHistogram()
|
|
fh.CounterResetHint = tc.input
|
|
got2 := writev2.FromFloatHistogram(1337, &fh)
|
|
require.Equal(t, tc.expectedV2, got2.GetResetHint())
|
|
})
|
|
})
|
|
}
|
|
}
|