From a116f5e7c1d3ec55fd3e782e4f938aba76a4939f Mon Sep 17 00:00:00 2001 From: Artem Navoiev <tenmozes@gmail.com> Date: Mon, 30 Sep 2019 11:25:54 +0300 Subject: [PATCH] Add regression test for query apo (#194) Part of https://github.com/VictoriaMetrics/VictoriaMetrics/issues/187 cover: - https://github.com/VictoriaMetrics/VictoriaMetrics/issues/184 --- app/victoria-metrics/main_test.go | 134 +++++++++++------- app/victoria-metrics/test/parser.go | 51 +++++++ app/victoria-metrics/test/prom_types.go | 2 - .../testdata/graphite/basic.json | 4 +- .../graphite/subquery-aggregation.json | 14 ++ .../testdata/influxdb/basic.json | 2 +- .../testdata/opentsdb/basic.json | 4 +- .../testdata/opentsdbhttp/basic.json | 4 +- .../testdata/opentsdbhttp/multi_line.json | 6 +- .../testdata/prometheus/basic.json | 2 +- .../prometheus/case-sensitive-regex.json | 2 +- .../testdata/prometheus/duplicate-label.json | 2 +- .../testdata/prometheus/match-series.json | 2 +- 13 files changed, 161 insertions(+), 68 deletions(-) create mode 100644 app/victoria-metrics/test/parser.go create mode 100644 app/victoria-metrics/testdata/graphite/subquery-aggregation.json diff --git a/app/victoria-metrics/main_test.go b/app/victoria-metrics/main_test.go index b0fc39c3eb..995ed8221c 100644 --- a/app/victoria-metrics/main_test.go +++ b/app/victoria-metrics/main_test.go @@ -50,13 +50,6 @@ const ( testStorageInitTimeout = 10 * time.Second ) -const ( - tplWordTime = "{TIME}" - tplQuotedWordTime = `"{TIME}"` - tplQuotedWordTimeSeconds = `"{TIME_S}"` - tplQuotedWordTimeMillis = `"{TIME_MS}"` -) - var ( storagePath string insertionTime = time.Now().UTC() @@ -64,10 +57,11 @@ var ( type test struct { Name string `json:"name"` - Data string `json:"data"` + Data []string `json:"data"` Query []string `json:"query"` ResultMetrics []Metric `json:"result_metrics"` ResultSeries Series `json:"result_series"` + ResultQuery Query `json:"result_query"` Issue string `json:"issue"` } @@ -77,28 +71,32 @@ type Metric struct { Timestamps []int64 `json:"timestamps"` } +func (r *Metric) UnmarshalJSON(b []byte) error { + type plain Metric + return json.Unmarshal(testutil.PopulateTimeTpl(b, insertionTime), (*plain)(r)) +} + type Series struct { Status string `json:"status"` Data []map[string]string `json:"data"` } - -func (r *Metric) UnmarshalJSON(b []byte) error { - type plain Metric - return json.Unmarshal(populateTimeTpl(b), (*plain)(r)) +type Query struct { + Status string `json:"status"` + Data QueryData `json:"data"` +} +type QueryData struct { + ResultType string `json:"resultType"` + Result []QueryDataResult `json:"result"` } -func populateTimeTpl(b []byte) []byte { - var ( - tplTimeToQuotedMS = [2][]byte{[]byte(tplQuotedWordTimeMillis), []byte(fmt.Sprintf("%d", timeToMillis(insertionTime)))} - tpsTimeToQuotedS = [2][]byte{[]byte(tplQuotedWordTimeSeconds), []byte(fmt.Sprintf("%d", insertionTime.Unix()*1e3))} - ) - tpls := [][2][]byte{ - tplTimeToQuotedMS, tpsTimeToQuotedS, - } - for i := range tpls { - b = bytes.ReplaceAll(b, tpls[i][0], tpls[i][1]) - } - return b +type QueryDataResult struct { + Metric map[string]string `json:"metric"` + Value []interface{} `json:"value"` +} + +func (r *QueryDataResult) UnmarshalJSON(b []byte) error { + type plain QueryDataResult + return json.Unmarshal(testutil.PopulateTimeTpl(b, insertionTime), (*plain)(r)) } func TestMain(m *testing.M) { @@ -182,10 +180,10 @@ func TestWriteRead(t *testing.T) { func testWrite(t *testing.T) { t.Run("prometheus", func(t *testing.T) { - for _, test := range readIn("prometheus", t, fmt.Sprintf("%d", timeToMillis(insertionTime))) { + for _, test := range readIn("prometheus", t, insertionTime) { s := newSuite(t) r := testutil.WriteRequest{} - s.noError(json.Unmarshal([]byte(test.Data), &r.Timeseries)) + s.noError(json.Unmarshal([]byte(strings.Join(test.Data, "\n")), &r.Timeseries)) data, err := testutil.Compress(r) s.greaterThan(len(r.Timeseries), 0) if err != nil { @@ -197,39 +195,39 @@ func testWrite(t *testing.T) { }) t.Run("influxdb", func(t *testing.T) { - for _, x := range readIn("influxdb", t, fmt.Sprintf("%d", insertionTime.UnixNano())) { + for _, x := range readIn("influxdb", t, insertionTime) { test := x t.Run(test.Name, func(t *testing.T) { t.Parallel() - httpWrite(t, testWriteHTTPPath, bytes.NewBufferString(test.Data)) + httpWrite(t, testWriteHTTPPath, bytes.NewBufferString(strings.Join(test.Data, "\n"))) }) } }) t.Run("graphite", func(t *testing.T) { - for _, x := range readIn("graphite", t, fmt.Sprintf("%d", insertionTime.Unix())) { + for _, x := range readIn("graphite", t, insertionTime) { test := x t.Run(test.Name, func(t *testing.T) { t.Parallel() - tcpWrite(t, "127.0.0.1"+testStatsDListenAddr, test.Data) + tcpWrite(t, "127.0.0.1"+testStatsDListenAddr, strings.Join(test.Data, "\n")) }) } }) t.Run("opentsdb", func(t *testing.T) { - for _, x := range readIn("opentsdb", t, fmt.Sprintf("%d", insertionTime.Unix())) { + for _, x := range readIn("opentsdb", t, insertionTime) { test := x t.Run(test.Name, func(t *testing.T) { t.Parallel() - tcpWrite(t, "127.0.0.1"+testOpenTSDBListenAddr, test.Data) + tcpWrite(t, "127.0.0.1"+testOpenTSDBListenAddr, strings.Join(test.Data, "\n")) }) } }) t.Run("opentsdbhttp", func(t *testing.T) { - for _, x := range readIn("opentsdbhttp", t, fmt.Sprintf("%d", insertionTime.Unix())) { + for _, x := range readIn("opentsdbhttp", t, insertionTime) { test := x t.Run(test.Name, func(t *testing.T) { t.Parallel() logger.Infof("writing %s", test.Data) - httpWrite(t, testOpenTSDBWriteHTTPPath, bytes.NewBufferString(test.Data)) + httpWrite(t, testOpenTSDBWriteHTTPPath, bytes.NewBufferString(strings.Join(test.Data, "\n"))) }) } }) @@ -238,16 +236,25 @@ func testWrite(t *testing.T) { func testRead(t *testing.T) { for _, engine := range []string{"prometheus", "graphite", "opentsdb", "influxdb", "opentsdbhttp"} { t.Run(engine, func(t *testing.T) { - for _, x := range readIn(engine, t, fmt.Sprintf("%d", insertionTime.UnixNano())) { + for _, x := range readIn(engine, t, insertionTime) { test := x t.Run(test.Name, func(t *testing.T) { t.Parallel() for _, q := range test.Query { + q = testutil.PopulateTimeTplString(q, insertionTime) switch true { case strings.HasPrefix(q, "/api/v1/export"): checkMetricsResult(t, httpReadMetrics(t, testReadHTTPPath, q), test.ResultMetrics, q, test.Issue) case strings.HasPrefix(q, "/api/v1/series"): - checkSeriesResult(t, httpReadSeries(t, testReadHTTPPath, q), test.ResultSeries, q, test.Issue) + s := Series{} + httpReadStruct(t, testReadHTTPPath, q, &s) + checkSeriesResult(t, s, test.ResultSeries, q, test.Issue) + case strings.HasPrefix(q, "/api/v1/query_range"): + t.Fatalf("unsupported read query %s", q) + case strings.HasPrefix(q, "/api/v1/query"): + queryResult := Query{} + httpReadStruct(t, testReadHTTPPath, q, &queryResult) + checkQueryResult(t, queryResult, test.ResultQuery, q, test.Issue) default: t.Fatalf("unsupported read query %s", q) } @@ -258,7 +265,7 @@ func testRead(t *testing.T) { } } -func readIn(readFor string, t *testing.T, timeStr string) []test { +func readIn(readFor string, t *testing.T, insertTime time.Time) []test { t.Helper() s := newSuite(t) var tt []test @@ -270,8 +277,9 @@ func readIn(readFor string, t *testing.T, timeStr string) []test { s.noError(err) item := test{} s.noError(json.Unmarshal(b, &item)) - item.Data = strings.Replace(item.Data, tplQuotedWordTime, timeStr, -1) - item.Data = strings.Replace(item.Data, tplWordTime, timeStr, -1) + for i := range item.Data { + item.Data[i] = testutil.PopulateTimeTplString(item.Data[i], insertTime) + } tt = append(tt, item) return nil })) @@ -316,19 +324,14 @@ func httpReadMetrics(t *testing.T, address, query string) []Metric { } return rows } - -func httpReadSeries(t *testing.T, address, query string) Series { +func httpReadStruct(t *testing.T, address, query string, dst interface{}) { t.Helper() s := newSuite(t) resp, err := http.Get(address + query) s.noError(err) defer resp.Body.Close() s.equalInt(resp.StatusCode, 200) - var Series Series - if err := json.NewDecoder(resp.Body).Decode(&Series); err != nil { - s.noError(err) - } - return Series + s.noError(json.NewDecoder(resp.Body).Decode(dst)) } func checkMetricsResult(t *testing.T, got, want []Metric, query, issue string) { @@ -358,7 +361,7 @@ func removeIfFoundMetrics(r Metric, contains []Metric) []Metric { func checkSeriesResult(t *testing.T, got, want Series, query, issue string) { t.Helper() if got.Status != want.Status { - t.Fatalf("query %s. Result ResultSeries status mismatch %q - %q. %s", query, want.Status, got.Status, issue) + t.Fatalf("query %s. Result Series status mismatch %q - %q. %s", query, want.Status, got.Status, issue) } wantData := append([]map[string]string(nil), want.Data...) for _, r := range got.Data { @@ -368,7 +371,7 @@ func checkSeriesResult(t *testing.T, got, want Series, query, issue string) { if issue != "" { issue = "Regression in " + issue } - t.Fatalf("query %s. Result series %+v not found in %+v.%s", query, wantData, got.Data, issue) + t.Fatalf("query %s. Result Series %+v not found in %+v.%s", query, wantData, got.Data, issue) } } @@ -382,6 +385,37 @@ func removeIfFoundSeries(r map[string]string, contains []map[string]string) []ma return contains } +func checkQueryResult(t *testing.T, got, want Query, query, issue string) { + t.Helper() + if got.Status != want.Status { + t.Fatalf("query %s. Result Query status mismatch %q - %q. %s", query, want.Status, got.Status, issue) + } + if got.Data.ResultType != want.Data.ResultType { + t.Fatalf("query %s. Result Query Data ResultType status mismatch %q - %q. %s", query, want.Data.ResultType, got.Data.ResultType, issue) + } + + wantData := append([]QueryDataResult(nil), want.Data.Result...) + for _, r := range got.Data.Result { + wantData = removeIfFoundQueryData(r, wantData) + } + if len(wantData) > 0 { + if issue != "" { + issue = "Regression in " + issue + } + t.Fatalf("query %s. Result query %+v not found in %+v.%s", query, wantData, got.Data.Result, issue) + } +} + +func removeIfFoundQueryData(r QueryDataResult, contains []QueryDataResult) []QueryDataResult { + for i, item := range contains { + if reflect.DeepEqual(r.Metric, item.Metric) && reflect.DeepEqual(r.Value[0], item.Value[0]) && reflect.DeepEqual(r.Value[1], item.Value[1]) { + contains[i] = contains[len(contains)-1] + return contains[:len(contains)-1] + } + } + return contains +} + type suite struct{ t *testing.T } func newSuite(t *testing.T) *suite { return &suite{t: t} } @@ -409,7 +443,3 @@ func (s *suite) greaterThan(a, b int) { s.t.FailNow() } } - -func timeToMillis(t time.Time) int64 { - return t.UnixNano() / 1e6 -} diff --git a/app/victoria-metrics/test/parser.go b/app/victoria-metrics/test/parser.go new file mode 100644 index 0000000000..1cecc29f3d --- /dev/null +++ b/app/victoria-metrics/test/parser.go @@ -0,0 +1,51 @@ +// +build integration + +package test + +import ( + "fmt" + "log" + "regexp" + "strings" + "time" +) + +var ( + parseTimeExpRegex = regexp.MustCompile(`"?{TIME[^}]*}"?`) + extractRegex = regexp.MustCompile(`"?{([^}]*)}"?`) +) + +func PopulateTimeTplString(s string, t time.Time) string { + return string(PopulateTimeTpl([]byte(s), t)) +} + +func PopulateTimeTpl(b []byte, t time.Time) []byte { + return parseTimeExpRegex.ReplaceAllFunc(b, func(repl []byte) []byte { + repl = extractRegex.FindSubmatch(repl)[1] + parts := strings.SplitN(string(repl), "-", 2) + if len(parts) == 2 { + duration, err := time.ParseDuration(strings.TrimSpace(parts[1])) + if err != nil { + log.Fatalf("error %s parsing duration %s in %s", err, parts[1], repl) + } + t = t.Add(-duration) + } + switch strings.TrimSpace(parts[0]) { + case `TIME_S`: + return []byte(fmt.Sprintf("%d", t.Unix())) + case `TIME_MSZ`: + return []byte(fmt.Sprintf("%d", t.Unix()*1e3)) + case `TIME_MS`: + return []byte(fmt.Sprintf("%d", timeToMillis(t))) + case `TIME_NS`: + return []byte(fmt.Sprintf("%d", t.UnixNano())) + default: + log.Fatalf("unkown time pattern %s in %s", parts[0], repl) + } + return repl + }) +} + +func timeToMillis(t time.Time) int64 { + return t.UnixNano() / 1e6 +} diff --git a/app/victoria-metrics/test/prom_types.go b/app/victoria-metrics/test/prom_types.go index c52b5639c6..8aaf1eddab 100644 --- a/app/victoria-metrics/test/prom_types.go +++ b/app/victoria-metrics/test/prom_types.go @@ -5,7 +5,6 @@ package test import ( "encoding/binary" - "log" "math" "math/bits" ) @@ -124,7 +123,6 @@ func (m *Sample) MarshalTo(dAtA []byte) (int, error) { func (m *Sample) MarshalToSizedBuffer(dAtA []byte) (int, error) { i := len(dAtA) if m.Timestamp != 0 { - log.Printf("prom types %d", m.Timestamp) i = encodeVarintTypes(dAtA, i, uint64(m.Timestamp)) i-- dAtA[i] = 0x10 diff --git a/app/victoria-metrics/testdata/graphite/basic.json b/app/victoria-metrics/testdata/graphite/basic.json index 8aab533660..5a93c15fc7 100644 --- a/app/victoria-metrics/testdata/graphite/basic.json +++ b/app/victoria-metrics/testdata/graphite/basic.json @@ -1,8 +1,8 @@ { "name": "basic_insertion", - "data": "graphite.foo.bar.baz;tag1=value1;tag2=value2 123 {TIME}", + "data": ["graphite.foo.bar.baz;tag1=value1;tag2=value2 123 {TIME_S}"], "query": ["/api/v1/export?match={__name__!=''}"], "result_metrics": [ - {"metric":{"__name__":"graphite.foo.bar.baz","tag1":"value1","tag2":"value2"},"values":[123], "timestamps": ["{TIME_S}"]} + {"metric":{"__name__":"graphite.foo.bar.baz","tag1":"value1","tag2":"value2"},"values":[123], "timestamps": ["{TIME_MSZ}"]} ] } diff --git a/app/victoria-metrics/testdata/graphite/subquery-aggregation.json b/app/victoria-metrics/testdata/graphite/subquery-aggregation.json new file mode 100644 index 0000000000..882f8b5df2 --- /dev/null +++ b/app/victoria-metrics/testdata/graphite/subquery-aggregation.json @@ -0,0 +1,14 @@ +{ + "name": "subquery-aggregation", + "issue": "https://github.com/VictoriaMetrics/VictoriaMetrics/issues/184", + "data": [ + "forms_daily_count;item=x 1 {TIME_S-1m}", + "forms_daily_count;item=x 2 {TIME_S-2m}", + "forms_daily_count;item=y 3 {TIME_S-1m}", + "forms_daily_count;item=y 4 {TIME_S-2m}"], + "query": ["/api/v1/query?query=min%20by%20(item)%20(min_over_time(forms_daily_count[10m:1m]))&time={TIME_S-1m}"], + "result_query": { + "status":"success", + "data":{"resultType":"vector","result":[{"metric":{"item":"x"},"value":["{TIME_S-1m}","1"]},{"metric":{"item":"y"},"value":["{TIME_S-1m}","3"]}]} + } +} diff --git a/app/victoria-metrics/testdata/influxdb/basic.json b/app/victoria-metrics/testdata/influxdb/basic.json index 09d44b0b94..6127e69566 100644 --- a/app/victoria-metrics/testdata/influxdb/basic.json +++ b/app/victoria-metrics/testdata/influxdb/basic.json @@ -1,6 +1,6 @@ { "name": "basic_insertion", - "data": "measurement,tag1=value1,tag2=value2 field1=1.23,field2=123 {TIME}", + "data": ["measurement,tag1=value1,tag2=value2 field1=1.23,field2=123 {TIME_NS}"], "query": ["/api/v1/export?match={__name__!=''}"], "result_metrics": [ {"metric":{"__name__":"measurement_field2","tag1":"value1","tag2":"value2"},"values":[123], "timestamps": ["{TIME_MS}"]}, diff --git a/app/victoria-metrics/testdata/opentsdb/basic.json b/app/victoria-metrics/testdata/opentsdb/basic.json index 010b40ffbf..3250c19798 100644 --- a/app/victoria-metrics/testdata/opentsdb/basic.json +++ b/app/victoria-metrics/testdata/opentsdb/basic.json @@ -1,8 +1,8 @@ { "name": "basic_insertion", - "data": "put openstdb.foo.bar.baz {TIME} 123 tag1=value1 tag2=value2", + "data": ["put openstdb.foo.bar.baz {TIME_S} 123 tag1=value1 tag2=value2"], "query": ["/api/v1/export?match={__name__!=''}"], "result_metrics": [ - {"metric":{"__name__":"openstdb.foo.bar.baz","tag1":"value1","tag2":"value2"},"values":[123], "timestamps": ["{TIME_S}"]} + {"metric":{"__name__":"openstdb.foo.bar.baz","tag1":"value1","tag2":"value2"},"values":[123], "timestamps": ["{TIME_MSZ}"]} ] } diff --git a/app/victoria-metrics/testdata/opentsdbhttp/basic.json b/app/victoria-metrics/testdata/opentsdbhttp/basic.json index e8eb44c8d4..343b88db9a 100644 --- a/app/victoria-metrics/testdata/opentsdbhttp/basic.json +++ b/app/victoria-metrics/testdata/opentsdbhttp/basic.json @@ -1,8 +1,8 @@ { "name": "basic_insertion", - "data": "{\"metric\": \"opentsdbhttp.foo\", \"value\": 1001, \"timestamp\": {TIME}, \"tags\": {\"bar\":\"baz\", \"x\": \"y\"}}", + "data": ["{\"metric\": \"opentsdbhttp.foo\", \"value\": 1001, \"timestamp\": {TIME_S}, \"tags\": {\"bar\":\"baz\", \"x\": \"y\"}}"], "query": ["/api/v1/export?match={__name__!=''}"], "result_metrics": [ - {"metric":{"__name__":"opentsdbhttp.foo","bar":"baz","x":"y"},"values":[1001], "timestamps": ["{TIME_S}"]} + {"metric":{"__name__":"opentsdbhttp.foo","bar":"baz","x":"y"},"values":[1001], "timestamps": ["{TIME_MSZ}"]} ] } diff --git a/app/victoria-metrics/testdata/opentsdbhttp/multi_line.json b/app/victoria-metrics/testdata/opentsdbhttp/multi_line.json index f1f444f759..35780861a4 100644 --- a/app/victoria-metrics/testdata/opentsdbhttp/multi_line.json +++ b/app/victoria-metrics/testdata/opentsdbhttp/multi_line.json @@ -1,9 +1,9 @@ { "name": "multiline", - "data": "[{\"metric\": \"opentsdbhttp.multiline1\", \"value\": 1001, \"timestamp\": \"{TIME}\", \"tags\": {\"bar\":\"baz\", \"x\": \"y\"}}, {\"metric\": \"opentsdbhttp.multiline2\", \"value\": 1002, \"timestamp\": {TIME}}]", + "data": ["[{\"metric\": \"opentsdbhttp.multiline1\", \"value\": 1001, \"timestamp\": \"{TIME_S}\", \"tags\": {\"bar\":\"baz\", \"x\": \"y\"}}, {\"metric\": \"opentsdbhttp.multiline2\", \"value\": 1002, \"timestamp\": {TIME_S}}]"], "query": ["/api/v1/export?match={__name__!=''}"], "result_metrics": [ - {"metric":{"__name__":"opentsdbhttp.multiline1","bar":"baz","x":"y"},"values":[1001], "timestamps": ["{TIME_S}"]}, - {"metric":{"__name__":"opentsdbhttp.multiline2"},"values":[1002], "timestamps": ["{TIME_S}"]} + {"metric":{"__name__":"opentsdbhttp.multiline1","bar":"baz","x":"y"},"values":[1001], "timestamps": ["{TIME_MSZ}"]}, + {"metric":{"__name__":"opentsdbhttp.multiline2"},"values":[1002], "timestamps": ["{TIME_MSZ}"]} ] } diff --git a/app/victoria-metrics/testdata/prometheus/basic.json b/app/victoria-metrics/testdata/prometheus/basic.json index 02cd92d3e2..6bd295787a 100644 --- a/app/victoria-metrics/testdata/prometheus/basic.json +++ b/app/victoria-metrics/testdata/prometheus/basic.json @@ -1,6 +1,6 @@ { "name": "basic_insertion", - "data": "[{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.bar\"},{\"name\":\"baz\",\"value\":\"qux\"}],\"samples\":[{\"value\":100000,\"timestamp\":\"{TIME}\"}]}]", + "data": ["[{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.bar\"},{\"name\":\"baz\",\"value\":\"qux\"}],\"samples\":[{\"value\":100000,\"timestamp\":\"{TIME_MS}\"}]}]"], "query": ["/api/v1/export?match={__name__!=''}"], "result_metrics": [ {"metric":{"__name__":"prometheus.bar","baz":"qux"},"values":[100000], "timestamps": ["{TIME_MS}"]} diff --git a/app/victoria-metrics/testdata/prometheus/case-sensitive-regex.json b/app/victoria-metrics/testdata/prometheus/case-sensitive-regex.json index f0241f8f40..997163e07e 100644 --- a/app/victoria-metrics/testdata/prometheus/case-sensitive-regex.json +++ b/app/victoria-metrics/testdata/prometheus/case-sensitive-regex.json @@ -1,7 +1,7 @@ { "name": "case-sensitive-regex", "issue": "https://github.com/VictoriaMetrics/VictoriaMetrics/issues/161", - "data": "[{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.sensitiveRegex\"},{\"name\":\"label\",\"value\":\"sensitiveRegex\"}],\"samples\":[{\"value\":2,\"timestamp\":\"{TIME}\"}]},{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.sensitiveRegex\"},{\"name\":\"label\",\"value\":\"SensitiveRegex\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME}\"}]}]", + "data": ["[{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.sensitiveRegex\"},{\"name\":\"label\",\"value\":\"sensitiveRegex\"}],\"samples\":[{\"value\":2,\"timestamp\":\"{TIME_MS}\"}]},{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.sensitiveRegex\"},{\"name\":\"label\",\"value\":\"SensitiveRegex\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME_MS}\"}]}]"], "query": ["/api/v1/export?match={label=~'(?i)sensitiveregex'}"], "result_metrics": [ {"metric":{"__name__":"prometheus.sensitiveRegex","label":"sensitiveRegex"},"values":[2], "timestamps": ["{TIME_MS}"]}, diff --git a/app/victoria-metrics/testdata/prometheus/duplicate-label.json b/app/victoria-metrics/testdata/prometheus/duplicate-label.json index 0da251329d..1f27afaf8b 100644 --- a/app/victoria-metrics/testdata/prometheus/duplicate-label.json +++ b/app/victoria-metrics/testdata/prometheus/duplicate-label.json @@ -1,7 +1,7 @@ { "name": "duplicate_label", "issue": "https://github.com/VictoriaMetrics/VictoriaMetrics/issues/172", - "data": "[{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.duplicate_label\"},{\"name\":\"duplicate\",\"value\":\"label\"},{\"name\":\"duplicate\",\"value\":\"label\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME}\"}]}]", + "data": ["[{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.duplicate_label\"},{\"name\":\"duplicate\",\"value\":\"label\"},{\"name\":\"duplicate\",\"value\":\"label\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME_MS}\"}]}]"], "query": ["/api/v1/export?match={__name__!=''}"], "result_metrics": [ {"metric":{"__name__":"prometheus.duplicate_label","duplicate":"label"},"values":[1], "timestamps": ["{TIME_MS}"]} diff --git a/app/victoria-metrics/testdata/prometheus/match-series.json b/app/victoria-metrics/testdata/prometheus/match-series.json index 9d1547347a..67164535b5 100644 --- a/app/victoria-metrics/testdata/prometheus/match-series.json +++ b/app/victoria-metrics/testdata/prometheus/match-series.json @@ -1,7 +1,7 @@ { "name": "match_series", "issue": "https://github.com/VictoriaMetrics/VictoriaMetrics/issues/155", - "data": "[{\"labels\":[{\"name\":\"__name__\",\"value\":\"MatchSeries\"},{\"name\":\"db\",\"value\":\"TenMinute\"},{\"name\":\"TurbineType\",\"value\":\"V112\"},{\"name\":\"Park\",\"value\":\"1\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME}\"}]},{\"labels\":[{\"name\":\"__name__\",\"value\":\"MatchSeries\"},{\"name\":\"db\",\"value\":\"TenMinute\"},{\"name\":\"TurbineType\",\"value\":\"V112\"},{\"name\":\"Park\",\"value\":\"2\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME}\"}]},{\"labels\":[{\"name\":\"__name__\",\"value\":\"MatchSeries\"},{\"name\":\"db\",\"value\":\"TenMinute\"},{\"name\":\"TurbineType\",\"value\":\"V112\"},{\"name\":\"Park\",\"value\":\"3\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME}\"}]},{\"labels\":[{\"name\":\"__name__\",\"value\":\"MatchSeries\"},{\"name\":\"db\",\"value\":\"TenMinute\"},{\"name\":\"TurbineType\",\"value\":\"V112\"},{\"name\":\"Park\",\"value\":\"4\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME}\"}]}]", + "data": ["[{\"labels\":[{\"name\":\"__name__\",\"value\":\"MatchSeries\"},{\"name\":\"db\",\"value\":\"TenMinute\"},{\"name\":\"TurbineType\",\"value\":\"V112\"},{\"name\":\"Park\",\"value\":\"1\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME_MS}\"}]},{\"labels\":[{\"name\":\"__name__\",\"value\":\"MatchSeries\"},{\"name\":\"db\",\"value\":\"TenMinute\"},{\"name\":\"TurbineType\",\"value\":\"V112\"},{\"name\":\"Park\",\"value\":\"2\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME_MS}\"}]},{\"labels\":[{\"name\":\"__name__\",\"value\":\"MatchSeries\"},{\"name\":\"db\",\"value\":\"TenMinute\"},{\"name\":\"TurbineType\",\"value\":\"V112\"},{\"name\":\"Park\",\"value\":\"3\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME_MS}\"}]},{\"labels\":[{\"name\":\"__name__\",\"value\":\"MatchSeries\"},{\"name\":\"db\",\"value\":\"TenMinute\"},{\"name\":\"TurbineType\",\"value\":\"V112\"},{\"name\":\"Park\",\"value\":\"4\"}],\"samples\":[{\"value\":1,\"timestamp\":\"{TIME_MS}\"}]}]"], "query": ["/api/v1/series?match[]={__name__='MatchSeries'}", "/api/v1/series?match[]={__name__=~'MatchSeries.*'}"], "result_series": { "status": "success",