// 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 }
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) } } } }