You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
6.9 KiB
325 lines
6.9 KiB
package legacysync
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math/big"
|
|
"reflect"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/harmony-one/harmony/api/service/legacysync/downloader"
|
|
"github.com/harmony-one/harmony/block"
|
|
headerV3 "github.com/harmony-one/harmony/block/v3"
|
|
"github.com/harmony-one/harmony/core/types"
|
|
"github.com/harmony-one/harmony/p2p"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestSyncPeerConfig_IsEqual(t *testing.T) {
|
|
tests := []struct {
|
|
p1, p2 *SyncPeerConfig
|
|
exp bool
|
|
}{
|
|
{
|
|
p1: &SyncPeerConfig{
|
|
peer: p2p.Peer{
|
|
IP: "0.0.0.1",
|
|
Port: "1",
|
|
},
|
|
},
|
|
p2: &SyncPeerConfig{
|
|
peer: p2p.Peer{
|
|
IP: "0.0.0.1",
|
|
Port: "2",
|
|
},
|
|
},
|
|
exp: false,
|
|
},
|
|
{
|
|
p1: &SyncPeerConfig{
|
|
peer: p2p.Peer{
|
|
IP: "0.0.0.1",
|
|
Port: "1",
|
|
},
|
|
},
|
|
p2: &SyncPeerConfig{
|
|
peer: p2p.Peer{
|
|
IP: "0.0.0.2",
|
|
Port: "1",
|
|
},
|
|
},
|
|
exp: false,
|
|
},
|
|
{
|
|
p1: &SyncPeerConfig{
|
|
peer: p2p.Peer{
|
|
IP: "0.0.0.1",
|
|
Port: "1",
|
|
},
|
|
},
|
|
p2: &SyncPeerConfig{
|
|
peer: p2p.Peer{
|
|
IP: "0.0.0.1",
|
|
Port: "1",
|
|
},
|
|
},
|
|
exp: true,
|
|
},
|
|
}
|
|
for i, test := range tests {
|
|
res := test.p1.IsEqual(test.p2)
|
|
if res != test.exp {
|
|
t.Errorf("Test %v: unexpected res %v / %v", i, res, test.exp)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Simple test for IncorrectResponse
|
|
func TestCreateTestSyncPeerConfig(t *testing.T) {
|
|
client := &downloader.Client{}
|
|
blockHashes := [][]byte{{}}
|
|
syncPeerConfig := CreateTestSyncPeerConfig(client, blockHashes)
|
|
assert.Equal(t, client, syncPeerConfig.GetClient(), "error")
|
|
}
|
|
|
|
// Simple test for IncorrectResponse
|
|
func TestCompareSyncPeerConfigByblockHashes(t *testing.T) {
|
|
client := &downloader.Client{}
|
|
blockHashes1 := [][]byte{{1, 2, 3}}
|
|
syncPeerConfig1 := CreateTestSyncPeerConfig(client, blockHashes1)
|
|
blockHashes2 := [][]byte{{1, 2, 4}}
|
|
syncPeerConfig2 := CreateTestSyncPeerConfig(client, blockHashes2)
|
|
|
|
// syncPeerConfig1 is less than syncPeerConfig2
|
|
assert.Equal(t, CompareSyncPeerConfigByblockHashes(syncPeerConfig1, syncPeerConfig2), -1, "syncPeerConfig1 is less than syncPeerConfig2")
|
|
|
|
// syncPeerConfig1 is greater than syncPeerConfig2
|
|
blockHashes1[0][2] = 5
|
|
assert.Equal(t, CompareSyncPeerConfigByblockHashes(syncPeerConfig1, syncPeerConfig2), 1, "syncPeerConfig1 is greater than syncPeerConfig2")
|
|
|
|
// syncPeerConfig1 is equal to syncPeerConfig2
|
|
blockHashes1[0][2] = 4
|
|
assert.Equal(t, CompareSyncPeerConfigByblockHashes(syncPeerConfig1, syncPeerConfig2), 0, "syncPeerConfig1 is equal to syncPeerConfig2")
|
|
|
|
// syncPeerConfig1 is less than syncPeerConfig2
|
|
assert.Equal(t,
|
|
CompareSyncPeerConfigByblockHashes(
|
|
syncPeerConfig1, syncPeerConfig2,
|
|
),
|
|
0, "syncPeerConfig1 is less than syncPeerConfig2")
|
|
}
|
|
|
|
type mockBlockchain struct {
|
|
}
|
|
|
|
func (mockBlockchain) CurrentBlock() *types.Block {
|
|
panic("implement me")
|
|
}
|
|
|
|
func (mockBlockchain) ShardID() uint32 {
|
|
return 0
|
|
}
|
|
|
|
func TestCreateStateSync(t *testing.T) {
|
|
stateSync := CreateStateSync(mockBlockchain{}, "127.0.0.1", "8000", [20]byte{}, false, nodeconfig.Validator)
|
|
|
|
if stateSync == nil {
|
|
t.Error("Unable to create stateSync")
|
|
}
|
|
}
|
|
|
|
func TestCheckPeersDuplicity(t *testing.T) {
|
|
tests := []struct {
|
|
peers []p2p.Peer
|
|
expErr error
|
|
}{
|
|
{
|
|
peers: makePeersForTest(100),
|
|
expErr: nil,
|
|
},
|
|
{
|
|
peers: append(makePeersForTest(100), p2p.Peer{
|
|
IP: makeTestPeerIP(0),
|
|
}),
|
|
expErr: errors.New("duplicate peer"),
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
err := checkPeersDuplicity(test.peers)
|
|
|
|
if assErr := assertTestError(err, test.expErr); assErr != nil {
|
|
t.Errorf("Test %v: %v", i, assErr)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLimitPeersWithBound(t *testing.T) {
|
|
tests := []struct {
|
|
size int
|
|
expSize int
|
|
}{
|
|
{0, 0},
|
|
{1, 1},
|
|
{3, 3},
|
|
{4, 3},
|
|
{7, 3},
|
|
{8, 4},
|
|
{10, 5},
|
|
{11, 5},
|
|
{100, 5},
|
|
}
|
|
for _, test := range tests {
|
|
ps := makePeersForTest(test.size)
|
|
|
|
sz, res := limitNumPeers(ps, 1)
|
|
res = res[:sz]
|
|
|
|
if len(res) != test.expSize {
|
|
t.Errorf("result size unexpected: %v / %v", len(res), test.expSize)
|
|
}
|
|
if err := checkPeersDuplicity(res); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestLimitPeersWithBound_random(t *testing.T) {
|
|
ps1 := makePeersForTest(100)
|
|
ps2 := makePeersForTest(100)
|
|
s1, s2 := int64(1), int64(2)
|
|
|
|
sz1, res1 := limitNumPeers(ps1, s1)
|
|
res1 = res1[:sz1]
|
|
sz2, res2 := limitNumPeers(ps2, s2)
|
|
res2 = res2[:sz2]
|
|
if reflect.DeepEqual(res1, res2) {
|
|
t.Fatal("not randomized limit peer")
|
|
}
|
|
}
|
|
|
|
func TestCommonBlockIter(t *testing.T) {
|
|
size := 10
|
|
blocks := makeTestBlocks(size)
|
|
iter := newCommonBlockIter(blocks, testGenesis.Hash())
|
|
|
|
itCnt := 0
|
|
for {
|
|
hasNext := iter.HasNext()
|
|
b := iter.Next()
|
|
if (b == nil) == hasNext {
|
|
t.Errorf("has next unexpected: %v / %v", hasNext, b != nil)
|
|
}
|
|
if b == nil {
|
|
break
|
|
}
|
|
itCnt++
|
|
}
|
|
if itCnt != size {
|
|
t.Errorf("unexpected iteration count: %v / %v", itCnt, size)
|
|
}
|
|
}
|
|
|
|
func makePeersForTest(size int) []p2p.Peer {
|
|
ps := make([]p2p.Peer, 0, size)
|
|
for i := 0; i != size; i++ {
|
|
ps = append(ps, makePeerForTest(i))
|
|
}
|
|
return ps
|
|
}
|
|
|
|
func makePeerForTest(i interface{}) p2p.Peer {
|
|
return p2p.Peer{
|
|
IP: makeTestPeerIP(i),
|
|
}
|
|
}
|
|
|
|
func makeTestPeerIP(i interface{}) string {
|
|
return fmt.Sprintf("%v", i)
|
|
}
|
|
|
|
func assertTestError(got, expect error) error {
|
|
if (got == nil) && (expect == nil) {
|
|
return nil
|
|
}
|
|
if (got == nil) != (expect == nil) {
|
|
return fmt.Errorf("unexpected error: [%v] / [%v]", got, expect)
|
|
}
|
|
if !strings.Contains(got.Error(), expect.Error()) {
|
|
return fmt.Errorf("unexpected error: [%v] / [%v]", got, expect)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func makeTestBlocks(size int) map[int]*types.Block {
|
|
m := make(map[int]*types.Block)
|
|
parentHash := testGenesis.Hash()
|
|
for i := 0; i != size; i++ {
|
|
b := makeTestBlock(uint64(i)+1, parentHash)
|
|
parentHash = b.Hash()
|
|
|
|
m[i] = b
|
|
}
|
|
return m
|
|
}
|
|
|
|
var testGenesis = makeTestBlock(0, common.Hash{})
|
|
|
|
func makeTestBlock(bn uint64, parentHash common.Hash) *types.Block {
|
|
testHeader := &block.Header{Header: headerV3.NewHeader()}
|
|
testHeader.SetNumber(big.NewInt(int64(bn)))
|
|
testHeader.SetParentHash(parentHash)
|
|
block := types.NewBlockWithHeader(testHeader)
|
|
return block
|
|
}
|
|
|
|
func TestSyncStatus_Get_Concurrency(t *testing.T) {
|
|
t.Skip()
|
|
|
|
ss := newSyncStatus(nodeconfig.Validator)
|
|
ss.expiration = 2 * time.Second
|
|
var (
|
|
total int32
|
|
updated int32
|
|
wg sync.WaitGroup
|
|
stop = make(chan struct{})
|
|
)
|
|
|
|
fb := func() SyncCheckResult {
|
|
time.Sleep(1 * time.Second)
|
|
atomic.AddInt32(&updated, 1)
|
|
return SyncCheckResult{IsSynchronized: true}
|
|
}
|
|
for i := 0; i != 20; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
t := time.NewTicker(20 * time.Millisecond)
|
|
defer t.Stop()
|
|
for {
|
|
select {
|
|
case <-stop:
|
|
return
|
|
case <-t.C:
|
|
atomic.AddInt32(&total, 1)
|
|
ss.Get(fb)
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
|
|
time.Sleep(10 * time.Second)
|
|
close(stop)
|
|
wg.Wait()
|
|
|
|
fmt.Printf("updated %v times\n", updated)
|
|
fmt.Printf("total %v times\n", total)
|
|
}
|
|
|