151 lines
3.5 KiB
Go
151 lines
3.5 KiB
Go
package chain
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
"github.com/filecoin-project/lotus/chain/types/mock"
|
|
)
|
|
|
|
var genTs = mock.TipSet(mock.MkBlock(nil, 0, 0))
|
|
|
|
type syncOp struct {
|
|
ts *types.TipSet
|
|
done func()
|
|
}
|
|
|
|
func runSyncMgrTest(t *testing.T, tname string, thresh int, tf func(*testing.T, *syncManager, chan *syncOp)) {
|
|
syncTargets := make(chan *syncOp)
|
|
sm := NewSyncManager(func(ctx context.Context, ts *types.TipSet) error {
|
|
ch := make(chan struct{})
|
|
syncTargets <- &syncOp{
|
|
ts: ts,
|
|
done: func() { close(ch) },
|
|
}
|
|
<-ch
|
|
return nil
|
|
}).(*syncManager)
|
|
sm.bspThresh = thresh
|
|
|
|
sm.Start()
|
|
defer sm.Stop()
|
|
t.Run(tname+fmt.Sprintf("-%d", thresh), func(t *testing.T) {
|
|
tf(t, sm, syncTargets)
|
|
})
|
|
}
|
|
|
|
func assertTsEqual(t *testing.T, actual, expected *types.TipSet) {
|
|
t.Helper()
|
|
if !actual.Equals(expected) {
|
|
t.Fatalf("got unexpected tipset %s (expected: %s)", actual.Cids(), expected.Cids())
|
|
}
|
|
}
|
|
|
|
func assertNoOp(t *testing.T, c chan *syncOp) {
|
|
t.Helper()
|
|
select {
|
|
case <-time.After(time.Millisecond * 20):
|
|
case <-c:
|
|
t.Fatal("shouldnt have gotten any sync operations yet")
|
|
}
|
|
}
|
|
|
|
func assertGetSyncOp(t *testing.T, c chan *syncOp, ts *types.TipSet) {
|
|
t.Helper()
|
|
|
|
select {
|
|
case <-time.After(time.Millisecond * 100):
|
|
t.Fatal("expected sync manager to try and sync to our target")
|
|
case op := <-c:
|
|
op.done()
|
|
if !op.ts.Equals(ts) {
|
|
t.Fatalf("somehow got wrong tipset from syncer (got %s, expected %s)", op.ts.Cids(), ts.Cids())
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSyncManager(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
a := mock.TipSet(mock.MkBlock(genTs, 1, 1))
|
|
b := mock.TipSet(mock.MkBlock(a, 1, 2))
|
|
c1 := mock.TipSet(mock.MkBlock(b, 1, 3))
|
|
c2 := mock.TipSet(mock.MkBlock(b, 2, 4))
|
|
c3 := mock.TipSet(mock.MkBlock(b, 3, 5))
|
|
d := mock.TipSet(mock.MkBlock(c1, 4, 5))
|
|
|
|
runSyncMgrTest(t, "testBootstrap", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
|
sm.SetPeerHead(ctx, "peer1", c1)
|
|
assertGetSyncOp(t, stc, c1)
|
|
})
|
|
|
|
runSyncMgrTest(t, "testBootstrap", 2, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
|
sm.SetPeerHead(ctx, "peer1", c1)
|
|
assertNoOp(t, stc)
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c1)
|
|
assertGetSyncOp(t, stc, c1)
|
|
})
|
|
|
|
runSyncMgrTest(t, "testSyncAfterBootstrap", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
|
sm.SetPeerHead(ctx, "peer1", b)
|
|
assertGetSyncOp(t, stc, b)
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c1)
|
|
assertGetSyncOp(t, stc, c1)
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c2)
|
|
assertGetSyncOp(t, stc, c2)
|
|
})
|
|
|
|
runSyncMgrTest(t, "testCoalescing", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
|
sm.SetPeerHead(ctx, "peer1", a)
|
|
assertGetSyncOp(t, stc, a)
|
|
|
|
sm.SetPeerHead(ctx, "peer2", b)
|
|
op := <-stc
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c1)
|
|
sm.SetPeerHead(ctx, "peer2", c2)
|
|
sm.SetPeerHead(ctx, "peer2", d)
|
|
|
|
assertTsEqual(t, op.ts, b)
|
|
|
|
// need a better way to 'wait until syncmgr is idle'
|
|
time.Sleep(time.Millisecond * 20)
|
|
|
|
op.done()
|
|
|
|
assertGetSyncOp(t, stc, d)
|
|
})
|
|
|
|
runSyncMgrTest(t, "testSyncIncomingTipset", 1, func(t *testing.T, sm *syncManager, stc chan *syncOp) {
|
|
sm.SetPeerHead(ctx, "peer1", a)
|
|
assertGetSyncOp(t, stc, a)
|
|
|
|
sm.SetPeerHead(ctx, "peer2", b)
|
|
op := <-stc
|
|
op.done()
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c1)
|
|
op1 := <-stc
|
|
fmt.Println("op1: ", op1.ts.Cids())
|
|
|
|
sm.SetPeerHead(ctx, "peer2", c2)
|
|
sm.SetPeerHead(ctx, "peer2", c3)
|
|
|
|
op1.done()
|
|
|
|
op2 := <-stc
|
|
fmt.Println("op2: ", op2.ts.Cids())
|
|
op2.done()
|
|
|
|
op3 := <-stc
|
|
fmt.Println("op3: ", op3.ts.Cids())
|
|
op3.done()
|
|
})
|
|
}
|