-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add test peering and cache peering
- Loading branch information
Showing
5 changed files
with
254 additions
and
77 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
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,94 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"crypto/rand" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
chunker "github.com/ipfs/boxo/chunker" | ||
"github.com/ipfs/boxo/ipld/merkledag" | ||
"github.com/ipfs/boxo/ipld/unixfs/importer/balanced" | ||
uih "github.com/ipfs/boxo/ipld/unixfs/importer/helpers" | ||
"github.com/ipfs/go-cid" | ||
ic "github.com/libp2p/go-libp2p/core/crypto" | ||
"github.com/libp2p/go-libp2p/core/peer" | ||
"github.com/multiformats/go-multicodec" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func mustTestPeer(t *testing.T) (ic.PrivKey, peer.ID) { | ||
sk, _, err := ic.GenerateKeyPairWithReader(ic.Ed25519, 2048, rand.Reader) | ||
require.NoError(t, err) | ||
|
||
pid, err := peer.IDFromPrivateKey(sk) | ||
require.NoError(t, err) | ||
|
||
return sk, pid | ||
} | ||
|
||
func mustTestNode(t *testing.T, cfg Config) *Node { | ||
sk, _ := mustTestPeer(t) | ||
return mustTestNodeWithKey(t, cfg, sk) | ||
} | ||
|
||
func mustTestNodeWithKey(t *testing.T, cfg Config, sk ic.PrivKey) *Node { | ||
// Set necessary fields if not defined. | ||
if cfg.DataDir == "" { | ||
cfg.DataDir = t.TempDir() | ||
} | ||
if cfg.BlockstoreType == "" { | ||
cfg.BlockstoreType = "flatfs" | ||
} | ||
if cfg.DHTRouting == "" { | ||
cfg.DHTRouting = DHTOff | ||
} | ||
|
||
ctx := context.Background() | ||
cdns := newCachedDNS(dnsCacheRefreshInterval) | ||
|
||
t.Cleanup(func() { | ||
_ = cdns.Close() | ||
}) | ||
|
||
nd, err := Setup(ctx, cfg, sk, cdns) | ||
require.NoError(t, err) | ||
return nd | ||
} | ||
|
||
func mustTestServer(t *testing.T, cfg Config) (*httptest.Server, *Node) { | ||
nd := mustTestNode(t, cfg) | ||
|
||
handler, err := setupGatewayHandler(cfg, nd) | ||
if err != nil { | ||
require.NoError(t, err) | ||
} | ||
|
||
ts := httptest.NewServer(handler) | ||
return ts, nd | ||
} | ||
|
||
func mustAddFile(t *testing.T, gnd *Node, content []byte) cid.Cid { | ||
dsrv := merkledag.NewDAGService(gnd.bsrv) | ||
|
||
// Create a UnixFS graph from our file, parameters described here but can be visualized at https://dag.ipfs.tech/ | ||
ufsImportParams := uih.DagBuilderParams{ | ||
Maxlinks: uih.DefaultLinksPerBlock, // Default max of 174 links per block | ||
RawLeaves: true, // Leave the actual file bytes untouched instead of wrapping them in a dag-pb protobuf wrapper | ||
CidBuilder: cid.V1Builder{ // Use CIDv1 for all links | ||
Codec: uint64(multicodec.DagPb), | ||
MhType: uint64(multicodec.Sha2_256), // Use SHA2-256 as the hash function | ||
MhLength: -1, // Use the default hash length for the given hash function (in this case 256 bits) | ||
}, | ||
Dagserv: dsrv, | ||
NoCopy: false, | ||
} | ||
ufsBuilder, err := ufsImportParams.New(chunker.NewSizeSplitter(bytes.NewReader(content), chunker.DefaultBlockSize)) // Split the file up into fixed sized 256KiB chunks | ||
require.NoError(t, err) | ||
|
||
nd, err := balanced.Layout(ufsBuilder) // Arrange the graph with a balanced layout | ||
require.NoError(t, err) | ||
|
||
return nd.Cid() | ||
} |
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,150 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"net" | ||
"testing" | ||
"time" | ||
|
||
blocks "github.com/ipfs/go-block-format" | ||
ic "github.com/libp2p/go-libp2p/core/crypto" | ||
"github.com/libp2p/go-libp2p/core/network" | ||
"github.com/libp2p/go-libp2p/core/peer" | ||
"github.com/multiformats/go-multiaddr" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func mustFreePort(t *testing.T) (int, *net.TCPListener) { | ||
addr, err := net.ResolveTCPAddr("tcp", "localhost:0") | ||
require.NoError(t, err) | ||
|
||
l, err := net.ListenTCP("tcp", addr) | ||
require.NoError(t, err) | ||
|
||
return l.Addr().(*net.TCPAddr).Port, l | ||
} | ||
|
||
func mustFreePorts(t *testing.T, n int) []int { | ||
ports := make([]int, 0) | ||
for i := 0; i < n; i++ { | ||
port, listener := mustFreePort(t) | ||
defer listener.Close() | ||
ports = append(ports, port) | ||
} | ||
|
||
return ports | ||
} | ||
|
||
func mustListenAddrWithPort(t *testing.T, port int) multiaddr.Multiaddr { | ||
ma, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) | ||
require.NoError(t, err) | ||
return ma | ||
} | ||
|
||
// mustPeeredNodes creates a network of [Node]s with the given configuration. | ||
// The configuration contains as many elements as there are nodes. Each element | ||
// indicates to which other nodes it is connected. | ||
// | ||
// Example configuration: [][]int{ | ||
// {1, 2}, | ||
// {0}, | ||
// {0}, | ||
// } | ||
// | ||
// - Node 0 is connected to nodes 1 and 2. | ||
// - Node 1 is connected to node 0. | ||
// - Node 2 is connected to node 1. | ||
func mustPeeredNodes(t *testing.T, configuration [][]int, peeringCache bool) []*Node { | ||
n := len(configuration) | ||
|
||
// Generate ports, secrets keys, peer IDs and multiaddresses. | ||
ports := mustFreePorts(t, n) | ||
keys := make([]ic.PrivKey, n) | ||
pids := make([]peer.ID, n) | ||
mas := make([]multiaddr.Multiaddr, n) | ||
addrInfos := make([]peer.AddrInfo, n) | ||
|
||
for i := 0; i < n; i++ { | ||
keys[i], pids[i] = mustTestPeer(t) | ||
mas[i] = mustListenAddrWithPort(t, ports[i]) | ||
addrInfos[i] = peer.AddrInfo{ | ||
ID: pids[i], | ||
Addrs: []multiaddr.Multiaddr{mas[i]}, | ||
} | ||
} | ||
|
||
cfgs := make([]Config, n) | ||
nodes := make([]*Node, n) | ||
for i := 0; i < n; i++ { | ||
cfgs[i] = Config{ | ||
DHTRouting: DHTOff, | ||
RoutingV1Endpoints: []string{}, | ||
ListenAddrs: []string{mas[i].String()}, | ||
Peering: []peer.AddrInfo{}, | ||
PeeringCache: peeringCache, | ||
} | ||
|
||
for _, j := range configuration[i] { | ||
cfgs[i].Peering = append(cfgs[i].Peering, addrInfos[j]) | ||
} | ||
|
||
nodes[i] = mustTestNodeWithKey(t, cfgs[i], keys[i]) | ||
|
||
t.Log("Node", i, "Addresses", nodes[i].host.Addrs(), "Peering", cfgs[i].Peering) | ||
} | ||
|
||
require.Eventually(t, func() bool { | ||
for i, node := range nodes { | ||
for _, peer := range cfgs[i].Peering { | ||
if node.host.Network().Connectedness(peer.ID) != network.Connected { | ||
t.Log(node.host.Network().Connectedness(peer.ID)) | ||
return false | ||
} | ||
} | ||
} | ||
|
||
return true | ||
}, time.Second*30, time.Millisecond*100) | ||
|
||
return nodes | ||
} | ||
|
||
func TestPeering(t *testing.T) { | ||
_ = mustPeeredNodes(t, [][]int{ | ||
{1, 2}, | ||
{0, 2}, | ||
{0, 1}, | ||
}, false) | ||
} | ||
|
||
func TestPeeringCache(t *testing.T) { | ||
nodes := mustPeeredNodes(t, [][]int{ | ||
{1}, | ||
{0}, | ||
{}, | ||
}, true) | ||
|
||
bl := blocks.NewBlock([]byte(string("peering-cache-test"))) | ||
|
||
ctx, cancel := context.WithCancel(context.Background()) | ||
defer cancel() | ||
|
||
checkBitswap := func(i int, success bool) { | ||
ctx, cancel := context.WithTimeout(ctx, time.Second*5) | ||
defer cancel() | ||
|
||
_, err := nodes[i].bsrv.GetBlock(ctx, bl.Cid()) | ||
if success { | ||
require.NoError(t, err) | ||
} else { | ||
require.Error(t, err) | ||
} | ||
} | ||
|
||
err := nodes[0].bsrv.AddBlock(ctx, bl) | ||
require.NoError(t, err) | ||
|
||
checkBitswap(1, true) | ||
checkBitswap(2, false) | ||
} |