VictoriaMetrics/lib/storage/block_test.go
Aliaksandr Valialkin aadbd014ff all: add native format for data export and import
The data can be exported via [/api/v1/export/native](https://victoriametrics.github.io/#how-to-export-data-in-native-format) handler
and imported via [/api/v1/import/native](https://victoriametrics.github.io/#how-to-import-data-in-native-format) handler.
2020-09-27 17:36:38 +03:00

116 lines
3.7 KiB
Go

package storage
import (
"math/rand"
"reflect"
"strings"
"testing"
)
func TestBlockMarshalUnmarshalPortable(t *testing.T) {
var b Block
for i := 0; i < 1000; i++ {
b.Reset()
rowsCount := rand.Intn(maxRowsPerBlock) + 1
b.timestamps = getRandTimestamps(rowsCount)
b.values = getRandValues(rowsCount)
b.bh.Scale = int16(rand.Intn(30) - 15)
b.bh.PrecisionBits = 64
testBlockMarshalUnmarshalPortable(t, &b)
}
}
func testBlockMarshalUnmarshalPortable(t *testing.T, b *Block) {
var b1, b2 Block
b1.CopyFrom(b)
rowsCount := len(b.values)
data := b1.MarshalPortable(nil)
if b1.bh.RowsCount != uint32(rowsCount) {
t.Fatalf("unexpected number of rows marshaled; got %d; want %d", b1.bh.RowsCount, rowsCount)
}
tail, err := b2.UnmarshalPortable(data)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if len(tail) > 0 {
t.Fatalf("unexpected non-empty tail: %X", tail)
}
compareBlocksPortable(t, &b2, b, &b1.bh)
// Verify non-empty prefix and suffix
prefix := "prefix"
suffix := "suffix"
data = append(data[:0], prefix...)
data = b1.MarshalPortable(data)
if b1.bh.RowsCount != uint32(rowsCount) {
t.Fatalf("unexpected number of rows marshaled; got %d; want %d", b1.bh.RowsCount, rowsCount)
}
if !strings.HasPrefix(string(data), prefix) {
t.Fatalf("unexpected prefix in %X; want %X", data, prefix)
}
data = data[len(prefix):]
data = append(data, suffix...)
tail, err = b2.UnmarshalPortable(data)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if string(tail) != suffix {
t.Fatalf("unexpected tail; got %X; want %X", tail, suffix)
}
compareBlocksPortable(t, &b2, b, &b1.bh)
}
func compareBlocksPortable(t *testing.T, b1, b2 *Block, bhExpected *blockHeader) {
t.Helper()
if b1.bh.MinTimestamp != bhExpected.MinTimestamp {
t.Fatalf("unexpected MinTimestamp; got %d; want %d", b1.bh.MinTimestamp, bhExpected.MinTimestamp)
}
if b1.bh.FirstValue != bhExpected.FirstValue {
t.Fatalf("unexpected FirstValue; got %d; want %d", b1.bh.FirstValue, bhExpected.FirstValue)
}
if b1.bh.RowsCount != bhExpected.RowsCount {
t.Fatalf("unexpected RowsCount; got %d; want %d", b1.bh.RowsCount, bhExpected.RowsCount)
}
if b1.bh.Scale != bhExpected.Scale {
t.Fatalf("unexpected Scale; got %d; want %d", b1.bh.Scale, bhExpected.Scale)
}
if b1.bh.TimestampsMarshalType != bhExpected.TimestampsMarshalType {
t.Fatalf("unexpected TimestampsMarshalType; got %d; want %d", b1.bh.TimestampsMarshalType, bhExpected.TimestampsMarshalType)
}
if b1.bh.ValuesMarshalType != bhExpected.ValuesMarshalType {
t.Fatalf("unexpected ValuesMarshalType; got %d; want %d", b1.bh.ValuesMarshalType, bhExpected.ValuesMarshalType)
}
if b1.bh.PrecisionBits != bhExpected.PrecisionBits {
t.Fatalf("unexpected PrecisionBits; got %d; want %d", b1.bh.PrecisionBits, bhExpected.PrecisionBits)
}
if !reflect.DeepEqual(b1.values, b2.values) {
t.Fatalf("unexpected values; got %d; want %d", b1.values, b2.values)
}
if !reflect.DeepEqual(b1.timestamps, b2.timestamps) {
t.Fatalf("unexpected timestamps; got %d; want %d", b1.timestamps, b2.timestamps)
}
if len(b1.values) != int(bhExpected.RowsCount) {
t.Fatalf("unexpected number of values; got %d; want %d", len(b1.values), bhExpected.RowsCount)
}
if len(b1.timestamps) != int(bhExpected.RowsCount) {
t.Fatalf("unexpected number of timestamps; got %d; want %d", len(b1.timestamps), bhExpected.RowsCount)
}
}
func getRandValues(rowsCount int) []int64 {
a := make([]int64, rowsCount)
for i := 0; i < rowsCount; i++ {
a[i] = int64(rand.Intn(1e5) - 0.5e5)
}
return a
}
func getRandTimestamps(rowsCount int) []int64 {
a := make([]int64, rowsCount)
ts := int64(rand.Intn(1e12))
for i := 0; i < rowsCount; i++ {
a[i] = ts
ts += int64(rand.Intn(1e5))
}
return a
}