Example #1
0
func TestAgent(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	type testStruct struct {
		msg           string
		agent         *Agent
		appliedFunc   func(*Agent) error
		expectedPeers []peerExpectation
		expectedErr   error
	}
	tests := []testStruct{
		func() (s testStruct) {
			s.msg = "one retain"
			s.expectedPeers = createPeerExpectations(
				mockCtrl,
				[]string{"localhost:1234"},
				1,
			)
			s.appliedFunc = func(a *Agent) error {
				_, err := a.RetainPeer(s.expectedPeers[0].identifier, s.expectedPeers[0].subscribers[0])
				return err
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "one retain one release"
			s.expectedPeers = []peerExpectation{}
			s.appliedFunc = func(a *Agent) error {
				pid := hostport.PeerIdentifier("localhost:1234")

				sub := transporttest.NewMockPeerSubscriber(mockCtrl)

				if _, err := a.RetainPeer(pid, sub); err != nil {
					return err
				}
				return a.ReleasePeer(pid, sub)
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "one retain one release using peer"
			s.expectedPeers = []peerExpectation{}
			s.appliedFunc = func(a *Agent) error {
				pid := hostport.PeerIdentifier("localhost:1234")

				sub := transporttest.NewMockPeerSubscriber(mockCtrl)

				peer, err := a.RetainPeer(pid, sub)
				if err != nil {
					return err
				}
				err = a.ReleasePeer(peer, sub)

				return err
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "three retains"
			s.expectedPeers = createPeerExpectations(
				mockCtrl,
				[]string{"localhost:1234"},
				3,
			)
			s.appliedFunc = func(a *Agent) error {
				a.RetainPeer(s.expectedPeers[0].identifier, s.expectedPeers[0].subscribers[0])
				a.RetainPeer(s.expectedPeers[0].identifier, s.expectedPeers[0].subscribers[1])
				_, err := a.RetainPeer(s.expectedPeers[0].identifier, s.expectedPeers[0].subscribers[2])
				return err
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "three retains, one release"
			s.expectedPeers = createPeerExpectations(
				mockCtrl,
				[]string{"localhost:1234"},
				2,
			)
			s.appliedFunc = func(a *Agent) error {
				unSub := transporttest.NewMockPeerSubscriber(mockCtrl)
				a.RetainPeer(s.expectedPeers[0].identifier, unSub)
				a.RetainPeer(s.expectedPeers[0].identifier, s.expectedPeers[0].subscribers[0])
				a.ReleasePeer(s.expectedPeers[0].identifier, unSub)
				a.RetainPeer(s.expectedPeers[0].identifier, s.expectedPeers[0].subscribers[1])

				return nil
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "three retains, three release"
			s.expectedPeers = []peerExpectation{}
			s.appliedFunc = func(a *Agent) error {
				pid := hostport.PeerIdentifier("localhost:123")

				sub := transporttest.NewMockPeerSubscriber(mockCtrl)
				sub2 := transporttest.NewMockPeerSubscriber(mockCtrl)
				sub3 := transporttest.NewMockPeerSubscriber(mockCtrl)

				a.RetainPeer(pid, sub)
				a.RetainPeer(pid, sub2)
				a.ReleasePeer(pid, sub)
				a.RetainPeer(pid, sub3)
				a.ReleasePeer(pid, sub2)
				a.ReleasePeer(pid, sub3)

				return nil
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "no retains, one release"
			s.agent = NewAgent()
			s.expectedPeers = []peerExpectation{}

			pid := hostport.PeerIdentifier("localhost:1234")
			s.expectedErr = errors.ErrAgentHasNoReferenceToPeer{
				Agent:          s.agent,
				PeerIdentifier: pid,
			}

			s.appliedFunc = func(a *Agent) error {
				return a.ReleasePeer(pid, transporttest.NewMockPeerSubscriber(mockCtrl))
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "retain with invalid identifier"
			s.expectedPeers = []peerExpectation{}

			pid := transporttest.NewMockPeerIdentifier(mockCtrl)
			s.expectedErr = errors.ErrInvalidPeerType{
				ExpectedType:   "hostport.PeerIdentifier",
				PeerIdentifier: pid,
			}

			s.appliedFunc = func(a *Agent) error {
				_, err := a.RetainPeer(pid, transporttest.NewMockPeerSubscriber(mockCtrl))
				return err
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "one retains, one release (from different subscriber)"
			s.expectedPeers = createPeerExpectations(
				mockCtrl,
				[]string{"localhost:1234"},
				1,
			)

			invalidSub := transporttest.NewMockPeerSubscriber(mockCtrl)
			s.expectedErr = errors.ErrPeerHasNoReferenceToSubscriber{
				PeerIdentifier: s.expectedPeers[0].identifier,
				PeerSubscriber: invalidSub,
			}

			s.appliedFunc = func(a *Agent) error {
				a.RetainPeer(s.expectedPeers[0].identifier, s.expectedPeers[0].subscribers[0])
				return a.ReleasePeer(s.expectedPeers[0].identifier, invalidSub)
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "multi peer retain/release"
			s.expectedPeers = createPeerExpectations(
				mockCtrl,
				[]string{"localhost:1234", "localhost:1111", "localhost:2222"},
				2,
			)

			s.appliedFunc = func(a *Agent) error {
				expP1 := s.expectedPeers[0]
				expP2 := s.expectedPeers[1]
				expP3 := s.expectedPeers[2]
				rndP1 := hostport.PeerIdentifier("localhost:9888")
				rndP2 := hostport.PeerIdentifier("localhost:9883")
				rndSub1 := transporttest.NewMockPeerSubscriber(mockCtrl)
				rndSub2 := transporttest.NewMockPeerSubscriber(mockCtrl)
				rndSub3 := transporttest.NewMockPeerSubscriber(mockCtrl)

				// exp1: Defer a bunch of Releases
				a.RetainPeer(expP1.identifier, rndSub1)
				defer a.ReleasePeer(expP1.identifier, rndSub1)
				a.RetainPeer(expP1.identifier, expP1.subscribers[0])
				a.RetainPeer(expP1.identifier, rndSub2)
				defer a.ReleasePeer(expP1.identifier, rndSub2)
				a.RetainPeer(expP1.identifier, expP1.subscribers[1])

				// exp2: Retain a subscriber, release it, then retain it again
				a.RetainPeer(expP2.identifier, expP2.subscribers[0])
				a.RetainPeer(expP2.identifier, expP2.subscribers[1])
				a.ReleasePeer(expP2.identifier, expP2.subscribers[0])
				a.ReleasePeer(expP2.identifier, expP2.subscribers[1])
				a.RetainPeer(expP2.identifier, expP2.subscribers[0])
				a.RetainPeer(expP2.identifier, expP2.subscribers[1])

				// exp3: Retain release a Peer
				a.RetainPeer(expP3.identifier, rndSub3)
				a.ReleasePeer(expP3.identifier, rndSub3)
				a.RetainPeer(expP3.identifier, expP3.subscribers[0])
				a.RetainPeer(expP3.identifier, expP3.subscribers[1])

				// rnd1: retain/release on random sub
				a.RetainPeer(rndP1, rndSub1)
				a.ReleasePeer(rndP1, rndSub1)

				// rnd2: retain/release on already used subscriber
				a.RetainPeer(rndP2, expP1.subscribers[0])
				a.ReleasePeer(rndP2, expP1.subscribers[0])

				return nil
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "notification verification"
			s.expectedPeers = createPeerExpectations(
				mockCtrl,
				[]string{"localhost:1234"},
				2,
			)

			s.expectedPeers[0].subscribers[0].EXPECT().NotifyStatusChanged(
				peerIdentifierMatcher(s.expectedPeers[0].identifier),
			).Times(3)
			s.expectedPeers[0].subscribers[1].EXPECT().NotifyStatusChanged(
				peerIdentifierMatcher(s.expectedPeers[0].identifier),
			).Times(3)

			s.appliedFunc = func(a *Agent) error {
				peer, _ := a.RetainPeer(s.expectedPeers[0].identifier, s.expectedPeers[0].subscribers[0])
				a.RetainPeer(s.expectedPeers[0].identifier, s.expectedPeers[0].subscribers[1])

				a.NotifyStatusChanged(peer)
				a.NotifyStatusChanged(peer)
				a.NotifyStatusChanged(peer)

				return nil
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "no notification after release"
			s.expectedPeers = []peerExpectation{}

			sub := transporttest.NewMockPeerSubscriber(mockCtrl)
			sub.EXPECT().NotifyStatusChanged(gomock.Any()).Times(0)

			pid := hostport.PeerIdentifier("localhost:1234")

			s.appliedFunc = func(a *Agent) error {
				peer, _ := a.RetainPeer(pid, sub)
				a.ReleasePeer(pid, sub)

				a.NotifyStatusChanged(peer)
				a.NotifyStatusChanged(peer)
				a.NotifyStatusChanged(peer)

				return nil
			}
			return
		}(),
		func() (s testStruct) {
			s.msg = "notification before versus after release"
			s.expectedPeers = []peerExpectation{}

			pid := hostport.PeerIdentifier("localhost:1234")

			sub := transporttest.NewMockPeerSubscriber(mockCtrl)
			sub.EXPECT().NotifyStatusChanged(peerIdentifierMatcher(pid)).Times(1)

			s.appliedFunc = func(a *Agent) error {
				peer, _ := a.RetainPeer(pid, sub)

				a.NotifyStatusChanged(peer)

				a.ReleasePeer(pid, sub)

				a.NotifyStatusChanged(peer)
				a.NotifyStatusChanged(peer)
				a.NotifyStatusChanged(peer)

				return nil
			}
			return
		}(),
	}

	for _, tt := range tests {
		agent := tt.agent
		if agent == nil {
			agent = NewAgent()
		}

		err := tt.appliedFunc(agent)

		assert.Equal(t, tt.expectedErr, err, tt.msg)
		assert.Len(t, agent.peerNodes, len(tt.expectedPeers), tt.msg)
		for _, expectedPeerNode := range tt.expectedPeers {
			peerNode, ok := agent.peerNodes[expectedPeerNode.identifier.Identifier()]
			assert.True(t, ok, tt.msg)

			assert.Equal(t, expectedPeerNode.identifier.Identifier(), peerNode.peer.Identifier(), tt.msg)

			assert.Len(t, peerNode.subscribers, len(expectedPeerNode.subscribers), tt.msg)
			for _, expectedSubscriber := range expectedPeerNode.subscribers {
				_, ok := peerNode.subscribers[expectedSubscriber]
				assert.True(t, ok, "subscriber (%v) not in list (%v). %s", expectedSubscriber, peerNode.subscribers, tt.msg)
			}
		}
	}
}
Example #2
0
func TestSingle(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	type expectedChooseResult struct {
		peer transport.Peer
		err  error
	}

	type testStruct struct {
		msg                   string
		pid                   transport.PeerIdentifier
		agent                 *transporttest.MockAgent
		appliedFunc           func(*single) error
		expectedPeerID        transport.PeerIdentifier
		expectedPeer          transport.Peer
		expectedAgent         transport.Agent
		expectedStarted       bool
		expectedErr           error
		expectedChooseResults []expectedChooseResult
	}
	tests := []testStruct{
		func() (s testStruct) {
			s.msg = "setup"
			s.pid = transporttest.NewMockPeerIdentifier(mockCtrl)
			s.agent = transporttest.NewMockAgent(mockCtrl)

			s.appliedFunc = func(pl *single) error {
				return nil
			}

			s.expectedPeerID = s.pid
			s.expectedAgent = s.agent
			s.expectedStarted = false
			return
		}(),
		func() (s testStruct) {
			s.msg = "stop before start"
			s.pid = transporttest.NewMockPeerIdentifier(mockCtrl)
			s.agent = transporttest.NewMockAgent(mockCtrl)

			s.appliedFunc = func(pl *single) error {
				return pl.Stop()
			}

			s.expectedErr = errors.ErrPeerListNotStarted("single")
			s.expectedPeerID = s.pid
			s.expectedAgent = s.agent
			s.expectedStarted = false
			return
		}(),
		func() (s testStruct) {
			s.msg = "choose before start"
			s.pid = transporttest.NewMockPeerIdentifier(mockCtrl)
			s.agent = transporttest.NewMockAgent(mockCtrl)

			s.appliedFunc = func(pl *single) error {
				return nil
			}

			s.expectedPeerID = s.pid
			s.expectedAgent = s.agent
			s.expectedStarted = false
			s.expectedChooseResults = []expectedChooseResult{{
				peer: nil,
				err:  errors.ErrPeerListNotStarted("single"),
			}}
			return
		}(),
		func() (s testStruct) {
			s.msg = "start and choose"
			s.pid = transporttest.NewMockPeerIdentifier(mockCtrl)
			s.agent = transporttest.NewMockAgent(mockCtrl)

			s.expectedPeer = transporttest.NewMockPeer(mockCtrl)
			s.agent.EXPECT().RetainPeer(s.pid, gomock.Any()).Return(s.expectedPeer, nil)

			s.appliedFunc = func(pl *single) error {
				return pl.Start()
			}

			s.expectedPeerID = s.pid
			s.expectedAgent = s.agent
			s.expectedStarted = true
			s.expectedChooseResults = []expectedChooseResult{{
				peer: s.expectedPeer,
				err:  nil,
			}}
			return
		}(),
		func() (s testStruct) {
			s.msg = "start with agent error"
			s.pid = transporttest.NewMockPeerIdentifier(mockCtrl)
			s.agent = transporttest.NewMockAgent(mockCtrl)

			s.expectedErr = fmt.Errorf("test error")
			s.agent.EXPECT().RetainPeer(s.pid, gomock.Any()).Return(nil, s.expectedErr)

			s.appliedFunc = func(pl *single) error {
				return pl.Start()
			}

			s.expectedPeerID = s.pid
			s.expectedAgent = s.agent
			s.expectedStarted = false
			return
		}(),
		func() (s testStruct) {
			s.msg = "start twice"
			s.pid = transporttest.NewMockPeerIdentifier(mockCtrl)
			s.agent = transporttest.NewMockAgent(mockCtrl)

			s.expectedPeer = transporttest.NewMockPeer(mockCtrl)
			s.agent.EXPECT().RetainPeer(s.pid, gomock.Any()).Return(s.expectedPeer, nil)

			s.appliedFunc = func(pl *single) error {
				pl.Start()
				return pl.Start()
			}

			s.expectedErr = errors.ErrPeerListAlreadyStarted("single")
			s.expectedPeerID = s.pid
			s.expectedAgent = s.agent
			s.expectedStarted = true
			return
		}(),
		func() (s testStruct) {
			s.msg = "start stop"
			s.pid = transporttest.NewMockPeerIdentifier(mockCtrl)
			s.agent = transporttest.NewMockAgent(mockCtrl)

			peer := transporttest.NewMockPeer(mockCtrl)
			s.agent.EXPECT().RetainPeer(s.pid, gomock.Any()).Return(peer, nil)
			s.agent.EXPECT().ReleasePeer(s.pid, gomock.Any()).Return(nil)

			s.appliedFunc = func(pl *single) error {
				err := pl.Start()
				if err != nil {
					return err
				}
				return pl.Stop()
			}

			s.expectedErr = nil
			s.expectedPeerID = s.pid
			s.expectedPeer = nil
			s.expectedAgent = s.agent
			s.expectedStarted = false
			return
		}(),
		func() (s testStruct) {
			s.msg = "start stop release failure"
			s.pid = transporttest.NewMockPeerIdentifier(mockCtrl)
			s.agent = transporttest.NewMockAgent(mockCtrl)

			s.expectedPeer = transporttest.NewMockPeer(mockCtrl)
			s.agent.EXPECT().RetainPeer(s.pid, gomock.Any()).Return(s.expectedPeer, nil)

			s.expectedErr = errors.ErrAgentHasNoReferenceToPeer{}
			s.agent.EXPECT().ReleasePeer(s.pid, gomock.Any()).Return(s.expectedErr)

			s.appliedFunc = func(pl *single) error {
				err := pl.Start()
				if err != nil {
					return err
				}
				return pl.Stop()
			}

			s.expectedPeerID = s.pid
			s.expectedAgent = s.agent
			s.expectedStarted = false
			return
		}(),
	}

	for _, tt := range tests {
		pl := NewSingle(tt.pid, tt.agent).(*single)

		err := tt.appliedFunc(pl)

		assert.Equal(t, tt.expectedErr, err, tt.msg)
		assert.Equal(t, tt.expectedAgent, pl.agent, tt.msg)
		assert.Equal(t, tt.expectedPeerID, pl.initialPeerID, tt.msg)
		assert.Equal(t, tt.expectedPeer, pl.peer, tt.msg)
		assert.Equal(t, tt.expectedStarted, pl.started, tt.msg)

		for _, expectedResult := range tt.expectedChooseResults {
			peer, err := pl.ChoosePeer(context.Background(), &transport.Request{})

			assert.Equal(t, expectedResult.peer, peer, tt.msg)
			assert.True(t, expectedResult.peer == peer, tt.msg)
			assert.Equal(t, expectedResult.err, err, tt.msg)
		}
	}
}