2020-07-10 11:00:35 +02:00
|
|
|
package prometheus
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"compress/gzip"
|
|
|
|
"reflect"
|
2020-09-29 11:10:39 +02:00
|
|
|
"sync"
|
2020-07-10 11:00:35 +02:00
|
|
|
"testing"
|
2020-09-29 11:10:39 +02:00
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/common"
|
2020-07-10 11:00:35 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestParseStream(t *testing.T) {
|
2020-09-29 11:10:39 +02:00
|
|
|
common.StartUnmarshalWorkers()
|
|
|
|
defer common.StopUnmarshalWorkers()
|
|
|
|
|
2020-09-11 12:26:41 +02:00
|
|
|
const defaultTimestamp = 123
|
2020-07-10 11:00:35 +02:00
|
|
|
f := func(s string, rowsExpected []Row) {
|
|
|
|
t.Helper()
|
|
|
|
bb := bytes.NewBufferString(s)
|
|
|
|
var result []Row
|
2020-09-29 11:10:39 +02:00
|
|
|
var lock sync.Mutex
|
|
|
|
doneCh := make(chan struct{})
|
2020-09-11 12:26:41 +02:00
|
|
|
err := ParseStream(bb, defaultTimestamp, false, func(rows []Row) error {
|
2020-09-29 11:10:39 +02:00
|
|
|
lock.Lock()
|
2020-07-10 11:00:35 +02:00
|
|
|
result = appendRowCopies(result, rows)
|
2020-09-29 11:10:39 +02:00
|
|
|
if len(result) == len(rowsExpected) {
|
|
|
|
close(doneCh)
|
|
|
|
}
|
|
|
|
lock.Unlock()
|
2020-07-10 11:00:35 +02:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error when parsing %q: %s", s, err)
|
|
|
|
}
|
2020-09-29 11:10:39 +02:00
|
|
|
select {
|
|
|
|
case <-doneCh:
|
|
|
|
case <-time.After(time.Second):
|
|
|
|
t.Fatalf("timeout")
|
|
|
|
}
|
2020-07-10 11:00:35 +02:00
|
|
|
if !reflect.DeepEqual(result, rowsExpected) {
|
|
|
|
t.Fatalf("unexpected rows parsed; got\n%v\nwant\n%v", result, rowsExpected)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse compressed stream.
|
|
|
|
bb.Reset()
|
|
|
|
zw := gzip.NewWriter(bb)
|
|
|
|
if _, err := zw.Write([]byte(s)); err != nil {
|
|
|
|
t.Fatalf("unexpected error when gzipping %q: %s", s, err)
|
|
|
|
}
|
|
|
|
if err := zw.Close(); err != nil {
|
|
|
|
t.Fatalf("unexpected error when closing gzip writer: %s", err)
|
|
|
|
}
|
|
|
|
result = nil
|
2020-09-29 11:10:39 +02:00
|
|
|
doneCh = make(chan struct{})
|
2020-09-11 12:26:41 +02:00
|
|
|
err = ParseStream(bb, defaultTimestamp, true, func(rows []Row) error {
|
2020-09-29 11:10:39 +02:00
|
|
|
lock.Lock()
|
2020-07-10 11:00:35 +02:00
|
|
|
result = appendRowCopies(result, rows)
|
2020-09-29 11:10:39 +02:00
|
|
|
if len(result) == len(rowsExpected) {
|
|
|
|
close(doneCh)
|
|
|
|
}
|
|
|
|
lock.Unlock()
|
2020-07-10 11:00:35 +02:00
|
|
|
return nil
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error when parsing compressed %q: %s", s, err)
|
|
|
|
}
|
2020-09-29 11:10:39 +02:00
|
|
|
select {
|
|
|
|
case <-doneCh:
|
|
|
|
case <-time.After(time.Second):
|
|
|
|
t.Fatalf("timeout on compressed stream")
|
|
|
|
}
|
2020-07-10 11:00:35 +02:00
|
|
|
if !reflect.DeepEqual(result, rowsExpected) {
|
2020-09-29 11:10:39 +02:00
|
|
|
t.Fatalf("unexpected compressed rows parsed; got\n%v\nwant\n%v", result, rowsExpected)
|
2020-07-10 11:00:35 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
f("foo 123 456", []Row{{
|
|
|
|
Metric: "foo",
|
|
|
|
Value: 123,
|
|
|
|
Timestamp: 456,
|
|
|
|
}})
|
|
|
|
f(`foo{bar="baz"} 1 2`+"\n"+`aaa{} 3 4`, []Row{
|
|
|
|
{
|
|
|
|
Metric: "foo",
|
|
|
|
Tags: []Tag{{
|
|
|
|
Key: "bar",
|
|
|
|
Value: "baz",
|
|
|
|
}},
|
|
|
|
Value: 1,
|
|
|
|
Timestamp: 2,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Metric: "aaa",
|
|
|
|
Value: 3,
|
|
|
|
Timestamp: 4,
|
|
|
|
},
|
|
|
|
})
|
2020-09-11 12:26:41 +02:00
|
|
|
f("foo 23", []Row{{
|
|
|
|
Metric: "foo",
|
|
|
|
Value: 23,
|
|
|
|
Timestamp: defaultTimestamp,
|
|
|
|
}})
|
2020-07-10 11:00:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func appendRowCopies(dst, src []Row) []Row {
|
|
|
|
for _, r := range src {
|
|
|
|
// Make a copy of r, since r may contain garbage after returning from the callback to ParseStream.
|
|
|
|
var rCopy Row
|
|
|
|
rCopy.Metric = copyString(r.Metric)
|
|
|
|
rCopy.Value = r.Value
|
|
|
|
rCopy.Timestamp = r.Timestamp
|
|
|
|
for _, tag := range r.Tags {
|
|
|
|
rCopy.Tags = append(rCopy.Tags, Tag{
|
|
|
|
Key: copyString(tag.Key),
|
|
|
|
Value: copyString(tag.Value),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
dst = append(dst, rCopy)
|
|
|
|
}
|
|
|
|
return dst
|
|
|
|
}
|
|
|
|
|
|
|
|
func copyString(s string) string {
|
|
|
|
return string(append([]byte(nil), s...))
|
|
|
|
}
|