Files
VictoriaMetrics/apptest/tests/metric_names_stats_test.go
Artem Fetishev 01b36ddd19 Refactor apptests (#10940)
Fixes #10938.

---------

Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
2026-05-12 16:24:01 +02:00

273 lines
10 KiB
Go

package tests
import (
"fmt"
"strings"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/VictoriaMetrics/VictoriaMetrics/apptest"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
)
func TestSingleMetricNamesStats(t *testing.T) {
fs.MustRemoveDir(t.Name())
tc := apptest.NewTestCase(t)
defer tc.Stop()
sut := tc.MustStartVmsingle("vmsingle", []string{"-storage.trackMetricNamesStats=true", "-retentionPeriod=100y"})
const ingestDateTime = `2024-02-05T08:57:36.700Z`
const ingestTimestamp = ` 1707123456700`
const date = `2024-02-05`
dataSet := []string{
`metric_name_1{label="foo"} 10`,
`metric_name_1{label="bar"} 10`,
`metric_name_2{label="baz"} 20`,
`metric_name_1{label="baz"} 10`,
`metric_name_3{label="baz"} 30`,
}
largeMetricName := strings.Repeat("large_metric_name_", 32) + "1"
dataSet = append(dataSet, largeMetricName+`{label="bar"} 50`)
for idx := range dataSet {
dataSet[idx] += ingestTimestamp
}
tsdbMetricNameEntryCmpOpts := cmpopts.IgnoreFields(apptest.TSDBStatusResponseMetricNameEntry{}, "LastRequestTimestamp")
sut.PrometheusAPIV1ImportPrometheus(t, dataSet, apptest.QueryOpts{})
sut.ForceFlush(t)
// verify ingest request correctly registered
expected := apptest.MetricNamesStatsResponse{
Records: []apptest.MetricNamesStatsRecord{
{MetricName: largeMetricName},
{MetricName: "metric_name_1"},
{MetricName: "metric_name_2"},
{MetricName: "metric_name_3"},
},
}
got := sut.PrometheusAPIV1StatusMetricNamesStats(t, "", "", "", apptest.QueryOpts{})
if diff := cmp.Diff(expected, got); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
// verify query request correctly registered
sut.PrometheusAPIV1Query(t, `{__name__!=""}`, apptest.QueryOpts{Time: ingestDateTime})
expected = apptest.MetricNamesStatsResponse{
Records: []apptest.MetricNamesStatsRecord{
{MetricName: largeMetricName, QueryRequestsCount: 1},
{MetricName: "metric_name_1", QueryRequestsCount: 3},
{MetricName: "metric_name_2", QueryRequestsCount: 1},
{MetricName: "metric_name_3", QueryRequestsCount: 1},
},
}
got = sut.PrometheusAPIV1StatusMetricNamesStats(t, "", "", "", apptest.QueryOpts{})
if diff := cmp.Diff(expected, got); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
expectedStatsResponse := apptest.TSDBStatusResponse{
Data: apptest.TSDBStatusResponseData{
TotalSeries: 6,
TotalLabelValuePairs: 12,
SeriesCountByMetricName: []apptest.TSDBStatusResponseMetricNameEntry{
{Name: "metric_name_1", RequestsCount: 3},
{Name: largeMetricName, RequestsCount: 1},
{Name: "metric_name_2", RequestsCount: 1},
{Name: "metric_name_3", RequestsCount: 1},
},
SeriesCountByLabelName: []apptest.TSDBStatusResponseEntry{{Name: "__name__"}, {Name: "label"}},
SeriesCountByFocusLabelValue: []apptest.TSDBStatusResponseEntry{},
SeriesCountByLabelValuePair: []apptest.TSDBStatusResponseEntry{
{Name: "__name__=" + largeMetricName},
{Name: "__name__=metric_name_1"}, {Name: "label=baz"},
{Name: "__name__=metric_name_2"}, {Name: "__name__=metric_name_3"},
{Name: "label=bar"}, {Name: "label=foo"},
},
LabelValueCountByLabelName: []apptest.TSDBStatusResponseEntry{{Name: "__name__"}, {Name: "label"}},
},
}
expectedStatsResponse.Sort()
gotStatus := sut.PrometheusAPIV1StatusTSDB(t, "", date, "", apptest.QueryOpts{})
if diff := cmp.Diff(expectedStatsResponse, gotStatus, tsdbMetricNameEntryCmpOpts); diff != "" {
t.Errorf("unexpected APIV1StatusTSDB response (-want, +got):\n%s", diff)
}
// perform query request for single metric and check counter increase
sut.PrometheusAPIV1Query(t, `metric_name_2`, apptest.QueryOpts{Time: ingestDateTime})
expected = apptest.MetricNamesStatsResponse{
Records: []apptest.MetricNamesStatsRecord{
{MetricName: largeMetricName, QueryRequestsCount: 1},
{MetricName: "metric_name_1", QueryRequestsCount: 3},
{MetricName: "metric_name_2", QueryRequestsCount: 2},
{MetricName: "metric_name_3", QueryRequestsCount: 1},
},
}
got = sut.PrometheusAPIV1StatusMetricNamesStats(t, "", "", "", apptest.QueryOpts{})
if diff := cmp.Diff(expected, got); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
// verify le filter
expected = apptest.MetricNamesStatsResponse{
Records: []apptest.MetricNamesStatsRecord{
{MetricName: largeMetricName, QueryRequestsCount: 1},
{MetricName: "metric_name_2", QueryRequestsCount: 2},
{MetricName: "metric_name_3", QueryRequestsCount: 1},
},
}
got = sut.PrometheusAPIV1StatusMetricNamesStats(t, "", "2", "", apptest.QueryOpts{})
if diff := cmp.Diff(expected, got); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
// reset state and check empty request response
sut.PrometheusAPIV1AdminStatusMetricNamesStatsReset(t, apptest.QueryOpts{})
expected = apptest.MetricNamesStatsResponse{
Records: []apptest.MetricNamesStatsRecord{},
}
got = sut.PrometheusAPIV1StatusMetricNamesStats(t, "", "", "", apptest.QueryOpts{})
if diff := cmp.Diff(expected, got); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
}
func TestClusterMetricNamesStats(t *testing.T) {
fs.MustRemoveDir(t.Name())
tc := apptest.NewTestCase(t)
defer tc.Stop()
vmstorage1 := tc.MustStartVmstorage("vmstorage-1", []string{
"-storageDataPath=" + tc.Dir() + "/vmstorage-1",
"-retentionPeriod=100y",
"-storage.trackMetricNamesStats",
})
vmstorage2 := tc.MustStartVmstorage("vmstorage-2", []string{
"-storageDataPath=" + tc.Dir() + "/vmstorage-2",
"-retentionPeriod=100y",
"-storage.trackMetricNamesStats",
})
vminsert := tc.MustStartVminsert("vminsert", []string{
fmt.Sprintf("-storageNode=%s,%s", vmstorage1.VminsertAddr(), vmstorage2.VminsertAddr()),
})
vmselect := tc.MustStartVmselect("vmselect", []string{
fmt.Sprintf("-storageNode=%s,%s", vmstorage1.VmselectAddr(), vmstorage2.VmselectAddr()),
})
// verify empty stats
resp := vmselect.PrometheusAPIV1StatusMetricNamesStats(t, "", "", "", apptest.QueryOpts{Tenant: "0:0"})
if len(resp.Records) != 0 {
t.Fatalf("unexpected resp Records: %d, want: %d", len(resp.Records), 0)
}
const ingestDateTime = `2024-02-05T08:57:36.700Z`
const ingestTimestamp = ` 1707123456700`
const date = `2024-02-05`
dataSet := []string{
`metric_name_1{label="foo"} 10`,
`metric_name_1{label="bar"} 10`,
`metric_name_2{label="baz"} 20`,
`metric_name_1{label="baz"} 10`,
`metric_name_3{label="baz"} 30`,
}
largeMetricName := strings.Repeat("large_metric_name_", 32) + "1"
dataSet = append(dataSet, largeMetricName+`{label="bar"} 50`)
for idx := range dataSet {
dataSet[idx] += ingestTimestamp
}
tsdbMetricNameEntryCmpOpts := cmpopts.IgnoreFields(apptest.TSDBStatusResponseMetricNameEntry{}, "LastRequestTimestamp")
// ingest per tenant data and verify it with search
tenantIDs := []string{"1:1", "1:15", "15:15"}
for _, tenantID := range tenantIDs {
vminsert.PrometheusAPIV1ImportPrometheus(t, dataSet, apptest.QueryOpts{Tenant: tenantID})
vmstorage1.ForceFlush(t)
vmstorage2.ForceFlush(t)
// verify ingest request correctly registered
expected := apptest.MetricNamesStatsResponse{
Records: []apptest.MetricNamesStatsRecord{
{MetricName: largeMetricName},
{MetricName: "metric_name_1"},
{MetricName: "metric_name_2"},
{MetricName: "metric_name_3"},
},
}
gotStats := vmselect.PrometheusAPIV1StatusMetricNamesStats(t, "", "", "", apptest.QueryOpts{Tenant: tenantID})
if diff := cmp.Diff(expected, gotStats); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
// verify query request registered correctly
vmselect.PrometheusAPIV1Query(t, `{__name__!=""}`, apptest.QueryOpts{
Tenant: tenantID, Time: ingestDateTime,
})
expected = apptest.MetricNamesStatsResponse{
Records: []apptest.MetricNamesStatsRecord{
{MetricName: largeMetricName, QueryRequestsCount: 1},
{MetricName: "metric_name_2", QueryRequestsCount: 1},
{MetricName: "metric_name_3", QueryRequestsCount: 1},
{MetricName: "metric_name_1", QueryRequestsCount: 3},
},
}
gotStats = vmselect.PrometheusAPIV1StatusMetricNamesStats(t, "", "", "", apptest.QueryOpts{Tenant: tenantID})
if diff := cmp.Diff(expected, gotStats); diff != "" {
t.Errorf("unexpected response tenant: %s (-want, +got):\n%s", tenantID, diff)
}
expectedStatsResponse := apptest.TSDBStatusResponse{
Data: apptest.TSDBStatusResponseData{
TotalSeries: 6,
TotalLabelValuePairs: 12,
SeriesCountByMetricName: []apptest.TSDBStatusResponseMetricNameEntry{
{Name: "metric_name_1", RequestsCount: 3},
{Name: largeMetricName, RequestsCount: 1},
{Name: "metric_name_2", RequestsCount: 1},
{Name: "metric_name_3", RequestsCount: 1},
},
SeriesCountByLabelName: []apptest.TSDBStatusResponseEntry{{Name: "__name__"}, {Name: "label"}},
SeriesCountByFocusLabelValue: []apptest.TSDBStatusResponseEntry{},
SeriesCountByLabelValuePair: []apptest.TSDBStatusResponseEntry{
{Name: "__name__=" + largeMetricName},
{Name: "__name__=metric_name_1"}, {Name: "label=baz"},
{Name: "__name__=metric_name_2"}, {Name: "__name__=metric_name_3"},
{Name: "label=bar"}, {Name: "label=foo"},
},
LabelValueCountByLabelName: []apptest.TSDBStatusResponseEntry{{Name: "__name__"}, {Name: "label"}},
},
}
expectedStatsResponse.Sort()
gotStatus := vmselect.PrometheusAPIV1StatusTSDB(t, "", date, "", apptest.QueryOpts{Tenant: tenantID})
if diff := cmp.Diff(expectedStatsResponse, gotStatus, tsdbMetricNameEntryCmpOpts); diff != "" {
t.Errorf("unexpected TSDB status for tenant %s (-want, +got):\n%s", tenantID, diff)
}
}
// verify multitenant stats
expected := apptest.MetricNamesStatsResponse{
Records: []apptest.MetricNamesStatsRecord{
{MetricName: largeMetricName, QueryRequestsCount: 3},
{MetricName: "metric_name_2", QueryRequestsCount: 3},
{MetricName: "metric_name_3", QueryRequestsCount: 3},
{MetricName: "metric_name_1", QueryRequestsCount: 9},
},
}
gotStats := vmselect.PrometheusAPIV1StatusMetricNamesStats(t, "", "", "", apptest.QueryOpts{Tenant: "multitenant"})
if diff := cmp.Diff(expected, gotStats); diff != "" {
t.Errorf("unexpected response (-want, +got):\n%s", diff)
}
// reset cache and check empty state
vmselect.PrometheusAPIV1AdminStatusMetricNamesStatsReset(t, apptest.QueryOpts{})
resp = vmselect.PrometheusAPIV1StatusMetricNamesStats(t, "", "", "", apptest.QueryOpts{Tenant: "multitenant"})
if len(resp.Records) != 0 {
t.Fatalf("want 0 records, got: %d", len(resp.Records))
}
}