Path: blob/main/component/otelcol/receiver/prometheus/internal/metrics_adjuster_test.go
5443 views
// Copyright The OpenTelemetry Authors1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314package internal1516import (17"testing"18"time"1920"github.com/stretchr/testify/assert"21"go.opentelemetry.io/collector/pdata/pmetric"22semconv "go.opentelemetry.io/collector/semconv/v1.8.0"23"go.uber.org/zap"24)2526var (27tUnknown = timestampFromMs(0)28t1 = timestampFromMs(1)29t2 = timestampFromMs(2)30t3 = timestampFromMs(3)31t4 = timestampFromMs(4)32t5 = timestampFromMs(5)3334bounds0 = []float64{1, 2, 4}35percent0 = []float64{10, 50, 90}3637sum1 = "sum1"38gauge1 = "gauge1"39histogram1 = "histogram1"40summary1 = "summary1"4142k1v1k2v2 = []*kv{43{"k1", "v1"},44{"k2", "v2"},45}4647k1v10k2v20 = []*kv{48{"k1", "v10"},49{"k2", "v20"},50}5152k1v100k2v200 = []*kv{53{"k1", "v100"},54{"k2", "v200"},55}5657emptyLabels []*kv58k1vEmpty = []*kv{{"k1", ""}}59k1vEmptyk2vEmptyk3vEmpty = []*kv{{"k1", ""}, {"k2", ""}, {"k3", ""}}60)6162func TestGauge(t *testing.T) {63script := []*metricsAdjusterTest{64{65description: "Gauge: round 1 - gauge not adjusted",66metrics: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t1, t1, 44))),67adjusted: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t1, t1, 44))),68},69{70description: "Gauge: round 2 - gauge not adjusted",71metrics: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t2, t2, 66))),72adjusted: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t2, t2, 66))),73},74{75description: "Gauge: round 3 - value less than previous value - gauge is not adjusted",76metrics: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t3, t3, 55))),77adjusted: metrics(gaugeMetric(gauge1, doublePoint(k1v1k2v2, t3, t3, 55))),78},79}80runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)81}8283func TestSum(t *testing.T) {84script := []*metricsAdjusterTest{85{86description: "Sum: round 1 - initial instance, start time is established",87metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44))),88adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44))),89},90{91description: "Sum: round 2 - instance adjusted based on round 1",92metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t2, t2, 66))),93adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t2, 66))),94},95{96description: "Sum: round 3 - instance reset (value less than previous value), start time is reset",97metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 55))),98adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 55))),99},100{101description: "Sum: round 4 - instance adjusted based on round 3",102metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 72))),103adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t3, t4, 72))),104},105{106description: "Sum: round 5 - instance adjusted based on round 4",107metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t5, t5, 72))),108adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t3, t5, 72))),109},110}111runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)112}113114func TestSummaryNoCount(t *testing.T) {115script := []*metricsAdjusterTest{116{117description: "Summary No Count: round 1 - initial instance, start time is established",118metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 0, 40, percent0, []float64{1, 5, 8}))),119adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 0, 40, percent0, []float64{1, 5, 8}))),120},121{122description: "Summary No Count: round 2 - instance adjusted based on round 1",123metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t2, t2, 0, 70, percent0, []float64{7, 44, 9}))),124adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t2, 0, 70, percent0, []float64{7, 44, 9}))),125},126{127description: "Summary No Count: round 3 - instance reset (count less than previous), start time is reset",128metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 0, 66, percent0, []float64{3, 22, 5}))),129adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 0, 66, percent0, []float64{3, 22, 5}))),130},131{132description: "Summary No Count: round 4 - instance adjusted based on round 3",133metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t4, t4, 0, 96, percent0, []float64{9, 47, 8}))),134adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t4, 0, 96, percent0, []float64{9, 47, 8}))),135},136}137138runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)139}140141func TestSummaryFlagNoRecordedValue(t *testing.T) {142script := []*metricsAdjusterTest{143{144description: "Summary No Count: round 1 - initial instance, start time is established",145metrics: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 0, 40, percent0, []float64{1, 5, 8}))),146adjusted: metrics(summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 0, 40, percent0, []float64{1, 5, 8}))),147},148{149description: "Summary Flag NoRecordedValue: round 2 - instance adjusted based on round 1",150metrics: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, t2, t2))),151adjusted: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, t1, t2))),152},153}154155runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)156}157158func TestSummary(t *testing.T) {159script := []*metricsAdjusterTest{160{161description: "Summary: round 1 - initial instance, start time is established",162metrics: metrics(163summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),164),165adjusted: metrics(166summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),167),168},169{170description: "Summary: round 2 - instance adjusted based on round 1",171metrics: metrics(172summaryMetric(summary1, summaryPoint(k1v1k2v2, t2, t2, 15, 70, percent0, []float64{7, 44, 9})),173),174adjusted: metrics(175summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t2, 15, 70, percent0, []float64{7, 44, 9})),176),177},178{179description: "Summary: round 3 - instance reset (count less than previous), start time is reset",180metrics: metrics(181summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 12, 66, percent0, []float64{3, 22, 5})),182),183adjusted: metrics(184summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 12, 66, percent0, []float64{3, 22, 5})),185),186},187{188description: "Summary: round 4 - instance adjusted based on round 3",189metrics: metrics(190summaryMetric(summary1, summaryPoint(k1v1k2v2, t4, t4, 14, 96, percent0, []float64{9, 47, 8})),191),192adjusted: metrics(193summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t4, 14, 96, percent0, []float64{9, 47, 8})),194),195},196}197198runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)199}200201func TestHistogram(t *testing.T) {202script := []*metricsAdjusterTest{203{204description: "Histogram: round 1 - initial instance, start time is established",205metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7}))),206adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7}))),207}, {208description: "Histogram: round 2 - instance adjusted based on round 1",209metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t2, t2, bounds0, []uint64{6, 3, 4, 8}))),210adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t2, bounds0, []uint64{6, 3, 4, 8}))),211}, {212description: "Histogram: round 3 - instance reset (value less than previous value), start time is reset",213metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{5, 3, 2, 7}))),214adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{5, 3, 2, 7}))),215}, {216description: "Histogram: round 4 - instance adjusted based on round 3",217metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t4, t4, bounds0, []uint64{7, 4, 2, 12}))),218adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t4, bounds0, []uint64{7, 4, 2, 12}))),219},220}221runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)222}223224func TestHistogramFlagNoRecordedValue(t *testing.T) {225script := []*metricsAdjusterTest{226{227description: "Histogram: round 1 - initial instance, start time is established",228metrics: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{7, 4, 2, 12}))),229adjusted: metrics(histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{7, 4, 2, 12}))),230},231{232description: "Histogram: round 2 - instance adjusted based on round 1",233metrics: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t2))),234adjusted: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, t1, t2))),235},236}237238runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)239}240241func TestHistogramFlagNoRecordedValueFirstObservation(t *testing.T) {242script := []*metricsAdjusterTest{243{244description: "Histogram: round 1 - initial instance, start time is unknown",245metrics: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t1))),246adjusted: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t1))),247},248{249description: "Histogram: round 2 - instance unchanged",250metrics: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t2))),251adjusted: metrics(histogramMetric(histogram1, histogramPointNoValue(k1v1k2v2, tUnknown, t2))),252},253}254255runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)256}257258func TestSummaryFlagNoRecordedValueFirstObservation(t *testing.T) {259script := []*metricsAdjusterTest{260{261description: "Summary: round 1 - initial instance, start time is unknown",262metrics: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, tUnknown, t1))),263adjusted: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, tUnknown, t1))),264},265{266description: "Summary: round 2 - instance unchanged",267metrics: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, tUnknown, t2))),268adjusted: metrics(summaryMetric(summary1, summaryPointNoValue(k1v1k2v2, tUnknown, t2))),269},270}271272runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)273}274275func TestGaugeFlagNoRecordedValueFirstObservation(t *testing.T) {276script := []*metricsAdjusterTest{277{278description: "Gauge: round 1 - initial instance, start time is unknown",279metrics: metrics(gaugeMetric(gauge1, doublePointNoValue(k1v1k2v2, tUnknown, t1))),280adjusted: metrics(gaugeMetric(gauge1, doublePointNoValue(k1v1k2v2, tUnknown, t1))),281},282{283description: "Gauge: round 2 - instance unchanged",284metrics: metrics(gaugeMetric(gauge1, doublePointNoValue(k1v1k2v2, tUnknown, t2))),285adjusted: metrics(gaugeMetric(gauge1, doublePointNoValue(k1v1k2v2, tUnknown, t2))),286},287}288289runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)290}291292func TestSumFlagNoRecordedValueFirstObservation(t *testing.T) {293script := []*metricsAdjusterTest{294{295description: "Sum: round 1 - initial instance, start time is unknown",296metrics: metrics(sumMetric("sum1", doublePointNoValue(k1v1k2v2, tUnknown, t1))),297adjusted: metrics(sumMetric("sum1", doublePointNoValue(k1v1k2v2, tUnknown, t1))),298},299{300description: "Sum: round 2 - instance unchanged",301metrics: metrics(sumMetric("sum1", doublePointNoValue(k1v1k2v2, tUnknown, t2))),302adjusted: metrics(sumMetric("sum1", doublePointNoValue(k1v1k2v2, tUnknown, t2))),303},304}305306runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)307}308309func TestMultiMetrics(t *testing.T) {310script := []*metricsAdjusterTest{311{312description: "MultiMetrics: round 1 - combined round 1 of individual metrics",313metrics: metrics(314gaugeMetric(gauge1, doublePoint(k1v1k2v2, t1, t1, 44)),315sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),316histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),317summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),318),319adjusted: metrics(320gaugeMetric(gauge1, doublePoint(k1v1k2v2, t1, t1, 44)),321sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),322histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),323summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),324),325},326{327description: "MultiMetrics: round 2 - combined round 2 of individual metrics",328metrics: metrics(329gaugeMetric(gauge1, doublePoint(k1v1k2v2, t2, t2, 66)),330sumMetric(sum1, doublePoint(k1v1k2v2, t2, t2, 66)),331histogramMetric(histogram1, histogramPoint(k1v1k2v2, t2, t2, bounds0, []uint64{6, 3, 4, 8})),332summaryMetric(summary1, summaryPoint(k1v1k2v2, t2, t2, 15, 70, percent0, []float64{7, 44, 9})),333),334adjusted: metrics(335gaugeMetric(gauge1, doublePoint(k1v1k2v2, t2, t2, 66)),336sumMetric(sum1, doublePoint(k1v1k2v2, t1, t2, 66)),337histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t2, bounds0, []uint64{6, 3, 4, 8})),338summaryMetric(summary1, summaryPoint(k1v1k2v2, t1, t2, 15, 70, percent0, []float64{7, 44, 9})),339),340},341{342description: "MultiMetrics: round 3 - combined round 3 of individual metrics",343metrics: metrics(344gaugeMetric(gauge1, doublePoint(k1v1k2v2, t3, t3, 55)),345sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 55)),346histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{5, 3, 2, 7})),347summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 12, 66, percent0, []float64{3, 22, 5})),348),349adjusted: metrics(350gaugeMetric(gauge1, doublePoint(k1v1k2v2, t3, t3, 55)),351sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 55)),352histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{5, 3, 2, 7})),353summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t3, 12, 66, percent0, []float64{3, 22, 5})),354),355},356{357description: "MultiMetrics: round 4 - combined round 4 of individual metrics",358metrics: metrics(359sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 72)),360histogramMetric(histogram1, histogramPoint(k1v1k2v2, t4, t4, bounds0, []uint64{7, 4, 2, 12})),361summaryMetric(summary1, summaryPoint(k1v1k2v2, t4, t4, 14, 96, percent0, []float64{9, 47, 8})),362),363adjusted: metrics(364sumMetric(sum1, doublePoint(k1v1k2v2, t3, t4, 72)),365histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t4, bounds0, []uint64{7, 4, 2, 12})),366summaryMetric(summary1, summaryPoint(k1v1k2v2, t3, t4, 14, 96, percent0, []float64{9, 47, 8})),367),368},369}370runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)371}372373func TestNewDataPointsAdded(t *testing.T) {374script := []*metricsAdjusterTest{375{376description: "New Datapoints: round 1 - two datapoints each",377metrics: metrics(378sumMetric(sum1,379doublePoint(k1v1k2v2, t1, t1, 44),380doublePoint(k1v100k2v200, t1, t1, 44)),381histogramMetric(histogram1,382histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7}),383histogramPoint(k1v100k2v200, t1, t1, bounds0, []uint64{4, 2, 3, 7})),384summaryMetric(summary1,385summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8}),386summaryPoint(k1v100k2v200, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),387),388adjusted: metrics(389sumMetric(sum1,390doublePoint(k1v1k2v2, t1, t1, 44),391doublePoint(k1v100k2v200, t1, t1, 44)),392histogramMetric(histogram1,393histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7}),394histogramPoint(k1v100k2v200, t1, t1, bounds0, []uint64{4, 2, 3, 7})),395summaryMetric(summary1,396summaryPoint(k1v1k2v2, t1, t1, 10, 40, percent0, []float64{1, 5, 8}),397summaryPoint(k1v100k2v200, t1, t1, 10, 40, percent0, []float64{1, 5, 8})),398),399},400{401description: "New Datapoints: round 2 - new datapoints unchanged, old datapoints adjusted",402metrics: metrics(403sumMetric(sum1,404doublePoint(k1v1k2v2, t2, t2, 44),405doublePoint(k1v10k2v20, t2, t2, 44),406doublePoint(k1v100k2v200, t2, t2, 44)),407histogramMetric(histogram1,408histogramPoint(k1v1k2v2, t2, t2, bounds0, []uint64{4, 2, 3, 7}),409histogramPoint(k1v10k2v20, t2, t2, bounds0, []uint64{4, 2, 3, 7}),410histogramPoint(k1v100k2v200, t2, t2, bounds0, []uint64{4, 2, 3, 7})),411summaryMetric(summary1,412summaryPoint(k1v1k2v2, t2, t2, 10, 40, percent0, []float64{1, 5, 8}),413summaryPoint(k1v10k2v20, t2, t2, 10, 40, percent0, []float64{1, 5, 8}),414summaryPoint(k1v100k2v200, t2, t2, 10, 40, percent0, []float64{1, 5, 8})),415),416adjusted: metrics(417sumMetric(sum1,418doublePoint(k1v1k2v2, t1, t2, 44),419doublePoint(k1v10k2v20, t2, t2, 44),420doublePoint(k1v100k2v200, t1, t2, 44)),421histogramMetric(histogram1,422histogramPoint(k1v1k2v2, t1, t2, bounds0, []uint64{4, 2, 3, 7}),423histogramPoint(k1v10k2v20, t2, t2, bounds0, []uint64{4, 2, 3, 7}),424histogramPoint(k1v100k2v200, t1, t2, bounds0, []uint64{4, 2, 3, 7})),425summaryMetric(summary1,426summaryPoint(k1v1k2v2, t1, t2, 10, 40, percent0, []float64{1, 5, 8}),427summaryPoint(k1v10k2v20, t2, t2, 10, 40, percent0, []float64{1, 5, 8}),428summaryPoint(k1v100k2v200, t1, t2, 10, 40, percent0, []float64{1, 5, 8})),429),430},431}432runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)433}434435func TestMultiTimeseries(t *testing.T) {436script := []*metricsAdjusterTest{437{438description: "MultiTimeseries: round 1 - initial first instance, start time is established",439metrics: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44))),440adjusted: metrics(sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44))),441},442{443description: "MultiTimeseries: round 2 - first instance adjusted based on round 1, initial second instance",444metrics: metrics(445sumMetric(sum1, doublePoint(k1v1k2v2, t2, t2, 66)),446sumMetric(sum1, doublePoint(k1v10k2v20, t2, t2, 20.0)),447),448adjusted: metrics(449sumMetric(sum1, doublePoint(k1v1k2v2, t1, t2, 66)),450sumMetric(sum1, doublePoint(k1v10k2v20, t2, t2, 20.0)),451),452},453{454description: "MultiTimeseries: round 3 - first instance adjusted based on round 1, second based on round 2",455metrics: metrics(456sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 88.0)),457sumMetric(sum1, doublePoint(k1v10k2v20, t3, t3, 49.0)),458),459adjusted: metrics(460sumMetric(sum1, doublePoint(k1v1k2v2, t1, t3, 88.0)),461sumMetric(sum1, doublePoint(k1v10k2v20, t2, t3, 49.0)),462),463},464{465description: "MultiTimeseries: round 4 - first instance reset, second instance adjusted based on round 2, initial third instance",466metrics: metrics(467sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 87.0)),468sumMetric(sum1, doublePoint(k1v10k2v20, t4, t4, 57.0)),469sumMetric(sum1, doublePoint(k1v100k2v200, t4, t4, 10.0)),470),471adjusted: metrics(472sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 87.0)),473sumMetric(sum1, doublePoint(k1v10k2v20, t2, t4, 57.0)),474sumMetric(sum1, doublePoint(k1v100k2v200, t4, t4, 10.0)),475),476},477{478description: "MultiTimeseries: round 5 - first instance adjusted based on round 4, second on round 2, third on round 4",479metrics: metrics(480sumMetric(sum1, doublePoint(k1v1k2v2, t5, t5, 90.0)),481sumMetric(sum1, doublePoint(k1v10k2v20, t5, t5, 65.0)),482sumMetric(sum1, doublePoint(k1v100k2v200, t5, t5, 22.0)),483),484adjusted: metrics(485sumMetric(sum1, doublePoint(k1v1k2v2, t4, t5, 90.0)),486sumMetric(sum1, doublePoint(k1v10k2v20, t2, t5, 65.0)),487sumMetric(sum1, doublePoint(k1v100k2v200, t4, t5, 22.0)),488),489},490}491runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)492}493494func TestEmptyLabels(t *testing.T) {495script := []*metricsAdjusterTest{496{497description: "EmptyLabels: round 1 - initial instance, implicitly empty labels, start time is established",498metrics: metrics(sumMetric(sum1, doublePoint(emptyLabels, t1, t1, 44))),499adjusted: metrics(sumMetric(sum1, doublePoint(emptyLabels, t1, t1, 44))),500},501{502description: "EmptyLabels: round 2 - instance adjusted based on round 1",503metrics: metrics(sumMetric(sum1, doublePoint(emptyLabels, t2, t2, 66))),504adjusted: metrics(sumMetric(sum1, doublePoint(emptyLabels, t1, t2, 66))),505},506{507description: "EmptyLabels: round 3 - one explicitly empty label, instance adjusted based on round 1",508metrics: metrics(sumMetric(sum1, doublePoint(k1vEmpty, t3, t3, 77))),509adjusted: metrics(sumMetric(sum1, doublePoint(k1vEmpty, t1, t3, 77))),510},511{512description: "EmptyLabels: round 4 - three explicitly empty labels, instance adjusted based on round 1",513metrics: metrics(sumMetric(sum1, doublePoint(k1vEmptyk2vEmptyk3vEmpty, t3, t3, 88))),514adjusted: metrics(sumMetric(sum1, doublePoint(k1vEmptyk2vEmptyk3vEmpty, t1, t3, 88))),515},516}517runScript(t, NewInitialPointAdjuster(zap.NewNop(), time.Minute), "job", "0", script)518}519520func TestTsGC(t *testing.T) {521script1 := []*metricsAdjusterTest{522{523description: "TsGC: round 1 - initial instances, start time is established",524metrics: metrics(525sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),526sumMetric(sum1, doublePoint(k1v10k2v20, t1, t1, 20)),527histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),528histogramMetric(histogram1, histogramPoint(k1v10k2v20, t1, t1, bounds0, []uint64{40, 20, 30, 70})),529),530adjusted: metrics(531sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),532sumMetric(sum1, doublePoint(k1v10k2v20, t1, t1, 20)),533histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),534histogramMetric(histogram1, histogramPoint(k1v10k2v20, t1, t1, bounds0, []uint64{40, 20, 30, 70})),535),536},537}538539script2 := []*metricsAdjusterTest{540{541description: "TsGC: round 2 - metrics first timeseries adjusted based on round 2, second timeseries not updated",542metrics: metrics(543sumMetric(sum1, doublePoint(k1v1k2v2, t2, t2, 88)),544histogramMetric(histogram1, histogramPoint(k1v1k2v2, t2, t2, bounds0, []uint64{8, 7, 9, 14})),545),546adjusted: metrics(547sumMetric(sum1, doublePoint(k1v1k2v2, t1, t2, 88)),548histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t2, bounds0, []uint64{8, 7, 9, 14})),549),550},551}552553script3 := []*metricsAdjusterTest{554{555description: "TsGC: round 3 - metrics first timeseries adjusted based on round 2, second timeseries empty due to timeseries gc()",556metrics: metrics(557sumMetric(sum1, doublePoint(k1v1k2v2, t3, t3, 99)),558sumMetric(sum1, doublePoint(k1v10k2v20, t3, t3, 80)),559histogramMetric(histogram1, histogramPoint(k1v1k2v2, t3, t3, bounds0, []uint64{9, 8, 10, 15})),560histogramMetric(histogram1, histogramPoint(k1v10k2v20, t3, t3, bounds0, []uint64{55, 66, 33, 77})),561),562adjusted: metrics(563sumMetric(sum1, doublePoint(k1v1k2v2, t1, t3, 99)),564sumMetric(sum1, doublePoint(k1v10k2v20, t3, t3, 80)),565histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t3, bounds0, []uint64{9, 8, 10, 15})),566histogramMetric(histogram1, histogramPoint(k1v10k2v20, t3, t3, bounds0, []uint64{55, 66, 33, 77})),567),568},569}570571ma := NewInitialPointAdjuster(zap.NewNop(), time.Minute)572573// run round 1574runScript(t, ma, "job", "0", script1)575// gc the tsmap, unmarking all entries576ma.(*initialPointAdjuster).jobsMap.get("job", "0").gc()577// run round 2 - update metrics first timeseries only578runScript(t, ma, "job", "0", script2)579// gc the tsmap, collecting umarked entries580ma.(*initialPointAdjuster).jobsMap.get("job", "0").gc()581// run round 3 - verify that metrics second timeseries have been gc'd582runScript(t, ma, "job", "0", script3)583}584585func TestJobGC(t *testing.T) {586job1Script1 := []*metricsAdjusterTest{587{588description: "JobGC: job 1, round 1 - initial instances, adjusted should be empty",589metrics: metrics(590sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),591sumMetric(sum1, doublePoint(k1v10k2v20, t1, t1, 20)),592histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),593histogramMetric(histogram1, histogramPoint(k1v10k2v20, t1, t1, bounds0, []uint64{40, 20, 30, 70})),594),595adjusted: metrics(596sumMetric(sum1, doublePoint(k1v1k2v2, t1, t1, 44)),597sumMetric(sum1, doublePoint(k1v10k2v20, t1, t1, 20)),598histogramMetric(histogram1, histogramPoint(k1v1k2v2, t1, t1, bounds0, []uint64{4, 2, 3, 7})),599histogramMetric(histogram1, histogramPoint(k1v10k2v20, t1, t1, bounds0, []uint64{40, 20, 30, 70})),600),601},602}603604job2Script1 := []*metricsAdjusterTest{605{606description: "JobGC: job2, round 1 - no metrics adjusted, just trigger gc",607metrics: metrics(),608adjusted: metrics(),609},610}611612job1Script2 := []*metricsAdjusterTest{613{614description: "JobGC: job 1, round 2 - metrics timeseries empty due to job-level gc",615metrics: metrics(616sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 99)),617sumMetric(sum1, doublePoint(k1v10k2v20, t4, t4, 80)),618histogramMetric(histogram1, histogramPoint(k1v1k2v2, t4, t4, bounds0, []uint64{9, 8, 10, 15})),619histogramMetric(histogram1, histogramPoint(k1v10k2v20, t4, t4, bounds0, []uint64{55, 66, 33, 77})),620),621adjusted: metrics(622sumMetric(sum1, doublePoint(k1v1k2v2, t4, t4, 99)),623sumMetric(sum1, doublePoint(k1v10k2v20, t4, t4, 80)),624histogramMetric(histogram1, histogramPoint(k1v1k2v2, t4, t4, bounds0, []uint64{9, 8, 10, 15})),625histogramMetric(histogram1, histogramPoint(k1v10k2v20, t4, t4, bounds0, []uint64{55, 66, 33, 77})),626),627},628}629630gcInterval := 10 * time.Millisecond631ma := NewInitialPointAdjuster(zap.NewNop(), gcInterval)632633// run job 1, round 1 - all entries marked634runScript(t, ma, "job1", "0", job1Script1)635// sleep longer than gcInterval to enable job gc in the next run636time.Sleep(2 * gcInterval)637// run job 2, round1 - trigger job gc, unmarking all entries638runScript(t, ma, "job1", "1", job2Script1)639// sleep longer than gcInterval to enable job gc in the next run640time.Sleep(2 * gcInterval)641// re-run job 2, round1 - trigger job gc, removing unmarked entries642runScript(t, ma, "job1", "1", job2Script1)643// ensure that at least one jobsMap.gc() completed644ma.(*initialPointAdjuster).jobsMap.gc()645// run job 1, round 2 - verify that all job 1 timeseries have been gc'd646runScript(t, ma, "job1", "0", job1Script2)647}648649type metricsAdjusterTest struct {650description string651metrics pmetric.Metrics652adjusted pmetric.Metrics653}654655func runScript(t *testing.T, ma MetricsAdjuster, job, instance string, tests []*metricsAdjusterTest) {656for _, test := range tests {657t.Run(test.description, func(t *testing.T) {658adjusted := pmetric.NewMetrics()659test.metrics.CopyTo(adjusted)660// Add the instance/job to the input metrics.661adjusted.ResourceMetrics().At(0).Resource().Attributes().PutStr(semconv.AttributeServiceInstanceID, instance)662adjusted.ResourceMetrics().At(0).Resource().Attributes().PutStr(semconv.AttributeServiceName, job)663assert.NoError(t, ma.AdjustMetrics(adjusted))664665// Add the instance/job to the expected metrics as well.666test.adjusted.ResourceMetrics().At(0).Resource().Attributes().PutStr(semconv.AttributeServiceInstanceID, instance)667test.adjusted.ResourceMetrics().At(0).Resource().Attributes().PutStr(semconv.AttributeServiceName, job)668assert.EqualValues(t, test.adjusted, adjusted)669})670}671}672673674