github.com/celestiaorg/celestia-node@v0.15.0-beta.1/share/p2p/shrexnd/exchange_test.go (about)

     1  package shrexnd
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/ipfs/go-datastore"
    10  	ds_sync "github.com/ipfs/go-datastore/sync"
    11  	libhost "github.com/libp2p/go-libp2p/core/host"
    12  	"github.com/libp2p/go-libp2p/core/network"
    13  	mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
    14  	"github.com/stretchr/testify/require"
    15  
    16  	"github.com/celestiaorg/celestia-node/share"
    17  	"github.com/celestiaorg/celestia-node/share/eds"
    18  	"github.com/celestiaorg/celestia-node/share/eds/edstest"
    19  	"github.com/celestiaorg/celestia-node/share/p2p"
    20  	"github.com/celestiaorg/celestia-node/share/sharetest"
    21  )
    22  
    23  func TestExchange_RequestND_NotFound(t *testing.T) {
    24  	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
    25  	t.Cleanup(cancel)
    26  	edsStore, client, server := makeExchange(t)
    27  	require.NoError(t, edsStore.Start(ctx))
    28  	require.NoError(t, server.Start(ctx))
    29  
    30  	t.Run("CAR_not_exist", func(t *testing.T) {
    31  		ctx, cancel := context.WithTimeout(ctx, time.Second)
    32  		t.Cleanup(cancel)
    33  
    34  		root := share.Root{}
    35  		namespace := sharetest.RandV0Namespace()
    36  		_, err := client.RequestND(ctx, &root, namespace, server.host.ID())
    37  		require.ErrorIs(t, err, p2p.ErrNotFound)
    38  	})
    39  
    40  	t.Run("ErrNamespaceNotFound", func(t *testing.T) {
    41  		ctx, cancel := context.WithTimeout(ctx, time.Second)
    42  		t.Cleanup(cancel)
    43  
    44  		eds := edstest.RandEDS(t, 4)
    45  		dah, err := share.NewRoot(eds)
    46  		require.NoError(t, err)
    47  		require.NoError(t, edsStore.Put(ctx, dah.Hash(), eds))
    48  
    49  		namespace := sharetest.RandV0Namespace()
    50  		emptyShares, err := client.RequestND(ctx, dah, namespace, server.host.ID())
    51  		require.NoError(t, err)
    52  		require.Empty(t, emptyShares.Flatten())
    53  	})
    54  }
    55  
    56  func TestExchange_RequestND(t *testing.T) {
    57  	t.Run("ND_concurrency_limit", func(t *testing.T) {
    58  		net, err := mocknet.FullMeshConnected(2)
    59  		require.NoError(t, err)
    60  
    61  		client, err := NewClient(DefaultParameters(), net.Hosts()[0])
    62  		require.NoError(t, err)
    63  		server, err := NewServer(DefaultParameters(), net.Hosts()[1], nil)
    64  		require.NoError(t, err)
    65  
    66  		require.NoError(t, server.Start(context.Background()))
    67  
    68  		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    69  		t.Cleanup(cancel)
    70  
    71  		rateLimit := 2
    72  		wg := sync.WaitGroup{}
    73  		wg.Add(rateLimit)
    74  
    75  		// mockHandler will block requests on server side until test is over
    76  		lock := make(chan struct{})
    77  		defer close(lock)
    78  		mockHandler := func(network.Stream) {
    79  			wg.Done()
    80  			select {
    81  			case <-lock:
    82  			case <-ctx.Done():
    83  				t.Fatal("timeout")
    84  			}
    85  		}
    86  		middleware := p2p.NewMiddleware(rateLimit)
    87  		server.host.SetStreamHandler(server.protocolID,
    88  			middleware.RateLimitHandler(mockHandler))
    89  
    90  		// take server concurrency slots with blocked requests
    91  		for i := 0; i < rateLimit; i++ {
    92  			go func(i int) {
    93  				client.RequestND(ctx, nil, sharetest.RandV0Namespace(), server.host.ID()) //nolint:errcheck
    94  			}(i)
    95  		}
    96  
    97  		// wait until all server slots are taken
    98  		wg.Wait()
    99  		_, err = client.RequestND(ctx, nil, sharetest.RandV0Namespace(), server.host.ID())
   100  		require.ErrorIs(t, err, p2p.ErrRateLimited)
   101  	})
   102  }
   103  
   104  func newStore(t *testing.T) *eds.Store {
   105  	t.Helper()
   106  
   107  	storeCfg := eds.DefaultParameters()
   108  	ds := ds_sync.MutexWrap(datastore.NewMapDatastore())
   109  	store, err := eds.NewStore(storeCfg, t.TempDir(), ds)
   110  	require.NoError(t, err)
   111  	return store
   112  }
   113  
   114  func createMocknet(t *testing.T, amount int) []libhost.Host {
   115  	t.Helper()
   116  
   117  	net, err := mocknet.FullMeshConnected(amount)
   118  	require.NoError(t, err)
   119  	// get host and peer
   120  	return net.Hosts()
   121  }
   122  
   123  func makeExchange(t *testing.T) (*eds.Store, *Client, *Server) {
   124  	t.Helper()
   125  	store := newStore(t)
   126  	hosts := createMocknet(t, 2)
   127  
   128  	client, err := NewClient(DefaultParameters(), hosts[0])
   129  	require.NoError(t, err)
   130  	server, err := NewServer(DefaultParameters(), hosts[1], store)
   131  	require.NoError(t, err)
   132  
   133  	return store, client, server
   134  }