Topology gossip can be received on a connection before that connection has been marked as 'established'. If we do not include unestablished connections in topology gossip, then parts of the topology can be removed by gc, since they are deemed unreachable, which can cause subsequent incremental topology gossips to be rejected due to them containing references to peers that have been removed by the gc. Including unestablished connections in topology gossip requires: - removing the check for 'established' connections in the encoding of peers for topology gossip, - adding the 'established' flag to the internal representation of remote connections, - adding the 'established' flag to to encoding of connections in topology gossip, - treating the *addition* of a connection as an update to the local peer. The latter entails - bumping the peer version on connection addition (as well as on marking 'established' as previously), - bumping the peer version *unconditionally* on connection deletion (rather than only when the connection was 'established', as previously), - moving the initial sending of complete topology on the connection, and the broadcasting of a topology update containing the two peers at the ends of the connection, from the connection 'established' logic to the connection addition logic, - broadcasting just an topology update for the local peer when a connection gets marked as 'established', - broadcasting a topology update for the local peer *unconditionally* when a connection is removed (rather than only doing this when the connection was 'established', as previously).
114 lines
3.3 KiB
Go
114 lines
3.3 KiB
Go
// No mocks are tested by this file.
|
|
//
|
|
// It supplies some mock implementations to other unit tests, and is
|
|
// named "...test.go" so it is only compiled under `go test`.
|
|
|
|
package router
|
|
|
|
import (
|
|
wt "github.com/zettio/weave/testing"
|
|
"testing"
|
|
)
|
|
|
|
// Add to peers a connection from peers.ourself to p
|
|
func (peers *Peers) AddTestConnection(p *Peer) {
|
|
toPeer := NewPeer(p.Name, p.UID, 0)
|
|
peers.FetchWithDefault(toPeer) // Has side-effect of incrementing refcount
|
|
conn := newMockConnection(peers.ourself, toPeer)
|
|
peers.ourself.addConnection(conn)
|
|
peers.ourself.connectionEstablished(conn)
|
|
}
|
|
|
|
// Add to peers a connection from p1 to p2
|
|
func (peers *Peers) AddTestRemoteConnection(p1, p2 *Peer) {
|
|
fromName := p1.Name
|
|
fromPeer := NewPeer(fromName, p1.UID, 0)
|
|
fromPeer = peers.FetchWithDefault(fromPeer)
|
|
toName := p2.Name
|
|
toPeer := NewPeer(toName, p2.UID, 0)
|
|
toPeer = peers.FetchWithDefault(toPeer)
|
|
peers.ourself.addConnection(&RemoteConnection{fromPeer, toPeer, "", false})
|
|
}
|
|
|
|
func (peers *Peers) DeleteTestConnection(p *Peer) {
|
|
toName := p.Name
|
|
toPeer, _ := peers.Fetch(toName)
|
|
toPeer.DecrementLocalRefCount()
|
|
conn, _ := peers.ourself.ConnectionTo(toName)
|
|
peers.ourself.deleteConnection(conn)
|
|
}
|
|
|
|
// mockConnection used in testing is very similar to a
|
|
// RemoteConnection, without the RemoteTCPAddr(). We are making it a
|
|
// separate type in order to distinguish what is created by the test
|
|
// from what is created by the real code.
|
|
func newMockConnection(from, to *Peer) Connection {
|
|
type mockConnection struct{ RemoteConnection }
|
|
return &mockConnection{RemoteConnection{from, to, "", false}}
|
|
}
|
|
|
|
func checkEqualConns(t *testing.T, ourName PeerName, got, wanted map[PeerName]Connection) {
|
|
checkConns := make(map[PeerName]bool)
|
|
for _, conn := range wanted {
|
|
checkConns[conn.Remote().Name] = true
|
|
}
|
|
for _, conn := range got {
|
|
remoteName := conn.Remote().Name
|
|
if _, found := checkConns[remoteName]; found {
|
|
delete(checkConns, remoteName)
|
|
} else {
|
|
wt.Fatalf(t, "Unexpected connection from %s to %s", ourName, remoteName)
|
|
}
|
|
}
|
|
if len(checkConns) > 0 {
|
|
wt.Fatalf(t, "Expected connections not found: from %s to %v", ourName, checkConns)
|
|
}
|
|
}
|
|
|
|
// Get all the peers from a Peers in a slice
|
|
func (peers *Peers) allPeers() []*Peer {
|
|
res := make([]*Peer, 0)
|
|
for _, peer := range peers.table {
|
|
res = append(res, peer)
|
|
}
|
|
return res
|
|
}
|
|
|
|
func (peers *Peers) allPeersExcept(excludeName PeerName) []*Peer {
|
|
res := peers.allPeers()
|
|
for i, peer := range res {
|
|
if peer.Name == excludeName {
|
|
return append(res[:i], res[i+1:]...)
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
// Check that the peers slice matches the wanted peers
|
|
func checkPeerArray(t *testing.T, peers []*Peer, wantedPeers ...*Peer) {
|
|
checkTopologyPeers(t, false, peers, wantedPeers...)
|
|
}
|
|
|
|
// Check that the peers slice matches the wanted peers and optionally
|
|
// all of their connections
|
|
func checkTopologyPeers(t *testing.T, checkConns bool, peers []*Peer, wantedPeers ...*Peer) {
|
|
check := make(map[PeerName]*Peer)
|
|
for _, peer := range wantedPeers {
|
|
check[peer.Name] = peer
|
|
}
|
|
for _, peer := range peers {
|
|
name := peer.Name
|
|
if wantedPeer, found := check[name]; found {
|
|
if checkConns {
|
|
checkEqualConns(t, name, peer.connections, wantedPeer.connections)
|
|
}
|
|
delete(check, name)
|
|
} else {
|
|
wt.Fatalf(t, "Unexpected peer: %s", name)
|
|
}
|
|
}
|
|
if len(check) > 0 {
|
|
wt.Fatalf(t, "Expected peers not found: %v", check)
|
|
}
|
|
}
|