github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/network/p2p/builder/libp2pscaler_test.go (about)

     1  package p2pbuilder
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/libp2p/go-libp2p"
     7  	rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
     8  	"github.com/pbnjay/memory"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/onflow/flow-go/config"
    12  	p2pconfig "github.com/onflow/flow-go/network/p2p/config"
    13  	"github.com/onflow/flow-go/utils/unittest"
    14  )
    15  
    16  func TestAllowedMemoryScale(t *testing.T) {
    17  	m := memory.TotalMemory()
    18  	require.True(t, m > 0)
    19  
    20  	// scaling with factor of 1 should return the total memory.
    21  	s, err := allowedMemory(1)
    22  	require.NoError(t, err)
    23  	require.Equal(t, int64(m), s)
    24  
    25  	// scaling with factor of 0 should return an error.
    26  	_, err = allowedMemory(0)
    27  	require.Error(t, err)
    28  
    29  	// scaling with factor of -1 should return an error.
    30  	_, err = allowedMemory(-1)
    31  	require.Error(t, err)
    32  
    33  	// scaling with factor of 2 should return an error.
    34  	_, err = allowedMemory(2)
    35  	require.Error(t, err)
    36  
    37  	// scaling with factor of 0.5 should return half the total memory.
    38  	s, err = allowedMemory(0.5)
    39  	require.NoError(t, err)
    40  	require.Equal(t, int64(m/2), s)
    41  
    42  	// scaling with factor of 0.1 should return 10% of the total memory.
    43  	s, err = allowedMemory(0.1)
    44  	require.NoError(t, err)
    45  	require.Equal(t, int64(m/10), s)
    46  
    47  	// scaling with factor of 0.01 should return 1% of the total memory.
    48  	s, err = allowedMemory(0.01)
    49  	require.NoError(t, err)
    50  	require.Equal(t, int64(m/100), s)
    51  
    52  	// scaling with factor of 0.001 should return 0.1% of the total memory.
    53  	s, err = allowedMemory(0.001)
    54  	require.NoError(t, err)
    55  	require.Equal(t, int64(m/1000), s)
    56  
    57  	// scaling with factor of 0.0001 should return 0.01% of the total memory.
    58  	s, err = allowedMemory(0.0001)
    59  	require.NoError(t, err)
    60  	require.Equal(t, int64(m/10000), s)
    61  }
    62  
    63  func TestAllowedFileDescriptorsScale(t *testing.T) {
    64  	// getting actual file descriptor limit.
    65  	fd, err := getNumFDs()
    66  	require.NoError(t, err)
    67  	require.True(t, fd > 0)
    68  
    69  	// scaling with factor of 1 should return the total file descriptors.
    70  	s, err := allowedFileDescriptors(1)
    71  	require.NoError(t, err)
    72  	require.Equal(t, fd, s)
    73  
    74  	// scaling with factor of 0 should return an error.
    75  	_, err = allowedFileDescriptors(0)
    76  	require.Error(t, err)
    77  
    78  	// scaling with factor of -1 should return an error.
    79  	_, err = allowedFileDescriptors(-1)
    80  	require.Error(t, err)
    81  
    82  	// scaling with factor of 2 should return an error.
    83  	_, err = allowedFileDescriptors(2)
    84  	require.Error(t, err)
    85  
    86  	// scaling with factor of 0.5 should return half the total file descriptors.
    87  	s, err = allowedFileDescriptors(0.5)
    88  	require.NoError(t, err)
    89  	require.Equal(t, fd/2, s)
    90  
    91  	// scaling with factor of 0.1 should return 10% of the total file descriptors.
    92  	s, err = allowedFileDescriptors(0.1)
    93  	require.NoError(t, err)
    94  	require.Equal(t, fd/10, s)
    95  
    96  	// scaling with factor of 0.01 should return 1% of the total file descriptors.
    97  	s, err = allowedFileDescriptors(0.01)
    98  	require.NoError(t, err)
    99  	require.Equal(t, fd/100, s)
   100  
   101  	// scaling with factor of 0.001 should return 0.1% of the total file descriptors.
   102  	s, err = allowedFileDescriptors(0.001)
   103  	require.NoError(t, err)
   104  	require.Equal(t, fd/1000, s)
   105  
   106  	// scaling with factor of 0.0001 should return 0.01% of the total file descriptors.
   107  	s, err = allowedFileDescriptors(0.0001)
   108  	require.NoError(t, err)
   109  	require.Equal(t, fd/10000, s)
   110  }
   111  
   112  // TestApplyResourceLimitOverride tests the ApplyResourceLimitOverride function. It tests the following cases:
   113  // 1. The override limit is not set (i.e., left at zero), the original limit should be used.
   114  // 2. The override limit is set, the override limit should be used.
   115  func TestApplyResourceLimitOverride(t *testing.T) {
   116  	cfg, err := config.DefaultConfig()
   117  	require.NoError(t, err)
   118  
   119  	mem, err := allowedMemory(cfg.NetworkConfig.ResourceManager.MemoryLimitRatio)
   120  	require.NoError(t, err)
   121  
   122  	fd, err := allowedFileDescriptors(cfg.NetworkConfig.ResourceManager.FileDescriptorsRatio)
   123  	require.NoError(t, err)
   124  	limits := rcmgr.DefaultLimits
   125  	libp2p.SetDefaultServiceLimits(&limits)
   126  	scaled := limits.Scale(mem, fd)
   127  
   128  	systemOverride := p2pconfig.ResourceManagerOverrideLimit{
   129  		StreamsInbound:      0, // should not be overridden.
   130  		StreamsOutbound:     456,
   131  		ConnectionsInbound:  789,
   132  		ConnectionsOutbound: 0, // should not be overridden.
   133  		FD:                  4560,
   134  		Memory:              7890,
   135  	}
   136  
   137  	peerOverride := p2pconfig.ResourceManagerOverrideLimit{
   138  		StreamsInbound:      321,
   139  		StreamsOutbound:     0, // should not be overridden.
   140  		ConnectionsInbound:  987,
   141  		ConnectionsOutbound: 3210,
   142  		FD:                  0, // should not be overridden.
   143  		Memory:              9870,
   144  	}
   145  
   146  	partial := rcmgr.PartialLimitConfig{}
   147  	partial.System = ApplyResourceLimitOverride(unittest.Logger(), p2pconfig.ResourceScopeSystem, scaled.ToPartialLimitConfig().System, systemOverride)
   148  	partial.PeerDefault = ApplyResourceLimitOverride(unittest.Logger(), p2pconfig.ResourceScopePeer, scaled.ToPartialLimitConfig().PeerDefault, peerOverride)
   149  
   150  	final := partial.Build(scaled).ToPartialLimitConfig()
   151  	require.Equal(t, 456, int(final.System.StreamsOutbound))                                           // should be overridden.
   152  	require.Equal(t, 789, int(final.System.ConnsInbound))                                              // should be overridden.
   153  	require.Equal(t, 4560, int(final.System.FD))                                                       // should be overridden.
   154  	require.Equal(t, 7890, int(final.System.Memory))                                                   // should be overridden.
   155  	require.Equal(t, scaled.ToPartialLimitConfig().System.StreamsInbound, final.System.StreamsInbound) // should NOT be overridden.
   156  	require.Equal(t, scaled.ToPartialLimitConfig().System.ConnsOutbound, final.System.ConnsOutbound)   // should NOT be overridden.
   157  }
   158  
   159  // TestBuildLibp2pResourceManagerLimits tests the BuildLibp2pResourceManagerLimits function.
   160  // It creates a default configuration and an overridden configuration, and tests overriding the default configuration.
   161  func TestBuildLibp2pResourceManagerLimits(t *testing.T) {
   162  	cfg, err := config.DefaultConfig()
   163  	require.NoError(t, err)
   164  
   165  	// the default concrete limits is built from the default configuration.
   166  	defaultConcreteLimits, err := BuildLibp2pResourceManagerLimits(unittest.Logger(), &cfg.NetworkConfig.ResourceManager)
   167  	require.NoError(t, err)
   168  
   169  	// now the test creates random override configs for each scope, and re-build the concrete limits.
   170  	cfg.NetworkConfig.ResourceManager.Override.System = unittest.LibP2PResourceLimitOverrideFixture()
   171  	cfg.NetworkConfig.ResourceManager.Override.Transient = unittest.LibP2PResourceLimitOverrideFixture()
   172  	cfg.NetworkConfig.ResourceManager.Override.Protocol = unittest.LibP2PResourceLimitOverrideFixture()
   173  	cfg.NetworkConfig.ResourceManager.Override.Peer = unittest.LibP2PResourceLimitOverrideFixture()
   174  	cfg.NetworkConfig.ResourceManager.Override.PeerProtocol = unittest.LibP2PResourceLimitOverrideFixture()
   175  	overriddenConcreteLimits, err := BuildLibp2pResourceManagerLimits(unittest.Logger(), &cfg.NetworkConfig.ResourceManager)
   176  	require.NoError(t, err)
   177  
   178  	// this function will evaluate that the limits are override correctly on each scope using the override config.
   179  	requireEqual := func(t *testing.T, override p2pconfig.ResourceManagerOverrideLimit, actual rcmgr.ResourceLimits) {
   180  		require.Equal(t, override.StreamsInbound, int(actual.StreamsInbound))
   181  		require.Equal(t, override.StreamsOutbound, int(actual.StreamsOutbound))
   182  		require.Equal(t, override.ConnectionsInbound, int(actual.ConnsInbound))
   183  		require.Equal(t, override.ConnectionsOutbound, int(actual.ConnsOutbound))
   184  		require.Equal(t, override.FD, int(actual.FD))
   185  		require.Equal(t, override.Memory, int(actual.Memory))
   186  	}
   187  
   188  	op := overriddenConcreteLimits.ToPartialLimitConfig()
   189  	requireEqual(t, cfg.NetworkConfig.ResourceManager.Override.System, op.System)
   190  	requireEqual(t, cfg.NetworkConfig.ResourceManager.Override.Transient, op.Transient)
   191  	requireEqual(t, cfg.NetworkConfig.ResourceManager.Override.Protocol, op.ProtocolDefault)
   192  	requireEqual(t, cfg.NetworkConfig.ResourceManager.Override.Peer, op.PeerDefault)
   193  	requireEqual(t, cfg.NetworkConfig.ResourceManager.Override.PeerProtocol, op.ProtocolPeerDefault)
   194  
   195  	// this function will evaluate that the default limits (before overriding) are not equal to the overridden limits.
   196  	requireNotEqual := func(t *testing.T, a rcmgr.ResourceLimits, b rcmgr.ResourceLimits) {
   197  		require.NotEqual(t, a.StreamsInbound, b.StreamsInbound)
   198  		require.NotEqual(t, a.StreamsOutbound, b.StreamsOutbound)
   199  		require.NotEqual(t, a.ConnsInbound, b.ConnsInbound)
   200  		require.NotEqual(t, a.ConnsOutbound, b.ConnsOutbound)
   201  		require.NotEqual(t, a.FD, b.FD)
   202  		require.NotEqual(t, a.Memory, b.Memory)
   203  	}
   204  	dp := defaultConcreteLimits.ToPartialLimitConfig()
   205  	requireNotEqual(t, dp.System, op.System)
   206  	requireNotEqual(t, dp.Transient, op.Transient)
   207  	requireNotEqual(t, dp.ProtocolDefault, op.ProtocolDefault)
   208  	requireNotEqual(t, dp.PeerDefault, op.PeerDefault)
   209  	requireNotEqual(t, dp.ProtocolPeerDefault, op.ProtocolPeerDefault)
   210  }