Merge pull request #1767 from weaveworks/1765-test-gossip-surrogate-failure
better emulation of connections in gossip tests. Fixes #1765.
This commit is contained in:
commit
b51b1adfcd
1 file changed
+52
-52
+52
-52
@@ -11,9 +11,11 @@ import (
|
||||
// TODO test gossip unicast; atm we only test topology gossip and
|
||||
// surrogates, neither of which employ unicast.
|
||||
|
||||
type mockChannelConnection struct {
|
||||
type mockGossipConnection struct {
|
||||
RemoteConnection
|
||||
dest *Router
|
||||
router *Router
|
||||
dest *Router
|
||||
start chan struct{}
|
||||
}
|
||||
|
||||
func NewTestRouter(name string) *Router {
|
||||
@@ -23,12 +25,22 @@ func NewTestRouter(name string) *Router {
|
||||
return router
|
||||
}
|
||||
|
||||
func (conn *mockChannelConnection) SendProtocolMsg(protocolMsg ProtocolMsg) {
|
||||
func (conn *mockGossipConnection) SendProtocolMsg(protocolMsg ProtocolMsg) {
|
||||
<-conn.start
|
||||
if err := conn.dest.handleGossip(protocolMsg.tag, protocolMsg.msg); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (conn *mockGossipConnection) Connect() {
|
||||
conn.router.Ourself.handleAddConnection(conn)
|
||||
conn.router.Ourself.handleConnectionEstablished(conn)
|
||||
}
|
||||
|
||||
func (conn *mockGossipConnection) Start() {
|
||||
close(conn.start)
|
||||
}
|
||||
|
||||
func sendPendingGossip(routers ...*Router) {
|
||||
// Loop until all routers report they didn't send anything
|
||||
for sentSomething := true; sentSomething; {
|
||||
@@ -39,19 +51,27 @@ func sendPendingGossip(routers ...*Router) {
|
||||
}
|
||||
}
|
||||
|
||||
func (router *Router) AddTestChannelConnection(r *Router) {
|
||||
func AddTestGossipConnection(r1, r2 *Router) {
|
||||
c1 := r1.NewTestGossipConnection(r2)
|
||||
c2 := r2.NewTestGossipConnection(r1)
|
||||
c1.Connect()
|
||||
c2.Start()
|
||||
c2.Connect()
|
||||
c1.Start()
|
||||
}
|
||||
|
||||
func (router *Router) NewTestGossipConnection(r *Router) *mockGossipConnection {
|
||||
fromPeer := NewPeerFrom(router.Ourself.Peer)
|
||||
toPeer := NewPeerFrom(r.Ourself.Peer)
|
||||
|
||||
r.Peers.FetchWithDefault(fromPeer) // Has side-effect of incrementing refcount
|
||||
toPeer = router.Peers.FetchWithDefault(toPeer) //
|
||||
|
||||
conn := &mockChannelConnection{RemoteConnection{router.Ourself.Peer, toPeer, "", false, true}, r}
|
||||
router.Ourself.handleAddConnection(conn)
|
||||
router.Ourself.handleConnectionEstablished(conn)
|
||||
return &mockGossipConnection{
|
||||
RemoteConnection{router.Ourself.Peer, toPeer, "", false, true}, router, r, make(chan struct{})}
|
||||
}
|
||||
|
||||
func (router *Router) DeleteTestChannelConnection(r *Router) {
|
||||
func (router *Router) DeleteTestGossipConnection(r *Router) {
|
||||
fromName := router.Ourself.Peer.Name
|
||||
toName := r.Ourself.Peer.Name
|
||||
|
||||
@@ -87,67 +107,51 @@ func checkTopology(t *testing.T, router *Router, wantedPeers ...*Peer) {
|
||||
router.Peers.RUnlock()
|
||||
}
|
||||
|
||||
func flushAndCheckTopology(t *testing.T, routers []*Router, wantedPeers ...*Peer) {
|
||||
sendPendingGossip(routers...)
|
||||
for _, r := range routers {
|
||||
checkTopology(t, r, wantedPeers...)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGossipTopology(t *testing.T) {
|
||||
// Create some peers that will talk to each other
|
||||
r1 := NewTestRouter("01:00:00:01:00:00")
|
||||
r2 := NewTestRouter("02:00:00:02:00:00")
|
||||
r3 := NewTestRouter("03:00:00:03:00:00")
|
||||
|
||||
routers := []*Router{r1, r2, r3}
|
||||
// Check state when they have no connections
|
||||
checkTopology(t, r1, r1.tp())
|
||||
checkTopology(t, r2, r2.tp())
|
||||
|
||||
// Now try adding some connections
|
||||
r1.AddTestChannelConnection(r2)
|
||||
sendPendingGossip(r1, r2)
|
||||
checkTopology(t, r1, r1.tp(r2), r2.tp())
|
||||
checkTopology(t, r2, r1.tp(r2), r2.tp())
|
||||
r2.AddTestChannelConnection(r1)
|
||||
AddTestGossipConnection(r1, r2)
|
||||
sendPendingGossip(r1, r2)
|
||||
checkTopology(t, r1, r1.tp(r2), r2.tp(r1))
|
||||
checkTopology(t, r2, r1.tp(r2), r2.tp(r1))
|
||||
|
||||
// Currently, the connection from 2 to 3 is one-way only
|
||||
r2.AddTestChannelConnection(r3)
|
||||
sendPendingGossip(r1, r2, r3)
|
||||
checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp())
|
||||
checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp())
|
||||
// When r2 gossiped to r3, 1 was unreachable from r3 so it got removed from the
|
||||
// list of peers, but remains referenced in the connection from 1 to 3.
|
||||
checkTopology(t, r3, r2.tp(r1, r3), r3.tp())
|
||||
AddTestGossipConnection(r2, r3)
|
||||
flushAndCheckTopology(t, routers, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
|
||||
|
||||
// Add a connection from 3 to 1 and now r1 is reachable.
|
||||
r3.AddTestChannelConnection(r1)
|
||||
sendPendingGossip(r1, r2, r3)
|
||||
checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp(r1))
|
||||
checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp(r1))
|
||||
checkTopology(t, r3, r1.tp(), r2.tp(r1, r3), r3.tp(r1))
|
||||
|
||||
r1.AddTestChannelConnection(r3)
|
||||
sendPendingGossip(r1, r2, r3)
|
||||
checkTopology(t, r1, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1))
|
||||
checkTopology(t, r2, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1))
|
||||
checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1))
|
||||
AddTestGossipConnection(r3, r1)
|
||||
flushAndCheckTopology(t, routers, r1.tp(r2, r3), r2.tp(r1, r3), r3.tp(r1, r2))
|
||||
|
||||
// Drop the connection from 2 to 3
|
||||
r2.DeleteTestChannelConnection(r3)
|
||||
sendPendingGossip(r1, r2, r3)
|
||||
checkTopology(t, r1, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))
|
||||
checkTopology(t, r2, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))
|
||||
checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))
|
||||
r2.DeleteTestGossipConnection(r3)
|
||||
flushAndCheckTopology(t, routers, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1, r2))
|
||||
|
||||
// Drop the connection from 1 to 3
|
||||
r1.DeleteTestChannelConnection(r3)
|
||||
r1.DeleteTestGossipConnection(r3)
|
||||
sendPendingGossip(r1, r2, r3)
|
||||
checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1))
|
||||
checkTopology(t, r2, r1.tp(r2), r2.tp(r1))
|
||||
checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1, r2))
|
||||
checkTopology(t, r2, r1.tp(r2), r2.tp(r1), r3.tp(r1, r2))
|
||||
// r3 still thinks r1 has a connection to it
|
||||
checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1))
|
||||
checkTopology(t, r3, r1.tp(r2, r3), r2.tp(r1), r3.tp(r1, r2))
|
||||
|
||||
// On a timer, r3 will gossip to r1
|
||||
r3.SendAllGossip()
|
||||
sendPendingGossip(r1, r2, r3)
|
||||
checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1))
|
||||
checkTopology(t, r1, r1.tp(r2), r2.tp(r1), r3.tp(r1, r2))
|
||||
}
|
||||
|
||||
func TestGossipSurrogate(t *testing.T) {
|
||||
@@ -155,14 +159,10 @@ func TestGossipSurrogate(t *testing.T) {
|
||||
r1 := NewTestRouter("01:00:00:01:00:00")
|
||||
r2 := NewTestRouter("02:00:00:02:00:00")
|
||||
r3 := NewTestRouter("03:00:00:03:00:00")
|
||||
r1.AddTestChannelConnection(r2)
|
||||
r2.AddTestChannelConnection(r1)
|
||||
r3.AddTestChannelConnection(r2)
|
||||
r2.AddTestChannelConnection(r3)
|
||||
sendPendingGossip(r1, r2, r3)
|
||||
checkTopology(t, r1, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
|
||||
checkTopology(t, r2, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
|
||||
checkTopology(t, r3, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
|
||||
routers := []*Router{r1, r2, r3}
|
||||
AddTestGossipConnection(r1, r2)
|
||||
AddTestGossipConnection(r3, r2)
|
||||
flushAndCheckTopology(t, routers, r1.tp(r2), r2.tp(r1, r3), r3.tp(r2))
|
||||
|
||||
// create a gossiper at either end, but not the middle
|
||||
g1 := newTestGossiper()
|
||||
|
||||
Reference in new issue
Block a user