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

     1  /*
     2   * @file
     3   * @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package p2p
     7  
     8  import (
     9  	"errors"
    10  	"github.com/aergoio/aergo/p2p/list"
    11  	"github.com/aergoio/aergo/p2p/p2putil"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/aergoio/aergo-lib/log"
    16  	"github.com/aergoio/aergo/p2p/p2pcommon"
    17  	"github.com/aergoio/aergo/p2p/p2pmock"
    18  	"github.com/aergoio/aergo/types"
    19  	"github.com/golang/mock/gomock"
    20  	"github.com/libp2p/go-libp2p-core/network"
    21  )
    22  
    23  const (
    24  	OneDay = time.Hour * 24
    25  )
    26  
    27  func Test_staticWPManager_OnDiscoveredPeers(t *testing.T) {
    28  	ctrl := gomock.NewController(t)
    29  	defer ctrl.Finish()
    30  
    31  	type args struct {
    32  		metas []p2pcommon.PeerMeta
    33  	}
    34  	tests := []struct {
    35  		name      string
    36  		args      args
    37  		wantCount int
    38  	}{
    39  		{"TSingleDesign", args{desigPeers[:1]}, 0},
    40  		{"TAllDesign", args{desigPeers}, 0},
    41  		{"TNewID", args{unknownPeers}, 0},
    42  		{"TMixedIDs", args{append(unknownPeers[:5], desigPeers[:5]...)}, 0},
    43  	}
    44  	for _, tt := range tests {
    45  		t.Run(tt.name, func(t *testing.T) {
    46  			dummyPM := createDummyPM()
    47  			mockLM := p2pmock.NewMockListManager(ctrl)
    48  
    49  			dp := NewWaitingPeerManager(logger, dummyPM, mockLM, 10, false).(*staticWPManager)
    50  
    51  			dp.OnDiscoveredPeers(tt.args.metas)
    52  			if len(dummyPM.waitingPeers) != tt.wantCount {
    53  				t.Errorf("count waitingPeer %v, want %v", len(dummyPM.waitingPeers), tt.wantCount)
    54  			}
    55  		})
    56  	}
    57  }
    58  
    59  func Test_dynamicWPManager_OnDiscoveredPeers(t *testing.T) {
    60  	ctrl := gomock.NewController(t)
    61  	defer ctrl.Finish()
    62  
    63  	type args struct {
    64  		preConnected []types.PeerID
    65  		metas        []p2pcommon.PeerMeta
    66  	}
    67  	tests := []struct {
    68  		name      string
    69  		args      args
    70  		wantCount int
    71  	}{
    72  		{"TAllNew", args{nil, desigPeers[:1]}, 1},
    73  		{"TAllExist", args{desigIDs, desigPeers[:5]}, 0},
    74  		{"TMixedIDs", args{desigIDs, append(unknownPeers[:5], desigPeers[:5]...)}, 5},
    75  	}
    76  	for _, tt := range tests {
    77  		t.Run(tt.name, func(t *testing.T) {
    78  			dummyPM := createDummyPM()
    79  			mockLM := p2pmock.NewMockListManager(ctrl)
    80  
    81  			dp := NewWaitingPeerManager(logger, dummyPM, mockLM, 10, true)
    82  			for _, id := range tt.args.preConnected {
    83  				dummyPM.remotePeers[id] = &remotePeerImpl{}
    84  				dp.OnPeerConnect(id)
    85  			}
    86  
    87  			dp.OnDiscoveredPeers(tt.args.metas)
    88  			if len(dummyPM.waitingPeers) != tt.wantCount {
    89  				t.Errorf("count waitingPeer %v, want %v", len(dummyPM.waitingPeers), tt.wantCount)
    90  			}
    91  		})
    92  	}
    93  }
    94  
    95  func Test_setNextTrial(t *testing.T) {
    96  	dummyDesignated := p2pcommon.PeerMeta{Designated: true}
    97  
    98  	type args struct {
    99  		wp     *p2pcommon.WaitingPeer
   100  		setCnt int
   101  	}
   102  	tests := []struct {
   103  		name string
   104  		args args
   105  		want bool
   106  	}{
   107  		{"TDesig1", args{&p2pcommon.WaitingPeer{Meta: dummyDesignated}, 1}, true},
   108  		{"TDesigSome", args{&p2pcommon.WaitingPeer{Meta: dummyDesignated}, 5}, true},
   109  		{"TDesigMany", args{&p2pcommon.WaitingPeer{Meta: dummyDesignated}, 30}, true},
   110  
   111  		{"TUnknown1", args{&p2pcommon.WaitingPeer{Meta: dummyMeta}, 1}, false},
   112  		{"TUnknownSome", args{&p2pcommon.WaitingPeer{Meta: dummyMeta}, 5}, false},
   113  		{"TUnknownMany", args{&p2pcommon.WaitingPeer{Meta: dummyMeta}, 30}, false},
   114  	}
   115  	for _, tt := range tests {
   116  		t.Run(tt.name, func(t *testing.T) {
   117  			lastResult := false
   118  			prevDuration := time.Duration(0)
   119  			for i := 0; i < tt.args.setCnt; i++ {
   120  				now := time.Now()
   121  				lastResult = setNextTrial(tt.args.wp)
   122  				gotDuration := tt.args.wp.NextTrial.Sub(now)
   123  				// nextTrial time will be increased exponentially and clipped when trial count is bigger than internal count
   124  				// the clipped
   125  				if lastResult &&
   126  					(gotDuration < prevDuration && gotDuration < OneDay) {
   127  					t.Errorf("smaller duration %v, want at least %v", gotDuration, prevDuration)
   128  				}
   129  				prevDuration = gotDuration
   130  			}
   131  
   132  			if lastResult != tt.want {
   133  				t.Errorf("setNextTrial() = %v, want %v", lastResult, tt.want)
   134  			}
   135  		})
   136  	}
   137  }
   138  
   139  func Test_basePeerManager_tryAddPeer(t *testing.T) {
   140  	ctrl := gomock.NewController(t)
   141  	defer ctrl.Finish()
   142  
   143  	// tests for add peer
   144  	type args struct {
   145  		outbound bool
   146  		meta     p2pcommon.PeerMeta
   147  	}
   148  
   149  	tests := []struct {
   150  		name string
   151  		args args
   152  
   153  		hsRet *types.Status
   154  		hsErr error
   155  
   156  		wantDesign bool
   157  		wantHidden bool
   158  		wantID     types.PeerID
   159  		wantSucc   bool
   160  	}{
   161  		// add inbound peer
   162  		{"TIn", args{false, p2pcommon.PeerMeta{ID: dummyPeerID}},
   163  			dummyStatus(dummyPeerID, false), nil, false, false, dummyPeerID, true},
   164  
   165  		// add outbound peer
   166  		{"TOut", args{true, p2pcommon.PeerMeta{ID: dummyPeerID}},
   167  			dummyStatus(dummyPeerID, false), nil, false, false, dummyPeerID, true},
   168  
   169  		// failed to handshake
   170  		{"TErrHandshake", args{false, p2pcommon.PeerMeta{ID: dummyPeerID}},
   171  			nil, errors.New("handshake err"), false, false, dummyPeerID, false},
   172  	}
   173  	for _, tt := range tests {
   174  		t.Run(tt.name, func(t *testing.T) {
   175  			mockStream := p2pmock.NewMockStream(ctrl)
   176  			mockHSFactory := p2pmock.NewMockHSHandlerFactory(ctrl)
   177  			mockHSHandler := p2pmock.NewMockHSHandler(ctrl)
   178  			mockRW := p2pmock.NewMockMsgReadWriter(ctrl)
   179  			//mockHSFactory.EXPECT().CreateHSHandler(gomock.Any(), tt.args.outbound, tt.args.meta.ID).Return(mockHSHandler)
   180  			mockHSHandler.EXPECT().Handle(gomock.Any(), gomock.Any()).Return(mockRW, tt.hsRet, tt.hsErr)
   181  			//mockHandlerFactory := p2pmock.NewMockHSHandlerFactory(ctrl)
   182  			//mockHandlerFactory.EXPECT().InsertHandlers(gomock.AssignableToTypeOf(&remotePeerImpl{})).MaxTimes(1)
   183  
   184  			// in cases of handshake error
   185  			mockMF := p2pmock.NewMockMoFactory(ctrl)
   186  			mockMF.EXPECT().NewMsgRequestOrder(false, p2pcommon.GoAway, gomock.Any()).Return(&pbRequestOrder{}).MaxTimes(1)
   187  			mockRW.EXPECT().WriteMsg(gomock.Any()).MaxTimes(1)
   188  
   189  			pm := &peerManager{
   190  				hsFactory:      mockHSFactory,
   191  				peerHandshaked: make(chan handshakeResult, 10),
   192  			}
   193  			dpm := &basePeerManager{
   194  				pm:     pm,
   195  				logger: logger,
   196  			}
   197  			got, got1 := dpm.tryAddPeer(tt.args.outbound, tt.args.meta, mockStream, mockHSHandler)
   198  			if got1 != tt.wantSucc {
   199  				t.Errorf("basePeerManager.tryAddPeer() got1 = %v, want %v", got1, tt.wantSucc)
   200  			}
   201  			if tt.wantSucc {
   202  				if got.ID != tt.wantID {
   203  					t.Errorf("basePeerManager.tryAddPeer() got ID = %v, want %v", got.ID, tt.wantID)
   204  				}
   205  				if got.Outbound != tt.args.outbound {
   206  					t.Errorf("basePeerManager.tryAddPeer() got bound = %v, want %v", got.Outbound, tt.args.outbound)
   207  				}
   208  				if got.Designated != tt.wantDesign {
   209  					t.Errorf("basePeerManager.tryAddPeer() got Designated = %v, want %v", got.Designated, tt.wantDesign)
   210  				}
   211  				if got.Hidden != tt.wantHidden {
   212  					t.Errorf("basePeerManager.tryAddPeer() got Hidden = %v, want %v", got.Hidden, tt.wantHidden)
   213  				}
   214  			}
   215  
   216  		})
   217  	}
   218  }
   219  
   220  func dummyStatus(id types.PeerID, noexpose bool) *types.Status {
   221  	return &types.Status{Sender: &types.PeerAddress{PeerID: []byte(id)}, NoExpose: noexpose}
   222  }
   223  
   224  func Test_basePeerManager_CheckAndConnect(t *testing.T) {
   225  	type fields struct {
   226  		pm          *peerManager
   227  		lm          p2pcommon.ListManager
   228  		logger      *log.Logger
   229  		workingJobs map[types.PeerID]ConnWork
   230  	}
   231  	tests := []struct {
   232  		name   string
   233  		fields fields
   234  	}{
   235  		// TODO: Add test cases.
   236  	}
   237  	for _, tt := range tests {
   238  		t.Run(tt.name, func(t *testing.T) {
   239  			dpm := &basePeerManager{
   240  				pm:          tt.fields.pm,
   241  				lm:          tt.fields.lm,
   242  				logger:      tt.fields.logger,
   243  				workingJobs: tt.fields.workingJobs,
   244  			}
   245  			dpm.CheckAndConnect()
   246  		})
   247  	}
   248  }
   249  
   250  func Test_dynamicWPManager_CheckAndConnect(t *testing.T) {
   251  	ctrl := gomock.NewController(t)
   252  	defer ctrl.Finish()
   253  
   254  	type args struct {
   255  		preConnected []types.PeerID
   256  		metas        []p2pcommon.PeerMeta
   257  	}
   258  	tests := []struct {
   259  		name      string
   260  		args      args
   261  		wantCount int
   262  	}{
   263  		{"TAllNew", args{nil, desigPeers[:1]}, 1},
   264  		{"TAllExist", args{desigIDs, desigPeers[:5]}, 0},
   265  		{"TMixedIDs", args{desigIDs, append(unknownPeers[:5], desigPeers[:5]...)}, 5},
   266  	}
   267  	for _, tt := range tests {
   268  		t.Run(tt.name, func(t *testing.T) {
   269  			dummyPM := createDummyPM()
   270  			mockLM := p2pmock.NewMockListManager(ctrl)
   271  
   272  			dp := NewWaitingPeerManager(logger, dummyPM, mockLM, 10, true)
   273  			for _, id := range tt.args.preConnected {
   274  				dummyPM.remotePeers[id] = &remotePeerImpl{}
   275  				dp.OnPeerConnect(id)
   276  			}
   277  
   278  			dp.OnDiscoveredPeers(tt.args.metas)
   279  			if len(dummyPM.waitingPeers) != tt.wantCount {
   280  				t.Errorf("count waitingPeer %v, want %v", len(dummyPM.waitingPeers), tt.wantCount)
   281  			}
   282  		})
   283  	}
   284  }
   285  
   286  func Test_basePeerManager_connectWaitingPeers(t *testing.T) {
   287  	ctrl := gomock.NewController(t)
   288  	defer ctrl.Finish()
   289  
   290  	c := []*p2pcommon.WaitingPeer{}
   291  	for i := 0 ; i < 5 ; i++ {
   292  		meta := p2pcommon.PeerMeta{ID:p2putil.RandomPeerID()}
   293  		wp := &p2pcommon.WaitingPeer{Meta:meta, NextTrial:time.Now()}
   294  		c = append(c, wp)
   295  	}
   296  	n := []*p2pcommon.WaitingPeer{}
   297  	for i := 0 ; i < 5 ; i++ {
   298  		meta := p2pcommon.PeerMeta{ID:p2putil.RandomPeerID()}
   299  		wp := &p2pcommon.WaitingPeer{Meta:meta, NextTrial:time.Now().Add(time.Hour*100)}
   300  		n = append(n, wp)
   301  	}
   302  	type args struct {
   303  		maxJob int
   304  	}
   305  	tests := []struct {
   306  		name string
   307  		wjs  []*p2pcommon.WaitingPeer
   308  		args args
   309  
   310  		wantCnt int
   311  	}{
   312  		{"TEmptyJob", nil, args{4}, 0},
   313  		{"TFewer", c[:2], args{4}, 2},
   314  		{"TLarger", c, args{4}, 4},
   315  		{"TWithNotConn", append(nc(),c[0],n[0],n[1],c[1],n[4],c[4]), args{4}, 3},
   316  
   317  	}
   318  	for _, tt := range tests {
   319  		t.Run(tt.name, func(t *testing.T) {
   320  			mockLM := p2pmock.NewMockListManager(ctrl)
   321  			mockNT := p2pmock.NewMockNetworkTransport(ctrl)
   322  			wpMap := make(map[types.PeerID]*p2pcommon.WaitingPeer)
   323  			for _, w := range tt.wjs {
   324  				wpMap[w.Meta.ID] = w
   325  			}
   326  
   327  			dummyPM := &peerManager{nt: mockNT, waitingPeers:wpMap, workDoneChannel: make(chan p2pcommon.ConnWorkResult,10)}
   328  
   329  			dpm := &basePeerManager{
   330  				pm:          dummyPM,
   331  				lm:          mockLM,
   332  				logger:      logger,
   333  				workingJobs: make(map[types.PeerID]ConnWork),
   334  			}
   335  
   336  			mockNT.EXPECT().GetOrCreateStream(gomock.Any(), gomock.Any()).Return(nil, errors.New("stream failed")).Times(tt.wantCnt)
   337  			mockLM.EXPECT().IsBanned(gomock.Any(), gomock.Any()).Return(false, list.FarawayFuture).AnyTimes()
   338  
   339  			dpm.connectWaitingPeers(tt.args.maxJob)
   340  
   341  			doneCnt := 0
   342  			expire := time.NewTimer(time.Millisecond * 500)
   343  			WAITLOOP:
   344  			for doneCnt < tt.wantCnt {
   345  				select {
   346  				case <-dummyPM.workDoneChannel:
   347  					doneCnt++
   348  				case <-expire.C:
   349  					t.Errorf("connectWaitingPeers() job cnt %v, want %v", doneCnt, tt.wantCnt)
   350  					break WAITLOOP
   351  				}
   352  			}
   353  		})
   354  	}
   355  }
   356  
   357  func nc() []*p2pcommon.WaitingPeer {
   358  	return nil
   359  }
   360  func Test_basePeerManager_OnInboundConn(t *testing.T) {
   361  	ctrl := gomock.NewController(t)
   362  	defer ctrl.Finish()
   363  
   364  	type fields struct {
   365  		workingJobs map[types.PeerID]ConnWork
   366  	}
   367  	type args struct {
   368  		s network.Stream
   369  	}
   370  	tests := []struct {
   371  		name   string
   372  		fields fields
   373  		args   args
   374  	}{
   375  		// TODO: Add test cases.
   376  	}
   377  	for _, tt := range tests {
   378  		t.Run(tt.name, func(t *testing.T) {
   379  			dummyPM := &peerManager{}
   380  			mockLM := p2pmock.NewMockListManager(ctrl)
   381  
   382  			mockStream := p2pmock.NewMockStream(ctrl)
   383  
   384  			dpm := &basePeerManager{
   385  				pm:          dummyPM,
   386  				lm:          mockLM,
   387  				logger:      logger,
   388  				workingJobs: tt.fields.workingJobs,
   389  			}
   390  			dpm.OnInboundConn(mockStream)
   391  		})
   392  	}
   393  }