-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests: add comprehensive end-to-end tests for connection gating (#2200)
* tests: add integration tests for gating of outgoing connections * tests: integrate connection gating tests into the transport tests * disable gating tests with race detector
- Loading branch information
1 parent
22a70b4
commit 8a3fafd
Showing
4 changed files
with
353 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
package transport_integration | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
"time" | ||
|
||
"github.com/libp2p/go-libp2p/core/network" | ||
"github.com/libp2p/go-libp2p/core/peer" | ||
"github.com/libp2p/go-libp2p/core/protocol" | ||
"github.com/libp2p/go-libp2p/p2p/net/swarm" | ||
|
||
"github.com/libp2p/go-libp2p-testing/race" | ||
|
||
"github.com/golang/mock/gomock" | ||
ma "github.com/multiformats/go-multiaddr" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
//go:generate go run github.com/golang/mock/mockgen -package transport_integration -destination mock_connection_gater_test.go github.com/libp2p/go-libp2p/core/connmgr ConnectionGater | ||
|
||
func stripCertHash(addr ma.Multiaddr) ma.Multiaddr { | ||
for { | ||
if _, err := addr.ValueForProtocol(ma.P_CERTHASH); err != nil { | ||
break | ||
} | ||
addr, _ = ma.SplitLast(addr) | ||
} | ||
return addr | ||
} | ||
|
||
func TestInterceptPeerDial(t *testing.T) { | ||
if race.WithRace() { | ||
t.Skip("The upgrader spawns a new Go routine, which leads to race conditions when using GoMock.") | ||
} | ||
for _, tc := range transportsToTest { | ||
t.Run(tc.Name, func(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
connGater := NewMockConnectionGater(ctrl) | ||
|
||
h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, ConnGater: connGater}) | ||
h2 := tc.HostGenerator(t, TransportTestCaseOpts{}) | ||
require.Len(t, h2.Addrs(), 1) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
defer cancel() | ||
connGater.EXPECT().InterceptPeerDial(h2.ID()) | ||
require.ErrorIs(t, h1.Connect(ctx, peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}), swarm.ErrGaterDisallowedConnection) | ||
}) | ||
} | ||
} | ||
|
||
func TestInterceptAddrDial(t *testing.T) { | ||
if race.WithRace() { | ||
t.Skip("The upgrader spawns a new Go routine, which leads to race conditions when using GoMock.") | ||
} | ||
for _, tc := range transportsToTest { | ||
t.Run(tc.Name, func(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
connGater := NewMockConnectionGater(ctrl) | ||
|
||
h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, ConnGater: connGater}) | ||
h2 := tc.HostGenerator(t, TransportTestCaseOpts{}) | ||
require.Len(t, h2.Addrs(), 1) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
defer cancel() | ||
gomock.InOrder( | ||
connGater.EXPECT().InterceptPeerDial(h2.ID()).Return(true), | ||
connGater.EXPECT().InterceptAddrDial(h2.ID(), h2.Addrs()[0]), | ||
) | ||
require.ErrorIs(t, h1.Connect(ctx, peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}), swarm.ErrNoGoodAddresses) | ||
}) | ||
} | ||
} | ||
|
||
func TestInterceptSecuredOutgoing(t *testing.T) { | ||
if race.WithRace() { | ||
t.Skip("The upgrader spawns a new Go routine, which leads to race conditions when using GoMock.") | ||
} | ||
for _, tc := range transportsToTest { | ||
t.Run(tc.Name, func(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
connGater := NewMockConnectionGater(ctrl) | ||
|
||
h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, ConnGater: connGater}) | ||
h2 := tc.HostGenerator(t, TransportTestCaseOpts{}) | ||
require.Len(t, h2.Addrs(), 1) | ||
require.Len(t, h2.Addrs(), 1) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
defer cancel() | ||
gomock.InOrder( | ||
connGater.EXPECT().InterceptPeerDial(h2.ID()).Return(true), | ||
connGater.EXPECT().InterceptAddrDial(h2.ID(), gomock.Any()).Return(true), | ||
connGater.EXPECT().InterceptSecured(network.DirOutbound, h2.ID(), gomock.Any()).Do(func(_ network.Direction, _ peer.ID, addrs network.ConnMultiaddrs) { | ||
// remove the certhash component from WebTransport addresses | ||
require.Equal(t, stripCertHash(h2.Addrs()[0]).String(), addrs.RemoteMultiaddr().String()) | ||
}), | ||
) | ||
err := h1.Connect(ctx, peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) | ||
require.Error(t, err) | ||
require.NotErrorIs(t, err, context.DeadlineExceeded) | ||
}) | ||
} | ||
} | ||
|
||
func TestInterceptUpgradedOutgoing(t *testing.T) { | ||
if race.WithRace() { | ||
t.Skip("The upgrader spawns a new Go routine, which leads to race conditions when using GoMock.") | ||
} | ||
for _, tc := range transportsToTest { | ||
t.Run(tc.Name, func(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
connGater := NewMockConnectionGater(ctrl) | ||
|
||
h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true, ConnGater: connGater}) | ||
h2 := tc.HostGenerator(t, TransportTestCaseOpts{}) | ||
require.Len(t, h2.Addrs(), 1) | ||
require.Len(t, h2.Addrs(), 1) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
defer cancel() | ||
gomock.InOrder( | ||
connGater.EXPECT().InterceptPeerDial(h2.ID()).Return(true), | ||
connGater.EXPECT().InterceptAddrDial(h2.ID(), gomock.Any()).Return(true), | ||
connGater.EXPECT().InterceptSecured(network.DirOutbound, h2.ID(), gomock.Any()).Return(true), | ||
connGater.EXPECT().InterceptUpgraded(gomock.Any()).Do(func(c network.Conn) { | ||
// remove the certhash component from WebTransport addresses | ||
require.Equal(t, stripCertHash(h2.Addrs()[0]), c.RemoteMultiaddr()) | ||
require.Equal(t, h1.ID(), c.LocalPeer()) | ||
require.Equal(t, h2.ID(), c.RemotePeer()) | ||
})) | ||
err := h1.Connect(ctx, peer.AddrInfo{ID: h2.ID(), Addrs: h2.Addrs()}) | ||
require.Error(t, err) | ||
require.NotErrorIs(t, err, context.DeadlineExceeded) | ||
}) | ||
} | ||
} | ||
|
||
func TestInterceptAccept(t *testing.T) { | ||
if race.WithRace() { | ||
t.Skip("The upgrader spawns a new Go routine, which leads to race conditions when using GoMock.") | ||
} | ||
for _, tc := range transportsToTest { | ||
t.Run(tc.Name, func(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
connGater := NewMockConnectionGater(ctrl) | ||
|
||
h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) | ||
h2 := tc.HostGenerator(t, TransportTestCaseOpts{ConnGater: connGater}) | ||
require.Len(t, h2.Addrs(), 1) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
defer cancel() | ||
// The basic host dials the first connection. | ||
connGater.EXPECT().InterceptAccept(gomock.Any()).Do(func(addrs network.ConnMultiaddrs) { | ||
// remove the certhash component from WebTransport addresses | ||
require.Equal(t, stripCertHash(h2.Addrs()[0]), addrs.LocalMultiaddr()) | ||
}) | ||
h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), time.Hour) | ||
_, err := h1.NewStream(ctx, h2.ID(), protocol.TestingID) | ||
require.Error(t, err) | ||
require.NotErrorIs(t, err, context.DeadlineExceeded) | ||
}) | ||
} | ||
} | ||
|
||
func TestInterceptSecuredIncoming(t *testing.T) { | ||
if race.WithRace() { | ||
t.Skip("The upgrader spawns a new Go routine, which leads to race conditions when using GoMock.") | ||
} | ||
for _, tc := range transportsToTest { | ||
t.Run(tc.Name, func(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
connGater := NewMockConnectionGater(ctrl) | ||
|
||
h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) | ||
h2 := tc.HostGenerator(t, TransportTestCaseOpts{ConnGater: connGater}) | ||
require.Len(t, h2.Addrs(), 1) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
defer cancel() | ||
gomock.InOrder( | ||
connGater.EXPECT().InterceptAccept(gomock.Any()).Return(true), | ||
connGater.EXPECT().InterceptSecured(network.DirInbound, h1.ID(), gomock.Any()).Do(func(_ network.Direction, _ peer.ID, addrs network.ConnMultiaddrs) { | ||
// remove the certhash component from WebTransport addresses | ||
require.Equal(t, stripCertHash(h2.Addrs()[0]), addrs.LocalMultiaddr()) | ||
}), | ||
) | ||
h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), time.Hour) | ||
_, err := h1.NewStream(ctx, h2.ID(), protocol.TestingID) | ||
require.Error(t, err) | ||
require.NotErrorIs(t, err, context.DeadlineExceeded) | ||
}) | ||
} | ||
} | ||
|
||
func TestInterceptUpgradedIncoming(t *testing.T) { | ||
if race.WithRace() { | ||
t.Skip("The upgrader spawns a new Go routine, which leads to race conditions when using GoMock.") | ||
} | ||
for _, tc := range transportsToTest { | ||
t.Run(tc.Name, func(t *testing.T) { | ||
ctrl := gomock.NewController(t) | ||
defer ctrl.Finish() | ||
connGater := NewMockConnectionGater(ctrl) | ||
|
||
h1 := tc.HostGenerator(t, TransportTestCaseOpts{NoListen: true}) | ||
h2 := tc.HostGenerator(t, TransportTestCaseOpts{ConnGater: connGater}) | ||
require.Len(t, h2.Addrs(), 1) | ||
|
||
ctx, cancel := context.WithTimeout(context.Background(), time.Second) | ||
defer cancel() | ||
gomock.InOrder( | ||
connGater.EXPECT().InterceptAccept(gomock.Any()).Return(true), | ||
connGater.EXPECT().InterceptSecured(network.DirInbound, h1.ID(), gomock.Any()).Return(true), | ||
connGater.EXPECT().InterceptUpgraded(gomock.Any()).Do(func(c network.Conn) { | ||
// remove the certhash component from WebTransport addresses | ||
require.Equal(t, stripCertHash(h2.Addrs()[0]), c.LocalMultiaddr()) | ||
require.Equal(t, h1.ID(), c.RemotePeer()) | ||
require.Equal(t, h2.ID(), c.LocalPeer()) | ||
}), | ||
) | ||
h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), time.Hour) | ||
_, err := h1.NewStream(ctx, h2.ID(), protocol.TestingID) | ||
require.Error(t, err) | ||
require.NotErrorIs(t, err, context.DeadlineExceeded) | ||
}) | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters