Example #1
0
// createPeerExpectations creates a slice of peerExpectation structs for the
// peers that are expected to be contained in the agent.  It will also add a
// number of expected subscribers for each Peer
func createPeerExpectations(
	mockCtrl *gomock.Controller,
	hostports []string,
	subscribers int,
) []peerExpectation {
	expectations := make([]peerExpectation, 0, len(hostports))
	for _, hp := range hostports {
		hpid := hostport.PeerIdentifier(hp)
		subs := make([]*transporttest.MockPeerSubscriber, 0, subscribers)
		for i := 0; i < subscribers; i++ {
			subs = append(subs, transporttest.NewMockPeerSubscriber(mockCtrl))
		}
		expectations = append(expectations, peerExpectation{
			identifier:  hpid,
			subscribers: subs,
		})
	}
	return expectations
}
Example #2
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)
			}
		}
	}
}