package wal import ( "errors" "os" "testing" "time" ) // ---------------------------------------------------------------------------- func (f *Follower) getReplay(afterSeqNum uint64) (l []Record) { f.Replay(afterSeqNum, func(rec Record) error { l = append(l, rec) return nil }) return l } func (f *Follower) waitForSeqNum(n uint64) { for { maxSeqNum := f.MaxSeqNum() //log.Printf("%d/%d", maxSeqNum, n) if maxSeqNum == n { return } time.Sleep(100 * time.Millisecond) } } // ---------------------------------------------------------------------------- func TestFollower(t *testing.T) { run := func(name string, inner func(t *testing.T, walPath string, w *Writer, f *Follower)) { t.Run(name, func(t *testing.T) { walPath := randPath() + ".wal" defer os.RemoveAll(walPath) w := newWriter(walPath, true) defer w.Close() f := NewFollower(walPath) defer f.Close() inner(t, walPath, w, f) }) } run("simple", func(t *testing.T, walPath string, w *Writer, f *Follower) { w.Store("a", 1, _b("Hello")) w.Delete("b", 1) w.Store("a", 2, _b("World")) w.Store("a", 1, _b("Good bye")) expected := []Record{ {SeqNum: 1, Collection: "a", ID: 1, Store: true, Data: _b("Hello")}, {SeqNum: 2, Collection: "b", ID: 1}, {SeqNum: 3, Collection: "a", ID: 2, Store: true, Data: _b("World")}, {SeqNum: 4, Collection: "a", ID: 1, Store: true, Data: _b("Good bye")}, } recs := f.getReplay(0) if err := recsEqual(recs, expected); err != nil { t.Fatal(err) } for i := 1; i < 4; i++ { recs = f.getReplay(uint64(i)) if err := recsEqual(recs, expected[i:]); err != nil { t.Fatal(err) } } }) run("write async", func(t *testing.T, walPath string, w *Writer, f *Follower) { w.storeAsync("a", 1, _b("hello1")) w.storeAsync("a", 2, _b("hello2")) w.deleteAsync("a", 1) w.storeAsync("a", 3, _b("hello3")) w.storeAsync("b", 1, _b("b1")) f.waitForSeqNum(5) expected := []Record{ {SeqNum: 1, Collection: "a", ID: 1, Store: true, Data: _b("hello1")}, {SeqNum: 2, Collection: "a", ID: 2, Store: true, Data: _b("hello2")}, {SeqNum: 3, Collection: "a", ID: 1, Store: false}, {SeqNum: 4, Collection: "a", ID: 3, Store: true, Data: _b("hello3")}, {SeqNum: 5, Collection: "b", ID: 1, Store: true, Data: _b("b1")}, } recs := f.getReplay(0) if err := recsEqual(recs, expected); err != nil { t.Fatal(err) } for i := 1; i < 4; i++ { recs = f.getReplay(uint64(i)) if err := recsEqual(recs, expected[i:]); err != nil { t.Fatal(err) } } }) run("replay error", func(t *testing.T, walPath string, w *Writer, f *Follower) { expectedErr := errors.New("My error") w.Store("a", 1, _b("Hello")) w.Delete("b", 1) w.Store("a", 2, _b("World")) w.Store("a", 1, _b("Good bye")) err := f.Replay(0, func(rec Record) error { if rec.Collection == "b" { return expectedErr } return nil }) if err != expectedErr { t.Fatal(err) } }) }