github.com/aergoio/aergo@v1.3.1/p2p/syncmanager_test.go (about)

     1  /*
     2   * @file
     3   * @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package p2p
     7  
     8  import (
     9  	"bytes"
    10  	"testing"
    11  
    12  	"github.com/aergoio/aergo-lib/log"
    13  	"github.com/aergoio/aergo/chain"
    14  	"github.com/aergoio/aergo/message"
    15  	"github.com/aergoio/aergo/p2p/p2pcommon"
    16  	"github.com/aergoio/aergo/p2p/p2pmock"
    17  	"github.com/aergoio/aergo/types"
    18  	"github.com/golang/mock/gomock"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/mock"
    21  )
    22  
    23  func TestSyncManager_HandleBlockProducedNotice(t *testing.T) {
    24  	// only interested in max block size
    25  	chain.Init(1024*1024,"",false,0,0)
    26  
    27  	ctrl := gomock.NewController(t)
    28  	defer ctrl.Finish()
    29  
    30  	logger := log.NewLogger("test.p2p")
    31  	sampleBlock := &types.Block{Hash: dummyBlockHash}
    32  	txs := make([]*types.Tx,1)
    33  	txs[0] = &types.Tx{Hash:make([]byte,1024*1024*2)}
    34  	sampleBigBlock := &types.Block{Hash:dummyBlockHash,Body:&types.BlockBody{Txs:txs}}
    35  	var blkHash = types.ToBlockID(dummyBlockHash)
    36  	// test if new block notice comes
    37  	tests := []struct {
    38  		name string
    39  		put  *types.BlockID
    40  		addedBlock *types.Block
    41  
    42  		wantActorCall bool
    43  	}{
    44  		// 1. Succ : valid block hash and not exist in local
    45  		{"TSucc", nil, sampleBlock,true},
    46  		// 2. Rare case - valid block hash but already exist in local cache
    47  		{"TExist", &blkHash, sampleBlock, false},
    48  		{"TTooBigBlock", nil, sampleBigBlock,false},
    49  	}
    50  	for _, test := range tests {
    51  		t.Run(test.name, func(t *testing.T) {
    52  			mockPM := p2pmock.NewMockPeerManager(ctrl)
    53  			mockActor := p2pmock.NewMockActorService(ctrl)
    54  			mockPeer := p2pmock.NewMockRemotePeer(ctrl)
    55  			mockPeer.EXPECT().Name().Return("16..aadecf@1").AnyTimes()
    56  			mockPeer.EXPECT().ID().Return(sampleMeta.ID).AnyTimes()
    57  			actorCallCnt := 0
    58  			if test.wantActorCall {
    59  				actorCallCnt = 1
    60  			}
    61  			mockActor.EXPECT().SendRequest(message.ChainSvc, gomock.Any()).Times(actorCallCnt)
    62  
    63  			target := newSyncManager(mockActor, mockPM, logger).(*syncManager)
    64  			if test.put != nil {
    65  				target.blkCache.Add(*test.put, true)
    66  			}
    67  			target.HandleBlockProducedNotice(mockPeer, test.addedBlock)
    68  		})
    69  	}
    70  }
    71  
    72  func TestSyncManager_HandleNewBlockNotice(t *testing.T) {
    73  	// only interested in max block size
    74  	chain.Init(1024*1024,"",false,0,0)
    75  
    76  	ctrl := gomock.NewController(t)
    77  	defer ctrl.Finish()
    78  
    79  	logger := log.NewLogger("test.p2p")
    80  	sampleBlock := &types.Block{Hash: dummyBlockHash}
    81  	var blkHash types.BlockID
    82  	// test if new block notice comes
    83  	tests := []struct {
    84  		name    string
    85  		put     *types.BlockID
    86  		syncing bool
    87  		setup   func(tt *testing.T, actor *p2pmock.MockActorService, ca *p2pmock.MockChainAccessor, peer *p2pmock.MockRemotePeer) (types.BlockID, *types.NewBlockNotice)
    88  		//verify  func(tt *testing.T, actor *p2pmock.MockActorService, ca *p2pmock.MockChainAccessor)
    89  	}{
    90  		// 1. Succ : valid block hash and not exist in local
    91  		{"TSucc", nil, false,
    92  			func(tt *testing.T, actor *p2pmock.MockActorService, ca *p2pmock.MockChainAccessor, peer *p2pmock.MockRemotePeer) (types.BlockID, *types.NewBlockNotice) {
    93  				ca.EXPECT().GetBlock(gomock.Any()).Return(nil, nil)
    94  				actor.EXPECT().GetChainAccessor().Return(ca)
    95  				copy(blkHash[:], dummyBlockHash)
    96  				actor.EXPECT().SendRequest(message.P2PSvc, gomock.Any())
    97  				peer.EXPECT().Name().Return("16..aadecf@1")
    98  				return blkHash, &types.NewBlockNotice{BlockHash: dummyBlockHash}
    99  			}},
   100  		// 1-1. Succ : valid block hash and exist in chainsvc, but not in cache
   101  		{"TSuccExistChain", nil, false,
   102  			func(tt *testing.T, actor *p2pmock.MockActorService, ca *p2pmock.MockChainAccessor, peer *p2pmock.MockRemotePeer) (types.BlockID, *types.NewBlockNotice) {
   103  				ca.EXPECT().GetBlock(gomock.Any()).Return(sampleBlock, nil)
   104  				copy(blkHash[:], dummyBlockHash)
   105  				actor.EXPECT().GetChainAccessor().Return(ca)
   106  				actor.EXPECT().SendRequest(message.P2PSvc, gomock.Any()).MaxTimes(0)
   107  				return blkHash, &types.NewBlockNotice{BlockHash: dummyBlockHash}
   108  			}},
   109  		// 2. SuccCachehit : valid block hash but already exist in local cache
   110  		{"TSuccExistCache", &blkHash, false,
   111  			func(tt *testing.T, actor *p2pmock.MockActorService, ca *p2pmock.MockChainAccessor, peer *p2pmock.MockRemotePeer) (types.BlockID, *types.NewBlockNotice) {
   112  				ca.EXPECT().GetBlock(gomock.Any()).Return(sampleBlock, nil).MaxTimes(0)
   113  				copy(blkHash[:], dummyBlockHash)
   114  
   115  				//ca.AssertNotCalled(tt, "GetBlock", mock.AnythingOfType("[]uint8"))
   116  				//actor.EXPECT().AssertNotCalled(tt, "SendRequest", message.P2PSvc, mock.Anything)
   117  				actor.EXPECT().SendRequest(message.P2PSvc, mock.Anything).MaxTimes(0)
   118  				return blkHash, &types.NewBlockNotice{BlockHash: dummyBlockHash}
   119  			}},
   120  		// 2. Busy : other sync worker is working
   121  		{"TBusy", &blkHash, true,
   122  			func(tt *testing.T, actor *p2pmock.MockActorService, ca *p2pmock.MockChainAccessor, peer *p2pmock.MockRemotePeer) (types.BlockID, *types.NewBlockNotice) {
   123  				copy(blkHash[:], dummyBlockHash)
   124  				actor.EXPECT().GetChainAccessor().MaxTimes(0)
   125  				actor.EXPECT().SendRequest(message.P2PSvc, gomock.Any()).MaxTimes(0)
   126  				return blkHash, &types.NewBlockNotice{BlockHash: dummyBlockHash}
   127  			}},
   128  	}
   129  	for _, test := range tests {
   130  		t.Run(test.name, func(t *testing.T) {
   131  			mockPM := p2pmock.NewMockPeerManager(ctrl)
   132  			mockActor := p2pmock.NewMockActorService(ctrl)
   133  			mockCA := p2pmock.NewMockChainAccessor(ctrl)
   134  			mockPeer := p2pmock.NewMockRemotePeer(ctrl)
   135  			mockPeer.EXPECT().ID().Return(sampleMeta.ID)
   136  
   137  			_, data := test.setup(t, mockActor, mockCA, mockPeer)
   138  			target := newSyncManager(mockActor, mockPM, logger).(*syncManager)
   139  			if test.put != nil {
   140  				target.blkCache.Add(*test.put, true)
   141  			}
   142  			target.HandleNewBlockNotice(mockPeer, data)
   143  			//test.verify(t, mockActor, mockCA)
   144  		})
   145  	}
   146  }
   147  
   148  func TestSyncManager_HandleNewTxNotice(t *testing.T) {
   149  	ctrl := gomock.NewController(t)
   150  	defer ctrl.Finish()
   151  
   152  	logger := log.NewLogger("test.p2p")
   153  	rawHashes := sampleTxs
   154  	txHashes := sampleTxHashes
   155  
   156  	// test if new block notice comes
   157  	tests := []struct {
   158  		name     string
   159  		inCache  []types.TxID
   160  		setup    func(tt *testing.T, actor *p2pmock.MockActorService)
   161  		expected []types.TxID
   162  	}{
   163  		// 1. Succ : valid tx hashes and not exist in local cache
   164  		{"TSuccAllNew", nil,
   165  			func(tt *testing.T, actor *p2pmock.MockActorService) {
   166  				actor.EXPECT().SendRequest(message.P2PSvc, gomock.Any()).DoAndReturn(func(name string, arg *message.GetTransactions) {
   167  					for i, hash := range arg.Hashes {
   168  						assert.True(tt, bytes.Equal(hash, txHashes[i][:]))
   169  					}
   170  					assert.True(tt, len(arg.Hashes) == len(txHashes))
   171  				})
   172  			}, sampleTxHashes},
   173  		// 2. Succ : valid tx hashes and partially exist in local cache
   174  		{"TSuccExistPart", txHashes[2:],
   175  			func(tt *testing.T, actor *p2pmock.MockActorService) {
   176  				// only hashes not in cache are sent to method, which is first 2 hashes
   177  				actor.EXPECT().SendRequest(message.P2PSvc, gomock.Any()).DoAndReturn(func(name string, arg *message.GetTransactions) {
   178  					for i, hash := range arg.Hashes {
   179  						assert.True(tt, bytes.Equal(hash, txHashes[i][:]))
   180  					}
   181  					assert.True(tt, len(arg.Hashes) == 2)
   182  				})
   183  
   184  			}, sampleTxHashes[:len(sampleTxHashes)-1]},
   185  		// 3. Succ : valid tx hashes and all exist in local cache
   186  		{"TSuccExistAll", txHashes,
   187  			func(tt *testing.T, actor *p2pmock.MockActorService) {
   188  				actor.EXPECT().SendRequest(message.P2PSvc, gomock.Any()).MaxTimes(0)
   189  			}, sampleTxHashes[:0]},
   190  	}
   191  	for _, test := range tests {
   192  		t.Run(test.name, func(t *testing.T) {
   193  			mockPM := p2pmock.NewMockPeerManager(ctrl)
   194  			mockActor := p2pmock.NewMockActorService(ctrl)
   195  			mockPeer := p2pmock.NewMockRemotePeer(ctrl)
   196  			mockPeer.EXPECT().ID().Return(sampleMeta.ID)
   197  
   198  			data := &types.NewTransactionsNotice{TxHashes: rawHashes}
   199  
   200  			test.setup(t, mockActor)
   201  			target := newSyncManager(mockActor, mockPM, logger)
   202  			if test.inCache != nil {
   203  				for _, hash := range test.inCache {
   204  					target.(*syncManager).txCache.Add(hash, true)
   205  				}
   206  			}
   207  			target.HandleNewTxNotice(mockPeer, txHashes, data)
   208  		})
   209  	}
   210  }
   211  
   212  func TestSyncManager_HandleGetBlockResponse(t *testing.T) {
   213  	// only interested in max block size
   214  	chain.Init(1024*1024,"",false,0,0)
   215  
   216  	ctrl := gomock.NewController(t)
   217  	defer ctrl.Finish()
   218  
   219  	totalBlkCnt := len(sampleTxs)
   220  	sampleBlocks := make([]*types.Block, totalBlkCnt)
   221  	for i, hash := range sampleTxs {
   222  		sampleBlocks[i] = &types.Block{Hash: hash}
   223  	}
   224  	tests := []struct {
   225  		name       string
   226  		respBlocks []*types.Block
   227  
   228  		// call count directly to chainservice
   229  		chainCallCnt int
   230  	}{
   231  		// 1. message triggered by NewBlockNotice (maybe)
   232  		{"TSingleBlock", sampleBlocks[:1], 1},
   233  		// 2. message triggered by newsyncer but not handled by it (caused by sync fail or timeout)
   234  		{"TZeroBlock", sampleBlocks[:0], 0},
   235  		{"TMultiBlocks", sampleBlocks, 0},
   236  	}
   237  	for _, test := range tests {
   238  		t.Run(test.name, func(t *testing.T) {
   239  			mockPM := p2pmock.NewMockPeerManager(ctrl)
   240  			mockActor := p2pmock.NewMockActorService(ctrl)
   241  			mockPeer := p2pmock.NewMockRemotePeer(ctrl)
   242  			mockPeer.EXPECT().ID().Return(sampleMeta.ID)
   243  
   244  			mockActor.EXPECT().SendRequest(gomock.Any(), gomock.Any()).Times(test.chainCallCnt)
   245  			dummyMsgID := p2pcommon.NewMsgID()
   246  			target := newSyncManager(mockActor, mockPM, logger).(*syncManager)
   247  
   248  			msg := p2pcommon.NewSimpleRespMsgVal(p2pcommon.PingResponse, p2pcommon.NewMsgID(), dummyMsgID)
   249  			resp := &types.GetBlockResponse{Blocks: test.respBlocks}
   250  			target.HandleGetBlockResponse(mockPeer, msg, resp)
   251  
   252  			//mockActor.AssertNumberOfCalls(t, "SendRequest", test.chainCallCnt)
   253  		})
   254  	}
   255  }