mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 09:05:18 +00:00
1054 lines
28 KiB
Go
1054 lines
28 KiB
Go
package rcmgr
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"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/core/test"
|
|
|
|
"github.com/multiformats/go-multiaddr"
|
|
)
|
|
|
|
var dummyMA = multiaddr.StringCast("/ip4/1.2.3.4/tcp/1234")
|
|
|
|
func TestResourceManager(t *testing.T) {
|
|
peerA := peer.ID("A")
|
|
peerB := peer.ID("B")
|
|
protoA := protocol.ID("/A")
|
|
protoB := protocol.ID("/B")
|
|
svcA := "A.svc"
|
|
svcB := "B.svc"
|
|
nmgr, err := NewResourceManager(
|
|
NewFixedLimiter(ConcreteLimitConfig{
|
|
system: BaseLimit{
|
|
Memory: 16384,
|
|
StreamsInbound: 3,
|
|
StreamsOutbound: 3,
|
|
Streams: 6,
|
|
ConnsInbound: 3,
|
|
ConnsOutbound: 3,
|
|
Conns: 6,
|
|
FD: 2,
|
|
},
|
|
transient: BaseLimit{
|
|
Memory: 4096,
|
|
StreamsInbound: 1,
|
|
StreamsOutbound: 1,
|
|
Streams: 2,
|
|
ConnsInbound: 1,
|
|
ConnsOutbound: 1,
|
|
Conns: 2,
|
|
FD: 1,
|
|
},
|
|
serviceDefault: BaseLimit{
|
|
Memory: 4096,
|
|
StreamsInbound: 1,
|
|
StreamsOutbound: 1,
|
|
Streams: 2,
|
|
ConnsInbound: 1,
|
|
ConnsOutbound: 1,
|
|
Conns: 2,
|
|
FD: 1,
|
|
},
|
|
servicePeerDefault: BaseLimit{
|
|
Memory: 4096,
|
|
StreamsInbound: 5,
|
|
StreamsOutbound: 5,
|
|
Streams: 10,
|
|
},
|
|
service: map[string]BaseLimit{
|
|
svcA: {
|
|
Memory: 8192,
|
|
StreamsInbound: 2,
|
|
StreamsOutbound: 2,
|
|
Streams: 4,
|
|
ConnsInbound: 2,
|
|
ConnsOutbound: 2,
|
|
Conns: 4,
|
|
FD: 1,
|
|
},
|
|
svcB: {
|
|
Memory: 8192,
|
|
StreamsInbound: 2,
|
|
StreamsOutbound: 2,
|
|
Streams: 4,
|
|
ConnsInbound: 2,
|
|
ConnsOutbound: 2,
|
|
Conns: 4,
|
|
FD: 1,
|
|
},
|
|
},
|
|
servicePeer: map[string]BaseLimit{
|
|
svcB: {
|
|
Memory: 8192,
|
|
StreamsInbound: 1,
|
|
StreamsOutbound: 1,
|
|
Streams: 2,
|
|
},
|
|
},
|
|
protocolDefault: BaseLimit{
|
|
Memory: 4096,
|
|
StreamsInbound: 1,
|
|
StreamsOutbound: 1,
|
|
Streams: 2,
|
|
},
|
|
protocol: map[protocol.ID]BaseLimit{
|
|
protoA: {
|
|
Memory: 8192,
|
|
StreamsInbound: 2,
|
|
StreamsOutbound: 2,
|
|
Streams: 2,
|
|
},
|
|
},
|
|
protocolPeer: map[protocol.ID]BaseLimit{
|
|
protoB: {
|
|
Memory: 8192,
|
|
StreamsInbound: 1,
|
|
StreamsOutbound: 1,
|
|
Streams: 2,
|
|
},
|
|
},
|
|
peerDefault: BaseLimit{
|
|
Memory: 4096,
|
|
StreamsInbound: 1,
|
|
StreamsOutbound: 1,
|
|
Streams: 2,
|
|
ConnsInbound: 1,
|
|
ConnsOutbound: 1,
|
|
Conns: 2,
|
|
FD: 1,
|
|
},
|
|
protocolPeerDefault: BaseLimit{
|
|
Memory: 4096,
|
|
StreamsInbound: 5,
|
|
StreamsOutbound: 5,
|
|
Streams: 10,
|
|
},
|
|
peer: map[peer.ID]BaseLimit{
|
|
peerA: {
|
|
Memory: 8192,
|
|
StreamsInbound: 2,
|
|
StreamsOutbound: 2,
|
|
Streams: 4,
|
|
ConnsInbound: 2,
|
|
ConnsOutbound: 2,
|
|
Conns: 4,
|
|
FD: 1,
|
|
},
|
|
},
|
|
conn: BaseLimit{
|
|
Memory: 4096,
|
|
ConnsInbound: 1,
|
|
ConnsOutbound: 1,
|
|
Conns: 1,
|
|
FD: 1,
|
|
},
|
|
stream: BaseLimit{
|
|
Memory: 4096,
|
|
StreamsInbound: 1,
|
|
StreamsOutbound: 1,
|
|
Streams: 1,
|
|
},
|
|
}),
|
|
)
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
mgr := nmgr.(*resourceManager)
|
|
defer mgr.Close()
|
|
|
|
checkRefCnt := func(s *resourceScope, count int) {
|
|
t.Helper()
|
|
if refCnt := s.refCnt; refCnt != count {
|
|
t.Fatalf("expected refCnt of %d, got %d", count, refCnt)
|
|
}
|
|
}
|
|
checkSystem := func(check func(s *resourceScope)) {
|
|
if err := mgr.ViewSystem(func(s network.ResourceScope) error {
|
|
check(s.(*systemScope).resourceScope)
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
checkTransient := func(check func(s *resourceScope)) {
|
|
if err := mgr.ViewTransient(func(s network.ResourceScope) error {
|
|
check(s.(*transientScope).resourceScope)
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
checkService := func(svc string, check func(s *resourceScope)) {
|
|
if err := mgr.ViewService(svc, func(s network.ServiceScope) error {
|
|
check(s.(*serviceScope).resourceScope)
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
checkProtocol := func(p protocol.ID, check func(s *resourceScope)) {
|
|
if err := mgr.ViewProtocol(p, func(s network.ProtocolScope) error {
|
|
check(s.(*protocolScope).resourceScope)
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
checkPeer := func(p peer.ID, check func(s *resourceScope)) {
|
|
if err := mgr.ViewPeer(p, func(s network.PeerScope) error {
|
|
check(s.(*peerScope).resourceScope)
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// open an inbound connection, using an fd
|
|
conn, err := mgr.OpenConnection(network.DirInbound, true, dummyMA)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1})
|
|
})
|
|
|
|
// the connection is transient, we shouldn't be able to open a second one
|
|
if _, err := mgr.OpenConnection(network.DirInbound, true, dummyMA); err == nil {
|
|
t.Fatal("expected OpenConnection to fail")
|
|
}
|
|
if _, err := mgr.OpenConnection(network.DirInbound, false, dummyMA); err == nil {
|
|
t.Fatal("expected OpenConnection to fail")
|
|
}
|
|
|
|
// close it to check resources are reclaimed
|
|
conn.Done()
|
|
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// open another inbound connection, using an fd
|
|
conn1, err := mgr.OpenConnection(network.DirInbound, true, dummyMA)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1})
|
|
})
|
|
|
|
// check nility of current peer scope
|
|
if conn1.PeerScope() != nil {
|
|
t.Fatal("peer scope should be nil")
|
|
}
|
|
|
|
// attach to a peer
|
|
if err := conn1.SetPeer(peerA); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 4)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// we should be able to open a second transient connection now
|
|
conn2, err := mgr.OpenConnection(network.DirInbound, true, dummyMA)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1})
|
|
})
|
|
|
|
// but we shouldn't be able to attach it to the same peer due to the fd limit
|
|
if err := conn2.SetPeer(peerA); err == nil {
|
|
t.Fatal("expected SetPeer to fail")
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 2})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 1})
|
|
})
|
|
|
|
// close it and reopen without using an FD -- we should be able to attach now
|
|
conn2.Done()
|
|
|
|
conn2, err = mgr.OpenConnection(network.DirInbound, false, dummyMA)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 1, NumFD: 0})
|
|
})
|
|
|
|
if err := conn2.SetPeer(peerA); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// open a stream
|
|
stream, err := mgr.OpenStream(peerA, network.DirInbound)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 4)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 6)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
// the stream is transient we shouldn't be able to open a second one
|
|
if _, err := mgr.OpenStream(peerA, network.DirInbound); err == nil {
|
|
t.Fatal("expected OpenStream to fail")
|
|
}
|
|
|
|
// close the stream to check resource reclamation
|
|
stream.Done()
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// open another stream, but this time attach it to a protocol
|
|
stream1, err := mgr.OpenStream(peerA, network.DirInbound)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 4)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 6)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
// check nility of protocol scope
|
|
if stream1.ProtocolScope() != nil {
|
|
t.Fatal("protocol scope should be nil")
|
|
}
|
|
|
|
if err := stream1.SetProtocol(protoA); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 4)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 7)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// and now we should be able to open another stream and attach it to the protocol
|
|
stream2, err := mgr.OpenStream(peerA, network.DirInbound)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 8)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
if err := stream2.SetProtocol(protoA); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 8)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// open a 3rd stream, and try to attach it to the same protocol
|
|
stream3, err := mgr.OpenStream(peerB, network.DirInbound)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkPeer(peerB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 10)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
if err := stream3.SetProtocol(protoA); err == nil {
|
|
t.Fatal("expected SetProtocol to fail")
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkPeer(peerB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 10)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
// but we should be able to set to another protocol
|
|
if err := stream3.SetProtocol(protoB); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkPeer(peerB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkProtocol(protoB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 11)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// check nility of current service scope
|
|
if stream1.ServiceScope() != nil {
|
|
t.Fatal("service scope should be nil")
|
|
}
|
|
|
|
// we should be able to attach stream1 and stream2 to svcA, but stream3 should fail due to limit
|
|
if err := stream1.SetService(svcA); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkPeer(peerB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkService(svcA, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkProtocol(protoB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 12)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
if err := stream2.SetService(svcA); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkPeer(peerB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkService(svcA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkProtocol(protoB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 12)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
if err := stream3.SetService(svcA); err == nil {
|
|
t.Fatal("expected SetService to fail")
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkPeer(peerB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkService(svcA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkProtocol(protoB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 12)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 3, NumConnsInbound: 2, NumFD: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// and now let's reclaim our resources to make sure we can gc unused peer and proto scopes
|
|
// but first check internal refs
|
|
mgr.mx.Lock()
|
|
_, okProtoA := mgr.proto[protoA]
|
|
_, okProtoB := mgr.proto[protoB]
|
|
_, okPeerA := mgr.peer[peerA]
|
|
_, okPeerB := mgr.peer[peerB]
|
|
mgr.mx.Unlock()
|
|
|
|
if !okProtoA {
|
|
t.Fatal("protocol scope is not stored")
|
|
}
|
|
if !okProtoB {
|
|
t.Fatal("protocol scope is not stored")
|
|
}
|
|
if !okPeerA {
|
|
t.Fatal("peer scope is not stored")
|
|
}
|
|
if !okPeerB {
|
|
t.Fatal("peer scope is not stored")
|
|
}
|
|
|
|
// ok, reclaim
|
|
stream1.Done()
|
|
stream2.Done()
|
|
stream3.Done()
|
|
conn1.Done()
|
|
conn2.Done()
|
|
|
|
// check everything released
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkPeer(peerB, func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkService(svcA, func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkProtocol(protoB, func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 7)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
mgr.gc()
|
|
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
mgr.mx.Lock()
|
|
lenProto := len(mgr.proto)
|
|
lenPeer := len(mgr.peer)
|
|
mgr.mx.Unlock()
|
|
|
|
if lenProto != 0 {
|
|
t.Fatal("protocols were not gc'ed")
|
|
}
|
|
if lenPeer != 0 {
|
|
t.Fatal("perrs were not gc'ed")
|
|
}
|
|
|
|
// check that per protocol peer scopes work as intended
|
|
stream1, err = mgr.OpenStream(peerA, network.DirInbound)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 5)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
if err := stream1.SetProtocol(protoB); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkProtocol(protoB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 6)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
stream2, err = mgr.OpenStream(peerA, network.DirInbound)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 7)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
if err := stream2.SetProtocol(protoB); err == nil {
|
|
t.Fatal("expected SetProtocol to fail")
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 7)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkProtocol(protoB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
stream1.Done()
|
|
stream2.Done()
|
|
|
|
// check that per service peer scopes work as intended
|
|
stream1, err = mgr.OpenStream(peerA, network.DirInbound)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 6)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
if err := stream1.SetProtocol(protoA); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 7)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
stream2, err = mgr.OpenStream(peerA, network.DirInbound)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 8)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
|
|
if err := stream2.SetProtocol(protoA); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 8)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
if err := stream1.SetService(svcB); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
checkPeer(peerA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkService(svcB, func(s *resourceScope) {
|
|
checkRefCnt(s, 2)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 1})
|
|
})
|
|
checkProtocol(protoA, func(s *resourceScope) {
|
|
checkRefCnt(s, 3)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 9)
|
|
checkResources(t, &s.rc, network.ScopeStat{NumStreamsInbound: 2})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
// now we should fail to set the service for stream2 to svcB because of the service peer limit
|
|
if err := stream2.SetService(svcB); err == nil {
|
|
t.Fatal("expected SetService to fail")
|
|
}
|
|
|
|
// now release resources and check interior gc of per service peer scopes
|
|
stream1.Done()
|
|
stream2.Done()
|
|
|
|
mgr.gc()
|
|
|
|
checkSystem(func(s *resourceScope) {
|
|
checkRefCnt(s, 4)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
checkTransient(func(s *resourceScope) {
|
|
checkRefCnt(s, 1)
|
|
checkResources(t, &s.rc, network.ScopeStat{})
|
|
})
|
|
|
|
mgr.mx.Lock()
|
|
lenProto = len(mgr.proto)
|
|
lenPeer = len(mgr.peer)
|
|
mgr.mx.Unlock()
|
|
|
|
svc := mgr.svc[svcB]
|
|
svc.Lock()
|
|
lenSvcPeer := len(svc.peers)
|
|
svc.Unlock()
|
|
|
|
if lenProto != 0 {
|
|
t.Fatal("protocols were not gc'ed")
|
|
}
|
|
if lenPeer != 0 {
|
|
t.Fatal("peers were not gc'ed")
|
|
}
|
|
if lenSvcPeer != 0 {
|
|
t.Fatal("service peers were not gc'ed")
|
|
}
|
|
|
|
}
|
|
|
|
func TestResourceManagerWithAllowlist(t *testing.T) {
|
|
peerA := test.RandPeerIDFatal(t)
|
|
|
|
limits := DefaultLimits.AutoScale()
|
|
limits.system.Conns = 0
|
|
limits.transient.Conns = 0
|
|
|
|
baseLimit := BaseLimit{
|
|
Conns: 2,
|
|
ConnsInbound: 2,
|
|
ConnsOutbound: 1,
|
|
}
|
|
baseLimit.Apply(limits.allowlistedSystem)
|
|
limits.allowlistedSystem = baseLimit
|
|
|
|
baseLimit = BaseLimit{
|
|
Conns: 1,
|
|
ConnsInbound: 1,
|
|
ConnsOutbound: 1,
|
|
}
|
|
baseLimit.Apply(limits.allowlistedTransient)
|
|
limits.allowlistedTransient = baseLimit
|
|
|
|
rcmgr, err := NewResourceManager(NewFixedLimiter(limits), WithAllowlistedMultiaddrs([]multiaddr.Multiaddr{
|
|
multiaddr.StringCast("/ip4/1.2.3.4"),
|
|
multiaddr.StringCast("/ip4/4.3.2.1/p2p/" + peerA.String()),
|
|
}))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer rcmgr.Close()
|
|
|
|
ableToGetAllowlist := GetAllowlist(rcmgr)
|
|
if ableToGetAllowlist == nil {
|
|
t.Fatal("Expected to be able to get the allowlist")
|
|
}
|
|
|
|
// A connection comes in from a non-allowlisted ip address
|
|
_, err = rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/1.2.3.5"))
|
|
if err == nil {
|
|
t.Fatalf("Expected this to fail. err=%v", err)
|
|
}
|
|
|
|
// A connection comes in from an allowlisted ip address
|
|
connScope, err := rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/1.2.3.4"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = connScope.SetPeer(test.RandPeerIDFatal(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// A connection comes in that looks like it should be allowlisted, but then has the wrong peer id.
|
|
connScope, err = rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/4.3.2.1"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = connScope.SetPeer(test.RandPeerIDFatal(t))
|
|
if err == nil {
|
|
t.Fatalf("Expected this to fail. err=%v", err)
|
|
}
|
|
|
|
// A connection comes in that looks like it should be allowlisted, and it has the allowlisted peer id
|
|
connScope, err = rcmgr.OpenConnection(network.DirInbound, true, multiaddr.StringCast("/ip4/4.3.2.1"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
err = connScope.SetPeer(peerA)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|