Files
metrics/apptest/tests/ingestprotocols_test.go
2026-01-06 12:27:01 +01:00

594 lines
16 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"
"github.com/VictoriaMetrics/VictoriaMetrics/lib/prompb"
)
func TestSingleIngestionProtocols(t *testing.T) {
fs.MustRemoveDir(t.Name())
tc := apptest.NewTestCase(t)
defer tc.Stop()
sut := tc.MustStartDefaultVmsingle()
type opts struct {
query string
wantMetrics []map[string]string
wantSamples []*apptest.Sample
}
f := func(sut apptest.PrometheusQuerier, opts *opts) {
t.Helper()
wantResult := []*apptest.QueryResult{}
for idx, wm := range opts.wantMetrics {
wantResult = append(wantResult, &apptest.QueryResult{
Metric: wm,
Samples: []*apptest.Sample{opts.wantSamples[idx]},
})
}
tc.Assert(&apptest.AssertOptions{
Msg: "unexpected /export query response",
Got: func() any {
got := sut.PrometheusAPIV1Export(t, opts.query, apptest.QueryOpts{
Start: "2024-02-05T08:50:00.700Z",
End: "2024-02-05T09:00:00.700Z",
})
got.Sort()
return got
},
Want: &apptest.PrometheusAPIV1QueryResponse{Data: &apptest.QueryData{Result: wantResult}},
CmpOpts: []cmp.Option{
cmpopts.IgnoreFields(apptest.PrometheusAPIV1QueryResponse{}, "Status", "Data.ResultType"),
},
})
}
// influx line format
sut.InfluxWrite(t, []string{
`influxline series1=10 1707123456700`, // 2024-02-05T08:57:36.700Z
`influxline,label=foo1,label1=value1,label2=value2 series2=40 1707123456800`, // 2024-02-05T08:57:36.800Z
}, apptest.QueryOpts{
ExtraLabels: []string{"el1=elv1", "el2=elv2"},
})
sut.ForceFlush(t)
f(sut, &opts{
query: `{__name__=~"influxline.+"}`,
wantMetrics: []map[string]string{
{
"__name__": "influxline_series1",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "influxline_series2",
"label": "foo1",
"label1": "value1",
"label2": "value2",
"el1": "elv1",
"el2": "elv2",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456700, Value: 10},
{Timestamp: 1707123456800, Value: 40},
},
})
// OpenTSDB HTTP write format
sut.OpenTSDBAPIPut(t, []string{
`{"metric":"opentsdbimport.foo","value":45.34, "timestamp": "1707123457"}`,
`{"metric":"opentsdbimport.bar","value":43, "timestamp": "1707123456"}`,
}, apptest.QueryOpts{
ExtraLabels: []string{"el1=elv1", "el2=elv2"},
})
sut.ForceFlush(t)
f(sut, &opts{
query: `{__name__=~"opentsdbimport.*"}`,
wantMetrics: []map[string]string{
{
"__name__": "opentsdbimport.bar",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "opentsdbimport.foo",
"el1": "elv1",
"el2": "elv2",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456000, Value: 43},
{Timestamp: 1707123457000, Value: 45.34},
},
})
// CSV import
sut.PrometheusAPIV1ImportCSV(t, []string{
`GOOG,1.23,4.56,NYSE,1707123457`,
`MSFT,23,56,NASDAQ,1707123457`,
}, apptest.QueryOpts{
ExtraLabels: []string{"el1=elv1", "el2=elv2"},
Format: "2:metric:csv_import,3:metric:csv_import_v2,1:label:ticker,4:label:market,5:time:unix_s",
})
sut.ForceFlush(t)
f(sut, &opts{
query: `{__name__=~"csv_import.*"}`,
wantMetrics: []map[string]string{
{
"__name__": "csv_import",
"ticker": "MSFT",
"market": "NASDAQ",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "csv_import",
"ticker": "GOOG",
"market": "NYSE",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "csv_import_v2",
"ticker": "MSFT",
"market": "NASDAQ",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "csv_import_v2",
"ticker": "GOOG",
"market": "NYSE",
"el1": "elv1",
"el2": "elv2",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123457000, Value: 23},
{Timestamp: 1707123457000, Value: 1.23},
{Timestamp: 1707123457000, Value: 56},
{Timestamp: 1707123457000, Value: 4.56},
},
})
// prometheus text exposition format
sut.PrometheusAPIV1ImportPrometheus(t, []string{
`# HELP importprometheus_series some help message`,
`# TYPE importprometheus_series gauge`,
`importprometheus_series 10 1707123456700`, // 2024-02-05T08:57:36.700Z
`# HELP importprometheus_series2 some help message second one`,
`# TYPE importprometheus_series2 gauge`,
`importprometheus_series2{label="foo",label1="value1"} 20 1707123456800`, // 2024-02-05T08:57:36.800Z
}, apptest.QueryOpts{
ExtraLabels: []string{"el1=elv1", "el2=elv2"},
})
sut.ForceFlush(t)
f(sut, &opts{
query: `{__name__=~"importprometheus.+"}`,
wantMetrics: []map[string]string{
{
"__name__": "importprometheus_series",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "importprometheus_series2",
"label": "foo",
"label1": "value1",
"el1": "elv1",
"el2": "elv2",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456700, Value: 10},
{Timestamp: 1707123456800, Value: 20},
},
})
// prometheus remote write format
pbData := prompb.WriteRequest{
Timeseries: []prompb.TimeSeries{
{
Labels: []prompb.Label{
{
Name: "__name__",
Value: "prometheusrw_series",
},
},
Samples: []prompb.Sample{
{
Value: 10,
Timestamp: 1707123456700, // 2024-02-05T08:57:36.700Z
},
},
},
{
Labels: []prompb.Label{
{
Name: "__name__",
Value: "prometheusrw_series2",
},
{
Name: "label",
Value: "foo2",
},
{
Name: "label1",
Value: "value1",
},
},
Samples: []prompb.Sample{
{
Value: 20,
Timestamp: 1707123456800, // 2024-02-05T08:57:36.800Z
},
},
},
},
Metadata: []prompb.MetricMetadata{
{
Type: 1,
MetricFamilyName: "prometheusrw_series",
Help: "some help",
Unit: "",
},
{
Type: 1,
MetricFamilyName: "prometheusrw_series2",
Help: "some help2",
Unit: "",
},
},
}
sut.PrometheusAPIV1Write(t, pbData, apptest.QueryOpts{})
sut.ForceFlush(t)
f(sut, &opts{
query: `{__name__=~"prometheusrw.+"}`,
wantMetrics: []map[string]string{
{
"__name__": "prometheusrw_series",
},
{
"__name__": "prometheusrw_series2",
"label": "foo2",
"label1": "value1",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456700, Value: 10}, // 2024-02-05T08:57:36.700Z
{Timestamp: 1707123456800, Value: 20}, // 2024-02-05T08:57:36.700Z
},
})
// zabbixconnector format
sut.ZabbixConnectorHistory(t,
[]string{
`{"host":{"host":"h1","name":"n1"},"item_tags":[], "itemid":1,"name":"zabbixconnector_series","clock":1707123456,"ns":700000000,"value":10,"type":0}`,
`{"host":{"host":"h2","name":"n2"},"item_tags":[{"tag":"foo2","value":"value1"}], "itemid":1,"name":"zabbixconnector_series2","clock":1707123456,"ns":800000000,"value":20,"type":0}`,
},
apptest.QueryOpts{})
sut.ForceFlush(t)
f(sut, &opts{
query: `{__name__=~"zabbixconnector.+"}`,
wantMetrics: []map[string]string{
{
"__name__": "zabbixconnector_series",
"host": "h1",
"hostname": "n1",
},
{
"__name__": "zabbixconnector_series2",
"host": "h2",
"hostname": "n2",
"tag_foo2": "value1",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456700, Value: 10}, // 2024-02-05T08:57:36.700Z
{Timestamp: 1707123456800, Value: 20}, // 2024-02-05T08:57:36.700Z
},
})
}
func TestClusterIngestionProtocols(t *testing.T) {
fs.MustRemoveDir(t.Name())
tc := apptest.NewTestCase(t)
defer tc.Stop()
vmstorage := tc.MustStartVmstorage("vmstorage", []string{
"-storageDataPath=" + tc.Dir() + "/vmstorage",
"-retentionPeriod=100y",
})
vminsert := tc.MustStartVminsert("vminsert", []string{
"-storageNode=" + vmstorage.VminsertAddr(),
})
vmselect := tc.MustStartVmselect("vmselect", []string{
"-storageNode=" + vmstorage.VmselectAddr(),
})
type opts struct {
query string
wantMetrics []map[string]string
wantSamples []*apptest.Sample
}
f := func(opts *opts) {
t.Helper()
wantResult := []*apptest.QueryResult{}
for idx, wm := range opts.wantMetrics {
wantResult = append(wantResult, &apptest.QueryResult{
Metric: wm,
Samples: []*apptest.Sample{opts.wantSamples[idx]},
})
}
tc.Assert(&apptest.AssertOptions{
Msg: "unexpected /export query response",
Got: func() any {
got := vmselect.PrometheusAPIV1Export(t, opts.query, apptest.QueryOpts{
Start: "2024-02-05T08:50:00.700Z",
End: "2024-02-05T09:00:00.700Z",
})
got.Sort()
return got
},
Want: &apptest.PrometheusAPIV1QueryResponse{Data: &apptest.QueryData{Result: wantResult}},
CmpOpts: []cmp.Option{
cmpopts.IgnoreFields(apptest.PrometheusAPIV1QueryResponse{}, "Status", "Data.ResultType"),
},
})
}
// prometheus text exposition format
vminsert.PrometheusAPIV1ImportPrometheus(t, []string{
`# HELP importprometheus_series some help message`,
`# TYPE importprometheus_series gauge`,
`importprometheus_series 10 1707123456700`, // 2024-02-05T08:57:36.700Z
`# HELP importprometheus_series2 some help message second one`,
`# TYPE importprometheus_series2 gauge`,
`importprometheus_series2{label="foo",label1="value1"} 20 1707123456800`, // 2024-02-05T08:57:36.800Z
}, apptest.QueryOpts{
ExtraLabels: []string{"el1=elv1", "el2=elv2"},
})
vmstorage.ForceFlush(t)
f(&opts{
query: `{__name__=~"importprometheus.+"}`,
wantMetrics: []map[string]string{
{
"__name__": "importprometheus_series",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "importprometheus_series2",
"label": "foo",
"label1": "value1",
"el1": "elv1",
"el2": "elv2",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456700, Value: 10},
{Timestamp: 1707123456800, Value: 20},
},
})
// influx line format
vminsert.InfluxWrite(t, []string{
`influxline series1=10 1707123456700`, // 2024-02-05T08:57:36.700Z
`influxline,label=foo1,label1=value1,label2=value2 series2=40 1707123456800`, // 2024-02-05T08:57:36.800Z
}, apptest.QueryOpts{
ExtraLabels: []string{"el1=elv1", "el2=elv2"},
})
vmstorage.ForceFlush(t)
f(&opts{
query: `{__name__=~"influxline.+"}`,
wantMetrics: []map[string]string{
{
"__name__": "influxline_series1",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "influxline_series2",
"label": "foo1",
"label1": "value1",
"label2": "value2",
"el1": "elv1",
"el2": "elv2",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456700, Value: 10},
{Timestamp: 1707123456800, Value: 40},
},
})
// CSV import
vminsert.PrometheusAPIV1ImportCSV(t, []string{
`GOOG,1.23,4.56,NYSE,1707123457`, // 2024-02-05T08:57:37.000Z
`MSFT,23,56,NASDAQ,1707123457`, // 2024-02-05T08:57:37.000Z
}, apptest.QueryOpts{
ExtraLabels: []string{"el1=elv1", "el2=elv2"},
Format: "2:metric:csv_import,3:metric:csv_import_v2,1:label:ticker,4:label:market,5:time:unix_s",
})
vmstorage.ForceFlush(t)
f(&opts{
query: `{__name__=~"csv_import.*"}`,
wantMetrics: []map[string]string{
{
"__name__": "csv_import",
"ticker": "MSFT",
"market": "NASDAQ",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "csv_import",
"ticker": "GOOG",
"market": "NYSE",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "csv_import_v2",
"ticker": "MSFT",
"market": "NASDAQ",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "csv_import_v2",
"ticker": "GOOG",
"market": "NYSE",
"el1": "elv1",
"el2": "elv2",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123457000, Value: 23}, // 2024-02-05T08:57:37.000Z
{Timestamp: 1707123457000, Value: 1.23}, // 2024-02-05T08:57:37.000Z
{Timestamp: 1707123457000, Value: 56}, // 2024-02-05T08:57:37.000Z
{Timestamp: 1707123457000, Value: 4.56}, // 2024-02-05T08:57:37.000Z
},
})
// openTSDB HTTP write format
vminsert.OpenTSDBAPIPut(t, []string{
`{"metric":"opentsdbimport.foo","value":45.34, "timestamp": "1707123457"}`, // 2024-02-05T08:57:37.000Z
`{"metric":"opentsdbimport.bar","value":43, "timestamp": "1707123456"}`, // 2024-02-05T08:57:36.000Z
}, apptest.QueryOpts{
ExtraLabels: []string{"el1=elv1", "el2=elv2"},
})
vmstorage.ForceFlush(t)
f(&opts{
query: `{__name__=~"opentsdbimport.*"}`,
wantMetrics: []map[string]string{
{
"__name__": "opentsdbimport.bar",
"el1": "elv1",
"el2": "elv2",
},
{
"__name__": "opentsdbimport.foo",
"el1": "elv1",
"el2": "elv2",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456000, Value: 43}, // 2024-02-05T08:57:36.000Z
{Timestamp: 1707123457000, Value: 45.34}, // 2024-02-05T08:57:37.000Z
},
})
// prometheus remote write format
pbData := prompb.WriteRequest{
Timeseries: []prompb.TimeSeries{
{
Labels: []prompb.Label{
{
Name: "__name__",
Value: "prometheusrw_series",
},
},
Samples: []prompb.Sample{
{
Value: 10,
Timestamp: 1707123456700, // 2024-02-05T08:57:36.700Z
},
},
},
{
Labels: []prompb.Label{
{
Name: "__name__",
Value: "prometheusrw_series2",
},
{
Name: "label",
Value: "foo2",
},
{
Name: "label1",
Value: "value1",
},
},
Samples: []prompb.Sample{
{
Value: 20,
Timestamp: 1707123456800, // 2024-02-05T08:57:36.800Z
},
},
},
},
Metadata: []prompb.MetricMetadata{
{
Type: 1,
MetricFamilyName: "prometheusrw_series",
Help: "some help",
Unit: "",
},
{
Type: 1,
MetricFamilyName: "prometheusrw_series2",
Help: "some help2",
Unit: "",
},
},
}
vminsert.PrometheusAPIV1Write(t, pbData, apptest.QueryOpts{})
vmstorage.ForceFlush(t)
f(&opts{
query: `{__name__=~"prometheusrw.+"}`,
wantMetrics: []map[string]string{
{
"__name__": "prometheusrw_series",
},
{
"__name__": "prometheusrw_series2",
"label": "foo2",
"label1": "value1",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456700, Value: 10}, // 2024-02-05T08:57:36.700Z
{Timestamp: 1707123456800, Value: 20}, // 2024-02-05T08:57:36.700Z
},
})
// zabbixconnector format
vminsert.ZabbixConnectorHistory(t,
[]string{
`{"host":{"host":"h1","name":"n1"},"item_tags":[], "itemid":1,"name":"zabbixconnector_series","clock":1707123456,"ns":700000000,"value":10,"type":0}`,
`{"host":{"host":"h2","name":"n2"},"item_tags":[{"tag":"foo2","value":"value1"}], "itemid":1,"name":"zabbixconnector_series2","clock":1707123456,"ns":800000000,"value":20,"type":0}`,
},
apptest.QueryOpts{})
vmstorage.ForceFlush(t)
f(&opts{
query: `{__name__=~"zabbixconnector.+"}`,
wantMetrics: []map[string]string{
{
"__name__": "zabbixconnector_series",
"host": "h1",
"hostname": "n1",
},
{
"__name__": "zabbixconnector_series2",
"host": "h2",
"hostname": "n2",
"tag_foo2": "value1",
},
},
wantSamples: []*apptest.Sample{
{Timestamp: 1707123456700, Value: 10}, // 2024-02-05T08:57:36.700Z
{Timestamp: 1707123456800, Value: 20}, // 2024-02-05T08:57:36.700Z
},
})
}