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.
298 lines
9.0 KiB
298 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()) |
|
}) |
|
}) |
|
} |
|
}
|
|
|