124 lines
2.9 KiB
Go
124 lines
2.9 KiB
Go
|
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)
|
||
|
}
|
||
|
})
|
||
|
|
||
|
}
|