Files
VictoriaMetrics/apptest/tests/query_resource_limit_test.go
Aliaksandr Valialkin 90a84f2526 apptest: consistently use lib/fs.MustRemoveDir() instead of os.RemoveAll()
This reduces the amounts of bolierplate code needed for error handling
2025-07-25 20:28:53 +02:00

183 lines
6.1 KiB
Go

package tests
import (
"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 TestClusterMaxUniqueTimeseries(t *testing.T) {
fs.MustRemoveDir(t.Name())
cmpOpt := cmpopts.IgnoreFields(apptest.PrometheusAPIV1QueryResponse{}, "Status", "Data.ResultType")
tc := apptest.NewTestCase(t)
defer tc.Stop()
vmstorage := tc.MustStartVmstorage("vmstorage", []string{
"-storageDataPath=" + tc.Dir() + "/vmstorage",
"-retentionPeriod=100y",
"-search.maxUniqueTimeseries=2",
})
vminsert := tc.MustStartVminsert("vminsert", []string{
"-storageNode=" + vmstorage.VminsertAddr(),
})
vmselectNoLimit := tc.MustStartVmselect("vmselect1", []string{
"-storageNode=" + vmstorage.VmselectAddr(),
"-search.tenantCacheExpireDuration=0",
})
vmselectSmallLimit := tc.MustStartVmselect("vmselect2", []string{
"-storageNode=" + vmstorage.VmselectAddr(),
"-search.tenantCacheExpireDuration=0",
"-search.maxUniqueTimeseries=1",
})
vmselectBigLimit := tc.MustStartVmselect("vmselect3", []string{
"-storageNode=" + vmstorage.VmselectAddr(),
"-search.tenantCacheExpireDuration=0",
"-search.maxUniqueTimeseries=3",
})
var commonSamples = []string{
`foo_bar1{instance="a"} 1.00 1652169660000`,
`foo_bar2{instance="a"} 1.00 1652169660000`,
`foo_bar2{instance="b"} 2.00 1652169660000`,
`foo_bar3{instance="a"} 1.00 1652169660000`,
`foo_bar3{instance="b"} 2.00 1652169660000`,
`foo_bar3{instance="c"} 3.00 1652169660000`,
}
// write data to two tenants
tenantIDs := []string{"0:0", "1:15"}
for _, tenantID := range tenantIDs {
vminsert.PrometheusAPIV1ImportPrometheus(t, commonSamples, apptest.QueryOpts{Tenant: tenantID})
vmstorage.ForceFlush(t)
}
instantCT := "2022-05-10T08:05:00.000Z"
// success - `/api/v1/query`
want := apptest.NewPrometheusAPIV1QueryResponse(t,
`{"data":
{"result":[
{"metric":{"__name__":"foo_bar1","instance":"a"},"value":[1652169900,"1"]}
]
}
}`,
)
queryRes := vmselectSmallLimit.PrometheusAPIV1Query(t, "foo_bar1", apptest.QueryOpts{
Time: instantCT,
})
if diff := cmp.Diff(want, queryRes, cmpOpt); diff != "" {
t.Fatalf("unexpected response (-want, +got):\n%s", diff)
}
// success - multitenant `/api/v1/query`
// query is split into two queries for each tenant, so the final result can exceed the limit.
want = apptest.NewPrometheusAPIV1QueryResponse(t,
`{"data":
{"result":[
{"metric":{"__name__":"foo_bar1","instance":"a","vm_account_id":"0","vm_project_id":"0"},"value":[1652169900,"1"]},
{"metric":{"__name__":"foo_bar1","instance":"a","vm_account_id":"1","vm_project_id":"15"},"value":[1652169900,"1"]}
]
}
}`,
)
queryRes = vmselectSmallLimit.PrometheusAPIV1Query(t, "foo_bar1", apptest.QueryOpts{
Time: instantCT,
Tenant: "multitenant",
})
if diff := cmp.Diff(want, queryRes, cmpOpt); diff != "" {
t.Fatalf("unexpected response (-want, +got):\n%s", diff)
}
// fail - `/api/v1/query`, exceed vmselect `maxUniqueTimeseries`
queryRes = vmselectSmallLimit.PrometheusAPIV1Query(t, "foo_bar2", apptest.QueryOpts{
Time: instantCT,
})
if queryRes.ErrorType != "422" {
t.Fatalf("unexpected status code, got %s, want %d, error message is: %v", queryRes.ErrorType, 422, queryRes.Error)
}
// fail - `/api/v1/query`, exceed vmstorage `maxUniqueTimeseries`
queryRes = vmselectNoLimit.PrometheusAPIV1Query(t, "foo_bar3", apptest.QueryOpts{
Time: instantCT,
})
if queryRes.ErrorType != "422" {
t.Fatalf("unexpected status code, got %s, want %d, error message is: %v", queryRes.ErrorType, 422, queryRes.Error)
}
// fail - `/api/v1/query`, vmselect `maxUniqueTimeseries` cannot exceed vmstorage `maxUniqueTimeseries`
queryRes = vmselectBigLimit.PrometheusAPIV1Query(t, "foo_bar3", apptest.QueryOpts{
Time: instantCT,
})
if queryRes.ErrorType != "422" {
t.Fatalf("unexpected status code, got %s, want %d, error message is: %v", queryRes.ErrorType, 422, queryRes.Error)
}
}
func TestClusterMaxSeries(t *testing.T) {
fs.MustRemoveDir(t.Name())
cmpSROpt := cmpopts.IgnoreFields(apptest.PrometheusAPIV1SeriesResponse{}, "Status", "IsPartial")
tc := apptest.NewTestCase(t)
defer tc.Stop()
vmstorage := tc.MustStartVmstorage("vmstorage", []string{
"-storageDataPath=" + tc.Dir() + "/vmstorage",
"-retentionPeriod=100y",
"-search.maxUniqueTimeseries=2",
})
vminsert := tc.MustStartVminsert("vminsert", []string{
"-storageNode=" + vmstorage.VminsertAddr(),
})
vmselectBigLimit := tc.MustStartVmselect("vmselect2", []string{
"-storageNode=" + vmstorage.VmselectAddr(),
"-search.tenantCacheExpireDuration=0",
"-search.maxSeries=3",
})
vmselectSmallLimit := tc.MustStartVmselect("vmselect1", []string{
"-storageNode=" + vmstorage.VmselectAddr(),
"-search.tenantCacheExpireDuration=0",
"-search.maxSeries=1",
})
var commonSamples = []string{
`foo_bar3{instance="a"} 1.00 1652169660000`,
`foo_bar3{instance="b"} 2.00 1652169660000`,
`foo_bar3{instance="c"} 3.00 1652169660000`,
}
// write data
vminsert.PrometheusAPIV1ImportPrometheus(t, commonSamples, apptest.QueryOpts{})
vmstorage.ForceFlush(t)
// success - `/api/v1/series`, vmselect `maxLabelsAPISeries` can exceed vmstorage `maxLabelsAPISeries``
wantSR := apptest.NewPrometheusAPIV1SeriesResponse(t,
`{"data": [
{"__name__":"foo_bar3","instance":"a"},
{"__name__":"foo_bar3","instance":"b"},
{"__name__":"foo_bar3","instance":"c"}
]
}`)
seriesRes := vmselectBigLimit.PrometheusAPIV1Series(t, "foo_bar3", apptest.QueryOpts{
Start: "2022-05-10T08:03:00.000Z",
})
if diff := cmp.Diff(wantSR.Sort(), seriesRes.Sort(), cmpSROpt); diff != "" {
t.Fatalf("unexpected response (-want, +got):\n%s", diff)
}
// fail - `/api/v1/series`, exceed vmselect `maxSeries`
seriesRes1 := vmselectSmallLimit.PrometheusAPIV1Series(t, "foo_bar3", apptest.QueryOpts{
Start: "2022-05-10T08:03:00.000Z",
})
if seriesRes1.ErrorType != "422" {
t.Fatalf("unexpected status code, got %s, want %d, error message is: %v", seriesRes.ErrorType, 422, seriesRes1.Error)
}
}