Artem Navoiev 2019-09-27 09:48:53 +03:00
parent fa81f82714
commit 1e6ae9eff4
10 changed files with 114 additions and 39 deletions

View file

@ -65,25 +65,26 @@ var (
type test struct {
Name string `json:"name"`
Data string `json:"data"`
Query string `json:"query"`
Result []Row `json:"result"`
Query []string `json:"query"`
ResultMetrics []Metric `json:"result_metrics"`
ResultSeries Series `json:"result_series"`
Issue string `json:"issue"`
}
type Row struct {
type Metric struct {
Metric map[string]string `json:"metric"`
Values []float64 `json:"values"`
Timestamps []int64 `json:"timestamps"`
}
func (r *Row) UnmarshalJSON(b []byte) error {
type withoutInterface Row
var to withoutInterface
if err := json.Unmarshal(populateTimeTpl(b), &to); err != nil {
return err
}
*r = Row(to)
return nil
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))
}
func populateTimeTpl(b []byte) []byte {
@ -241,7 +242,16 @@ func testRead(t *testing.T) {
test := x
t.Run(test.Name, func(t *testing.T) {
t.Parallel()
rowContains(t, httpRead(t, testReadHTTPPath, test.Query), test.Result, test.Issue)
for _, q := range test.Query {
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)
default:
t.Fatalf("unsupported read query %s", q)
}
}
})
}
})
@ -291,36 +301,50 @@ func tcpWrite(t *testing.T, address string, data string) {
s.equalInt(n, len(data))
}
func httpRead(t *testing.T, address, query string) []Row {
func httpReadMetrics(t *testing.T, address, query string) []Metric {
t.Helper()
s := newSuite(t)
resp, err := http.Get(address + query)
s.noError(err)
defer resp.Body.Close()
s.equalInt(resp.StatusCode, 200)
var rows []Row
var rows []Metric
for dec := json.NewDecoder(resp.Body); dec.More(); {
var row Row
var row Metric
s.noError(dec.Decode(&row))
rows = append(rows, row)
}
return rows
}
func rowContains(t *testing.T, rows, contains []Row, issue string) {
func httpReadSeries(t *testing.T, address, query string) Series {
t.Helper()
for _, r := range rows {
contains = removeIfFound(r, contains)
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)
}
if len(contains) > 0 {
return Series
}
func checkMetricsResult(t *testing.T, got, want []Metric, query, issue string) {
t.Helper()
for _, r := range append([]Metric(nil), got...) {
want = removeIfFoundMetrics(r, want)
}
if len(want) > 0 {
if issue != "" {
issue = "Regression in " + issue
}
t.Fatalf("result rows %+v not found in %+v.%s", contains, rows, issue)
t.Fatalf("query: %s. Result metrics %+v not found in %+v.%s", query, want, got, issue)
}
}
func removeIfFound(r Row, contains []Row) []Row {
func removeIfFoundMetrics(r Metric, contains []Metric) []Metric {
for i, item := range contains {
if reflect.DeepEqual(r.Metric, item.Metric) && reflect.DeepEqual(r.Values, item.Values) &&
reflect.DeepEqual(r.Timestamps, item.Timestamps) {
@ -331,6 +355,33 @@ func removeIfFound(r Row, contains []Row) []Row {
return contains
}
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)
}
wantData := append([]map[string]string(nil), want.Data...)
for _, r := range got.Data {
wantData = removeIfFoundSeries(r, wantData)
}
if len(wantData) > 0 {
if issue != "" {
issue = "Regression in " + issue
}
t.Fatalf("query %s. Result series %+v not found in %+v.%s", query, wantData, got.Data, issue)
}
}
func removeIfFoundSeries(r map[string]string, contains []map[string]string) []map[string]string {
for i, item := range contains {
if reflect.DeepEqual(r, item) {
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} }

View file

@ -1,8 +1,8 @@
{
"name": "basic_insertion",
"data": "graphite.foo.bar.baz;tag1=value1;tag2=value2 123 {TIME}",
"query": "/api/v1/export?match={__name__!=\"\"}",
"result": [
"query": ["/api/v1/export?match={__name__!=''}"],
"result_metrics": [
{"metric":{"__name__":"graphite.foo.bar.baz","tag1":"value1","tag2":"value2"},"values":[123], "timestamps": ["{TIME_S}"]}
]
}

View file

@ -1,8 +1,8 @@
{
"name": "basic_insertion",
"data": "measurement,tag1=value1,tag2=value2 field1=1.23,field2=123 {TIME}",
"query": "/api/v1/export?match={__name__!=\"\"}",
"result": [
"query": ["/api/v1/export?match={__name__!=''}"],
"result_metrics": [
{"metric":{"__name__":"measurement_field2","tag1":"value1","tag2":"value2"},"values":[123], "timestamps": ["{TIME_MS}"]},
{"metric":{"__name__":"measurement_field1","tag1":"value1","tag2":"value2"},"values":[1.23], "timestamps": ["{TIME_MS}"]}
]

View file

@ -1,8 +1,8 @@
{
"name": "basic_insertion",
"data": "put openstdb.foo.bar.baz {TIME} 123 tag1=value1 tag2=value2",
"query": "/api/v1/export?match={__name__!=\"\"}",
"result": [
"query": ["/api/v1/export?match={__name__!=''}"],
"result_metrics": [
{"metric":{"__name__":"openstdb.foo.bar.baz","tag1":"value1","tag2":"value2"},"values":[123], "timestamps": ["{TIME_S}"]}
]
}

View file

@ -1,8 +1,8 @@
{
"name": "basic_insertion",
"data": "{\"metric\": \"opentsdbhttp.foo\", \"value\": 1001, \"timestamp\": {TIME}, \"tags\": {\"bar\":\"baz\", \"x\": \"y\"}}",
"query": "/api/v1/export?match={__name__!=\"\"}",
"result": [
"query": ["/api/v1/export?match={__name__!=''}"],
"result_metrics": [
{"metric":{"__name__":"opentsdbhttp.foo","bar":"baz","x":"y"},"values":[1001], "timestamps": ["{TIME_S}"]}
]
}

View file

@ -1,8 +1,8 @@
{
"name": "multiline",
"data": "[{\"metric\": \"opentsdbhttp.multiline1\", \"value\": 1001, \"timestamp\": \"{TIME}\", \"tags\": {\"bar\":\"baz\", \"x\": \"y\"}}, {\"metric\": \"opentsdbhttp.multiline2\", \"value\": 1002, \"timestamp\": {TIME}}]",
"query": "/api/v1/export?match={__name__!=\"\"}",
"result": [
"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}"]}
]

View file

@ -1,8 +1,8 @@
{
"name": "basic_insertion",
"data": "[{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.bar\"},{\"name\":\"baz\",\"value\":\"qux\"}],\"samples\":[{\"value\":100000,\"timestamp\":{TIME}}]}]",
"query": "/api/v1/export?match={__name__!=''}",
"result": [
"data": "[{\"labels\":[{\"name\":\"__name__\",\"value\":\"prometheus.bar\"},{\"name\":\"baz\",\"value\":\"qux\"}],\"samples\":[{\"value\":100000,\"timestamp\":\"{TIME}\"}]}]",
"query": ["/api/v1/export?match={__name__!=''}"],
"result_metrics": [
{"metric":{"__name__":"prometheus.bar","baz":"qux"},"values":[100000], "timestamps": ["{TIME_MS}"]}
]
}

View file

@ -2,8 +2,8 @@
"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}\"}]}]",
"query": "/api/v1/export?match={label=~'(?i)sensitiveregex'}",
"result": [
"query": ["/api/v1/export?match={label=~'(?i)sensitiveregex'}"],
"result_metrics": [
{"metric":{"__name__":"prometheus.sensitiveRegex","label":"sensitiveRegex"},"values":[2], "timestamps": ["{TIME_MS}"]},
{"metric":{"__name__":"prometheus.sensitiveRegex","label":"SensitiveRegex"},"values":[1], "timestamps": ["{TIME_MS}"]}
]

View file

@ -0,0 +1,9 @@
{
"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}\"}]}]",
"query": ["/api/v1/export?match={__name__!=''}"],
"result_metrics": [
{"metric":{"__name__":"prometheus.duplicate_label","duplicate":"label"},"values":[1], "timestamps": ["{TIME_MS}"]}
]
}

View file

@ -0,0 +1,15 @@
{
"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}\"}]}]",
"query": ["/api/v1/series?match[]={__name__='MatchSeries'}", "/api/v1/series?match[]={__name__=~'MatchSeries.*'}"],
"result_series": {
"status": "success",
"data": [
{"__name__":"MatchSeries","db":"TenMinute","Park":"1","TurbineType":"V112"},
{"__name__":"MatchSeries","db":"TenMinute","Park":"2","TurbineType":"V112"},
{"__name__":"MatchSeries","db":"TenMinute","Park":"3","TurbineType":"V112"},
{"__name__":"MatchSeries","db":"TenMinute","Park":"4","TurbineType":"V112"}
]
}
}