mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-01 14:47:38 +00:00
c0caa69939
The strconv.AppendQuote improperly encodes special chars such as \x1b . They must be encoded as \u001b . See https://github.com/VictoriaMetrics/victorialogs-datasource/issues/24
351 lines
6.5 KiB
Go
351 lines
6.5 KiB
Go
package logstorage
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestMarshalFieldsToJSON(t *testing.T) {
|
|
f := func(fields []Field, resultExpected string) {
|
|
t.Helper()
|
|
|
|
result := MarshalFieldsToJSON(nil, fields)
|
|
if string(result) != resultExpected {
|
|
t.Fatalf("unexpected result\ngot\n%q\nwant\n%q", result, resultExpected)
|
|
}
|
|
}
|
|
|
|
f(nil, "{}")
|
|
f([]Field{}, "{}")
|
|
|
|
f([]Field{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
}, `{"foo":"bar"}`)
|
|
|
|
f([]Field{
|
|
{
|
|
Name: "foo\nbar",
|
|
Value: " \u001b[32m ",
|
|
},
|
|
{
|
|
Name: " \u001b[11m ",
|
|
Value: "АБв",
|
|
},
|
|
}, `{"foo\nbar":" \u001b[32m "," \u001b[11m ":"АБв"}`)
|
|
}
|
|
|
|
func TestMarshalFieldsToLogfmt(t *testing.T) {
|
|
f := func(fields []Field, resultExpected string) {
|
|
t.Helper()
|
|
|
|
result := MarshalFieldsToLogfmt(nil, fields)
|
|
if string(result) != resultExpected {
|
|
t.Fatalf("unexpected result\ngot\n%q\nwant\n%q", result, resultExpected)
|
|
}
|
|
}
|
|
|
|
f(nil, "")
|
|
f([]Field{}, "")
|
|
|
|
f([]Field{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
}, `foo=bar`)
|
|
|
|
f([]Field{
|
|
{
|
|
Name: "foo",
|
|
Value: " \u001b[32m ",
|
|
},
|
|
{
|
|
Name: "bar",
|
|
Value: "АБв",
|
|
},
|
|
}, `foo=" \u001b[32m " bar=АБв`)
|
|
}
|
|
|
|
func TestGetRowsSizeBytes(t *testing.T) {
|
|
f := func(rows [][]Field, uncompressedSizeBytesExpected int) {
|
|
t.Helper()
|
|
sizeBytes := uncompressedRowsSizeBytes(rows)
|
|
if sizeBytes != uint64(uncompressedSizeBytesExpected) {
|
|
t.Fatalf("unexpected sizeBytes; got %d; want %d", sizeBytes, uncompressedSizeBytesExpected)
|
|
}
|
|
}
|
|
f(nil, 0)
|
|
f([][]Field{}, 0)
|
|
f([][]Field{{}}, 35)
|
|
f([][]Field{{{Name: "foo"}}}, 40)
|
|
|
|
_, rows := newTestRows(1000, 10)
|
|
f(rows, 233900)
|
|
}
|
|
|
|
func TestRowsAppendRows(t *testing.T) {
|
|
var rs rows
|
|
|
|
timestamps := []int64{1}
|
|
rows := [][]Field{
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
}
|
|
rs.appendRows(timestamps, rows)
|
|
if len(rs.timestamps) != 1 {
|
|
t.Fatalf("unexpected number of row items; got %d; want 1", len(rs.timestamps))
|
|
}
|
|
rs.appendRows(timestamps, rows)
|
|
if len(rs.timestamps) != 2 {
|
|
t.Fatalf("unexpected number of row items; got %d; want 2", len(rs.timestamps))
|
|
}
|
|
for i := range rs.timestamps {
|
|
if rs.timestamps[i] != timestamps[0] {
|
|
t.Fatalf("unexpected timestamps copied; got %d; want %d", rs.timestamps[i], timestamps[0])
|
|
}
|
|
if !reflect.DeepEqual(rs.rows[i], rows[0]) {
|
|
t.Fatalf("unexpected fields copied\ngot\n%v\nwant\n%v", rs.rows[i], rows[0])
|
|
}
|
|
}
|
|
|
|
// append multiple log entries
|
|
timestamps, rows = newTestRows(100, 4)
|
|
rs.appendRows(timestamps, rows)
|
|
if len(rs.timestamps) != 102 {
|
|
t.Fatalf("unexpected number of row items; got %d; want 102", len(rs.timestamps))
|
|
}
|
|
for i := range timestamps {
|
|
if rs.timestamps[i+2] != timestamps[i] {
|
|
t.Fatalf("unexpected timestamps copied; got %d; want %d", rs.timestamps[i+2], timestamps[i])
|
|
}
|
|
if !reflect.DeepEqual(rs.rows[i+2], rows[i]) {
|
|
t.Fatalf("unexpected log entry copied\ngot\n%v\nwant\n%v", rs.rows[i+2], rows[i])
|
|
}
|
|
}
|
|
|
|
// reset rows
|
|
rs.reset()
|
|
if len(rs.timestamps) != 0 {
|
|
t.Fatalf("unexpected non-zero number of row items after reset: %d", len(rs.timestamps))
|
|
}
|
|
}
|
|
|
|
func TestMergeRows(t *testing.T) {
|
|
f := func(timestampsA, timestampsB []int64, fieldsA, fieldsB [][]Field, timestampsExpected []int64, rowsExpected [][]Field) {
|
|
t.Helper()
|
|
var rs rows
|
|
rs.mergeRows(timestampsA, timestampsB, fieldsA, fieldsB)
|
|
if !reflect.DeepEqual(rs.timestamps, timestampsExpected) {
|
|
t.Fatalf("unexpected timestamps after merge\ngot\n%v\nwant\n%v", rs.timestamps, timestampsExpected)
|
|
}
|
|
if !reflect.DeepEqual(rs.rows, rowsExpected) {
|
|
t.Fatalf("unexpected rows after merge\ngot\n%v\nwant\n%v", rs.rows, rowsExpected)
|
|
}
|
|
|
|
// check that the result doesn't change when merging in reverse order
|
|
rs.reset()
|
|
rs.mergeRows(timestampsB, timestampsA, fieldsB, fieldsA)
|
|
if !reflect.DeepEqual(rs.timestamps, timestampsExpected) {
|
|
t.Fatalf("unexpected timestamps after reverse merge\ngot\n%v\nwant\n%v", rs.timestamps, timestampsExpected)
|
|
}
|
|
if !reflect.DeepEqual(rs.rows, rowsExpected) {
|
|
t.Fatalf("unexpected rows after reverse merge\ngot\n%v\nwant\n%v", rs.rows, rowsExpected)
|
|
}
|
|
}
|
|
|
|
f(nil, nil, nil, nil, nil, nil)
|
|
|
|
// merge single entry with zero entries
|
|
timestampsA := []int64{123}
|
|
timestampsB := []int64{}
|
|
|
|
fieldsA := [][]Field{
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
}
|
|
fieldsB := [][]Field{}
|
|
|
|
resultTimestamps := []int64{123}
|
|
resultFields := [][]Field{
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
}
|
|
f(timestampsA, timestampsB, fieldsA, fieldsB, resultTimestamps, resultFields)
|
|
|
|
// merge two single entries
|
|
timestampsA = []int64{123}
|
|
timestampsB = []int64{43323}
|
|
|
|
fieldsA = [][]Field{
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
}
|
|
fieldsB = [][]Field{
|
|
{
|
|
{
|
|
Name: "asdfds",
|
|
Value: "asdfsa",
|
|
},
|
|
},
|
|
}
|
|
|
|
resultTimestamps = []int64{123, 43323}
|
|
resultFields = [][]Field{
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "asdfds",
|
|
Value: "asdfsa",
|
|
},
|
|
},
|
|
}
|
|
f(timestampsA, timestampsB, fieldsA, fieldsB, resultTimestamps, resultFields)
|
|
|
|
// merge identical entries
|
|
timestampsA = []int64{123, 456}
|
|
timestampsB = []int64{123, 456}
|
|
|
|
fieldsA = [][]Field{
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "baz",
|
|
},
|
|
},
|
|
}
|
|
fieldsB = [][]Field{
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "baz",
|
|
},
|
|
},
|
|
}
|
|
|
|
resultTimestamps = []int64{123, 123, 456, 456}
|
|
resultFields = [][]Field{
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "baz",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "baz",
|
|
},
|
|
},
|
|
}
|
|
f(timestampsA, timestampsB, fieldsA, fieldsB, resultTimestamps, resultFields)
|
|
|
|
// merge interleaved entries
|
|
timestampsA = []int64{12, 13432}
|
|
timestampsB = []int64{3, 43323}
|
|
|
|
fieldsA = [][]Field{
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "xfoo",
|
|
Value: "xbar",
|
|
},
|
|
},
|
|
}
|
|
fieldsB = [][]Field{
|
|
{
|
|
{
|
|
Name: "asd",
|
|
Value: "assa",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "asdfds",
|
|
Value: "asdfsa",
|
|
},
|
|
},
|
|
}
|
|
|
|
resultTimestamps = []int64{3, 12, 13432, 43323}
|
|
resultFields = [][]Field{
|
|
{
|
|
{
|
|
Name: "asd",
|
|
Value: "assa",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "foo",
|
|
Value: "bar",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "xfoo",
|
|
Value: "xbar",
|
|
},
|
|
},
|
|
{
|
|
{
|
|
Name: "asdfds",
|
|
Value: "asdfsa",
|
|
},
|
|
},
|
|
}
|
|
f(timestampsA, timestampsB, fieldsA, fieldsB, resultTimestamps, resultFields)
|
|
}
|