func TestFileStore_Stats(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) // Create 3 TSM files... data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(1, 2.0)}}, keyValues{"mem", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, } _, err := newFileDir(dir, data...) if err != nil { fatal(t, "creating test files", err) } fs := tsm1.NewFileStore(dir) if err := fs.Open(); err != nil { fatal(t, "opening file store", err) } defer fs.Close() stats := fs.Stats() if got, exp := len(stats), 3; got != exp { t.Fatalf("file count mismatch: got %v, exp %v", got, exp) } }
func TestFileStore_Read(t *testing.T) { fs := tsm1.NewFileStore("") // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(1, 2.0)}}, keyValues{"mem", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, } files, err := newFiles(data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) // Search for an entry that exists in the second file values, err := fs.Read("cpu", 1) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := data[1] if got, exp := len(values), len(exp.values); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp.values { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %d", i, got, exp) } } }
func TestFileStore_Delete(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) fs := tsm1.NewFileStore(dir) // Setup 3 files data := []keyValues{ keyValues{"cpu,host=server2!~#!value", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, keyValues{"cpu,host=server1!~#!value", []tsm1.Value{tsm1.NewValue(1, 2.0)}}, keyValues{"mem,host=server1!~#!value", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, } files, err := newFiles(dir, data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) keys := fs.Keys() if got, exp := len(keys), 3; got != exp { t.Fatalf("key length mismatch: got %v, exp %v", got, exp) } if err := fs.Delete([]string{"cpu,host=server2!~#!value"}); err != nil { fatal(t, "deleting", err) } keys = fs.Keys() if got, exp := len(keys), 2; got != exp { t.Fatalf("key length mismatch: got %v, exp %v", got, exp) } }
func TestFileStore_SeekToDesc_End(t *testing.T) { fs := tsm1.NewFileStore("") // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(1, 2.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, 3.0)}}, } files, err := newFiles(data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) buf := make([]tsm1.FloatValue, 1000) c := fs.KeyCursor("cpu", 2, false) values, err := c.ReadFloatBlock(tsm1.NewTimeDecoder(), &tsm1.FloatDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := data[2] if got, exp := len(values), len(exp.values); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp.values { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %d", i, got, exp) } } }
func TestFileStore_SeekToDesc_FromStart(t *testing.T) { fs := tsm1.NewFileStore("") // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(1, 2.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, 3.0)}}, } files, err := newFiles(data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) // Search for an entry that exists in the second file buf := make(tsm1.FloatValues, 1000) c := fs.KeyCursor("cpu", 0, false) values, err := c.ReadFloatBlock(buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := data[0] if got, exp := len(values), len(exp.values); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp.values { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %d", i, got, exp) } } }
func TestFileStore_Open(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) // Create 3 TSM files... data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(time.Unix(0, 0), 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(time.Unix(1, 0), 2.0)}}, keyValues{"mem", []tsm1.Value{tsm1.NewValue(time.Unix(0, 0), 1.0)}}, } _, err := newFileDir(dir, data...) if err != nil { fatal(t, "creating test files", err) } fs := tsm1.NewFileStore(dir) if err := fs.Open(); err != nil { fatal(t, "opening file store", err) } defer fs.Close() if got, exp := fs.Count(), 3; got != exp { t.Fatalf("file count mismatch: got %v, exp %v", got, exp) } if got, exp := fs.CurrentGeneration(), 4; got != exp { t.Fatalf("current ID mismatch: got %v, exp %v", got, exp) } }
func TestFileStore_SeekToDesc_Duplicate(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) fs := tsm1.NewFileStore(dir) // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, 4.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, 2.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, 3.0)}}, } files, err := newFiles(dir, data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) // Search for an entry that exists in the second file buf := make([]tsm1.FloatValue, 1000) c := fs.KeyCursor("cpu", 2, false) values, err := c.ReadFloatBlock(&tsm1.TimeDecoder{}, &tsm1.FloatDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := []tsm1.Value{ data[3].values[0], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } c.Next() values, err = c.ReadFloatBlock(&tsm1.TimeDecoder{}, &tsm1.FloatDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp = []tsm1.Value{ data[1].values[0], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } }
func TestFileStore_SeekToAsc_Duplicate(t *testing.T) { fs := tsm1.NewFileStore("") // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(time.Unix(0, 0), 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(time.Unix(0, 0), 2.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(time.Unix(2, 0), 3.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(time.Unix(2, 0), 4.0)}}, } files, err := newFiles(data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) buf := make(tsm1.FloatValues, 1000) c := fs.KeyCursor("cpu", time.Unix(0, 0), true) // Search for an entry that exists in the second file values, err := c.ReadFloatBlock(buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := data[1] if got, exp := len(values), len(exp.values); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp.values { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } // Check that calling Next will dedupe points c.Next() values, err = c.ReadFloatBlock(buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp = data[3] if got, exp := len(values), len(exp.values); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp.values { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } }
func TestFileStore_CreateSnapshot(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) fs := tsm1.NewFileStore(dir) // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(1, 2.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, 3.0)}}, } files, err := newFiles(dir, data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) // Create a tombstone if err := fs.DeleteRange([]string{"cpu"}, 1, 1); err != nil { t.Fatalf("unexpected error delete range: %v", err) } s, e := fs.CreateSnapshot() if e != nil { t.Fatal(e) } t.Logf("temp file for hard links: %q", s) tfs, e := ioutil.ReadDir(s) if e != nil { t.Fatal(e) } if len(tfs) == 0 { t.Fatal("no files found") } for _, f := range fs.Files() { p := filepath.Join(s, filepath.Base(f.Path())) t.Logf("checking for existence of hard link %q", p) if _, err := os.Stat(p); os.IsNotExist(err) { t.Fatalf("unable to find file %q", p) } for _, tf := range f.TombstoneFiles() { p := filepath.Join(s, filepath.Base(tf.Path)) t.Logf("checking for existence of hard link %q", p) if _, err := os.Stat(p); os.IsNotExist(err) { t.Fatalf("unable to find file %q", p) } } } }
func TestFileStore_Open_Deleted(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) // Create 3 TSM files... data := []keyValues{ keyValues{"cpu,host=server2!~#!value", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, keyValues{"cpu,host=server1!~#!value", []tsm1.Value{tsm1.NewValue(1, 2.0)}}, keyValues{"mem,host=server1!~#!value", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, } _, err := newFileDir(dir, data...) if err != nil { fatal(t, "creating test files", err) } fs := tsm1.NewFileStore(dir) if err := fs.Open(); err != nil { fatal(t, "opening file store", err) } defer fs.Close() if got, exp := len(fs.Keys()), 3; got != exp { t.Fatalf("file count mismatch: got %v, exp %v", got, exp) } if err := fs.Delete([]string{"cpu,host=server2!~#!value"}); err != nil { fatal(t, "deleting", err) } fs2 := tsm1.NewFileStore(dir) if err := fs2.Open(); err != nil { fatal(t, "opening file store", err) } defer fs2.Close() if got, exp := len(fs2.Keys()), 2; got != exp { t.Fatalf("file count mismatch: got %v, exp %v", got, exp) } }
func TestFileStore_SeekToDesc_AfterEnd_OverlapString(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) fs := tsm1.NewFileStore(dir) // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(8, "eight"), tsm1.NewValue(9, "nine")}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, "two")}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, "three")}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, "four"), tsm1.NewValue(7, "seven")}}, } files, err := newFiles(dir, data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) buf := make([]tsm1.StringValue, 1000) c := fs.KeyCursor("cpu", 8, false) values, err := c.ReadStringBlock(&tsm1.TimeDecoder{}, &tsm1.StringDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := []tsm1.Value{ data[1].values[0], data[3].values[0], data[3].values[1], data[0].values[0], data[0].values[1], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } }
// Tests that seeking and reading all blocks that contain overlapping points does // not skip any blocks. func TestFileStore_SeekToAsc_BeforeStart_OverlapBoolean(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) fs := tsm1.NewFileStore(dir) // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, true), tsm1.NewValue(1, false)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, true)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, true)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, false), tsm1.NewValue(7, true)}}, } files, err := newFiles(dir, data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) // Search for an entry that exists in the second file buf := make([]tsm1.BooleanValue, 1000) c := fs.KeyCursor("cpu", 0, true) values, err := c.ReadBooleanBlock(&tsm1.TimeDecoder{}, &tsm1.BooleanDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := []tsm1.Value{ data[3].values[0], data[0].values[1], data[1].values[0], data[2].values[0], data[3].values[1], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } }
// Tests that seeking and reading all blocks that contain overlapping points does // not skip any blocks. func TestFileStore_SeekToAsc_BeforeStart_OverlapString(t *testing.T) { fs := tsm1.NewFileStore("") // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, "zero"), tsm1.NewValue(1, "one")}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, "two")}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, "three")}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, "four"), tsm1.NewValue(7, "seven")}}, } files, err := newFiles(data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) // Search for an entry that exists in the second file buf := make([]tsm1.StringValue, 1000) c := fs.KeyCursor("cpu", 0, true) values, err := c.ReadStringBlock(tsm1.NewTimeDecoder(), &tsm1.StringDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := []tsm1.Value{ data[3].values[0], data[0].values[1], data[1].values[0], data[2].values[0], data[3].values[1], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } }
func TestFileStore_SeekToDesc_AfterEnd_OverlapInteger(t *testing.T) { fs := tsm1.NewFileStore("") // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(8, int64(0)), tsm1.NewValue(9, int64(1))}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, int64(2))}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, int64(3))}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, int64(4)), tsm1.NewValue(7, int64(7))}}, } files, err := newFiles(data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) buf := make(tsm1.IntegerValues, 1000) c := fs.KeyCursor("cpu", 8, false) values, err := c.ReadIntegerBlock(buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := []tsm1.Value{ data[1].values[0], data[3].values[0], data[3].values[1], data[0].values[0], data[0].values[1], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } }
func TestKeyCursor_TombstoneRange_PartialString(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) fs := tsm1.NewFileStore(dir) // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{ tsm1.NewValue(0, "1"), tsm1.NewValue(1, "2"), tsm1.NewValue(2, "3")}}, } files, err := newFiles(dir, data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) if err := fs.DeleteRange([]string{"cpu"}, 1, 1); err != nil { t.Fatalf("unexpected error delete range: %v", err) } buf := make([]tsm1.StringValue, 1000) c := fs.KeyCursor("cpu", 0, true) values, err := c.ReadStringBlock(&tsm1.TimeDecoder{}, &tsm1.StringDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } expValues := []tsm1.Value{data[0].values[0], data[0].values[2]} for i, v := range expValues { exp := v if got, exp := len(values), 2; got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } if got, exp := values[i].String(), exp.String(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %d", 0, got, exp) } } }
func TestKeyCursor_TombstoneRange(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) fs := tsm1.NewFileStore(dir) // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(0, 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(1, 2.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, 3.0)}}, } files, err := newFiles(dir, data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) if err := fs.DeleteRange([]string{"cpu"}, 1, 1); err != nil { t.Fatalf("unexpected error delete range: %v", err) } buf := make([]tsm1.FloatValue, 1000) c := fs.KeyCursor("cpu", 0, true) expValues := []int{0, 2} for _, v := range expValues { values, err := c.ReadFloatBlock(&tsm1.TimeDecoder{}, &tsm1.FloatDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := data[v] if got, exp := len(values), 1; got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } if got, exp := values[0].String(), exp.values[0].String(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %d", 0, got, exp) } c.Next() } }
func TestFileStore_SeekToDesc_AfterEnd_OverlapBoolean(t *testing.T) { fs := tsm1.NewFileStore("") // Setup 3 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(8, true), tsm1.NewValue(9, true)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, true)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, false)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, true), tsm1.NewValue(7, false)}}, } files, err := newFiles(data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) buf := make([]tsm1.BooleanValue, 1000) c := fs.KeyCursor("cpu", 8, false) values, err := c.ReadBooleanBlock(tsm1.NewTimeDecoder(), &tsm1.BooleanDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := []tsm1.Value{ data[1].values[0], data[3].values[0], data[3].values[1], data[0].values[0], data[0].values[1], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } }
func TestFileStore_SeekToDesc_AfterEnd_OverlapFloat(t *testing.T) { dir := MustTempDir() defer os.RemoveAll(dir) fs := tsm1.NewFileStore(dir) // Setup 4 files data := []keyValues{ keyValues{"cpu", []tsm1.Value{tsm1.NewValue(8, 0.0), tsm1.NewValue(9, 1.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(2, 2.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, 3.0)}}, keyValues{"cpu", []tsm1.Value{tsm1.NewValue(3, 4.0), tsm1.NewValue(7, 7.0)}}, } files, err := newFiles(dir, data...) if err != nil { t.Fatalf("unexpected error creating files: %v", err) } fs.Add(files...) buf := make([]tsm1.FloatValue, 1000) c := fs.KeyCursor("cpu", 10, false) values, err := c.ReadFloatBlock(&tsm1.TimeDecoder{}, &tsm1.FloatDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp := []tsm1.Value{ data[0].values[0], data[0].values[1], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } c.Next() values, err = c.ReadFloatBlock(&tsm1.TimeDecoder{}, &tsm1.FloatDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp = []tsm1.Value{ data[3].values[0], data[3].values[1], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } c.Next() values, err = c.ReadFloatBlock(&tsm1.TimeDecoder{}, &tsm1.FloatDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } exp = []tsm1.Value{ data[1].values[0], } if got, exp := len(values), len(exp); got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } for i, v := range exp { if got, exp := values[i].Value(), v.Value(); got != exp { t.Fatalf("read value mismatch(%d): got %v, exp %v", i, got, exp) } } c.Next() values, err = c.ReadFloatBlock(&tsm1.TimeDecoder{}, &tsm1.FloatDecoder{}, &buf) if err != nil { t.Fatalf("unexpected error reading values: %v", err) } if got, exp := len(values), 0; got != exp { t.Fatalf("value length mismatch: got %v, exp %v", got, exp) } }