Initial commit
This commit is contained in:
271
lib/wal/wal-sendrecv_test.go
Normal file
271
lib/wal/wal-sendrecv_test.go
Normal file
@@ -0,0 +1,271 @@
|
||||
package wal
|
||||
|
||||
import (
|
||||
"git.crumpington.com/public/jldb/lib/errs"
|
||||
"git.crumpington.com/public/jldb/lib/testutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSendRecvHarness(t *testing.T) {
|
||||
t.Parallel()
|
||||
(&SendRecvTestHarness{}).Run(t)
|
||||
}
|
||||
|
||||
type SendRecvTestHarness struct{}
|
||||
|
||||
func (h *SendRecvTestHarness) Run(t *testing.T) {
|
||||
val := reflect.ValueOf(h)
|
||||
typ := val.Type()
|
||||
for i := 0; i < typ.NumMethod(); i++ {
|
||||
method := typ.Method(i)
|
||||
if !strings.HasPrefix(method.Name, "Test") {
|
||||
continue
|
||||
}
|
||||
|
||||
t.Run(method.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
pDir := t.TempDir()
|
||||
sDir := t.TempDir()
|
||||
|
||||
config := Config{
|
||||
SegMinCount: 8,
|
||||
SegMaxAgeSec: 1,
|
||||
}
|
||||
|
||||
pWAL, err := Create(pDir, 1, config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer pWAL.Close()
|
||||
|
||||
sWAL, err := Create(sDir, 1, config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer sWAL.Close()
|
||||
|
||||
nw := testutil.NewNetwork()
|
||||
defer func() {
|
||||
nw.CloseServer()
|
||||
nw.CloseClient()
|
||||
}()
|
||||
|
||||
val.MethodByName(method.Name).Call([]reflect.Value{
|
||||
reflect.ValueOf(t),
|
||||
reflect.ValueOf(pWAL),
|
||||
reflect.ValueOf(sWAL),
|
||||
reflect.ValueOf(nw),
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (h *SendRecvTestHarness) TestSimple(
|
||||
t *testing.T,
|
||||
pWAL *WAL,
|
||||
sWAL *WAL,
|
||||
nw *testutil.Network,
|
||||
) {
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := writeRandomWithEOF(pWAL, 5*time.Second); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Send in the background.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
conn := nw.Accept()
|
||||
if err := pWAL.Send(conn, 8*time.Second); err != nil {
|
||||
log.Printf("Send error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Recv in the background.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
conn := nw.Dial()
|
||||
if err := sWAL.Recv(conn, 8*time.Second); err != nil {
|
||||
log.Printf("Recv error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
waitForEOF(t, sWAL)
|
||||
|
||||
nw.CloseServer()
|
||||
nw.CloseClient()
|
||||
wg.Wait()
|
||||
|
||||
checkWALsEqual(t, pWAL, sWAL)
|
||||
}
|
||||
|
||||
func (h *SendRecvTestHarness) TestWriteThenRead(
|
||||
t *testing.T,
|
||||
pWAL *WAL,
|
||||
sWAL *WAL,
|
||||
nw *testutil.Network,
|
||||
) {
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
if err := writeRandomWithEOF(pWAL, 2*time.Second); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Send in the background.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
conn := nw.Accept()
|
||||
if err := pWAL.Send(conn, 8*time.Second); err != nil {
|
||||
log.Printf("Send error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Recv in the background.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
conn := nw.Dial()
|
||||
if err := sWAL.Recv(conn, 8*time.Second); err != nil {
|
||||
log.Printf("Recv error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
waitForEOF(t, sWAL)
|
||||
|
||||
nw.CloseServer()
|
||||
nw.CloseClient()
|
||||
wg.Wait()
|
||||
|
||||
checkWALsEqual(t, pWAL, sWAL)
|
||||
}
|
||||
|
||||
func (h *SendRecvTestHarness) TestNetworkFailures(
|
||||
t *testing.T,
|
||||
pWAL *WAL,
|
||||
sWAL *WAL,
|
||||
nw *testutil.Network,
|
||||
) {
|
||||
recvDone := &atomic.Bool{}
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
writeRandomWithEOF(pWAL, 10*time.Second)
|
||||
}()
|
||||
|
||||
// Send in the background.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
for {
|
||||
if recvDone.Load() {
|
||||
return
|
||||
}
|
||||
if conn := nw.Accept(); conn != nil {
|
||||
pWAL.Send(conn, 8*time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Recv in the background.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for !recvDone.Load() {
|
||||
if conn := nw.Dial(); conn != nil {
|
||||
sWAL.Recv(conn, 8*time.Second)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
wg.Add(1)
|
||||
failureCount := 0
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for {
|
||||
if recvDone.Load() {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Millisecond * time.Duration(rand.Intn(100)))
|
||||
failureCount++
|
||||
if rand.Float64() < 0.5 {
|
||||
nw.CloseClient()
|
||||
} else {
|
||||
nw.CloseServer()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
waitForEOF(t, sWAL)
|
||||
recvDone.Store(true)
|
||||
wg.Wait()
|
||||
|
||||
log.Printf("%d network failures.", failureCount)
|
||||
|
||||
if failureCount < 10 {
|
||||
t.Fatal("Expected more failures.")
|
||||
}
|
||||
|
||||
checkWALsEqual(t, pWAL, sWAL)
|
||||
}
|
||||
|
||||
func (h *SendRecvTestHarness) TestSenderClose(
|
||||
t *testing.T,
|
||||
pWAL *WAL,
|
||||
sWAL *WAL,
|
||||
nw *testutil.Network,
|
||||
) {
|
||||
wg := sync.WaitGroup{}
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := writeRandomWithEOF(pWAL, 5*time.Second); !errs.Closed.Is(err) {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Close primary after some time.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
time.Sleep(time.Second)
|
||||
pWAL.Close()
|
||||
}()
|
||||
|
||||
// Send in the background.
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
conn := nw.Accept()
|
||||
if err := pWAL.Send(conn, 8*time.Second); err != nil {
|
||||
log.Printf("Send error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
conn := nw.Dial()
|
||||
if err := sWAL.Recv(conn, 8*time.Second); !errs.Closed.Is(err) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nw.CloseServer()
|
||||
nw.CloseClient()
|
||||
wg.Wait()
|
||||
}
|
||||
Reference in New Issue
Block a user