github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/p2p/resolve_ref_test.go (about)

     1  package p2p
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  	"testing"
     8  
     9  	peer "github.com/libp2p/go-libp2p-core/peer"
    10  	"github.com/qri-io/qri/auth/key"
    11  	"github.com/qri-io/qri/dscache"
    12  	"github.com/qri-io/qri/dsref"
    13  	dsrefspec "github.com/qri-io/qri/dsref/spec"
    14  	"github.com/qri-io/qri/event"
    15  	"github.com/qri-io/qri/logbook/oplog"
    16  	p2ptest "github.com/qri-io/qri/p2p/test"
    17  	"github.com/qri-io/qri/profile"
    18  )
    19  
    20  func TestResolveRef(t *testing.T) {
    21  	ctx := context.Background()
    22  	// create a network of connected nodes
    23  	factory := p2ptest.NewTestNodeFactory(NewTestableQriNode)
    24  	testPeers, err := p2ptest.NewTestDirNetwork(ctx, factory)
    25  	if err != nil {
    26  		t.Fatalf("error creating network: %s", err.Error())
    27  	}
    28  
    29  	// Convert from test nodes to non-test nodes.
    30  	nodes := make([]*QriNode, len(testPeers))
    31  	numNodes := len(nodes)
    32  	for i, node := range testPeers {
    33  		nodes[i] = node.(*QriNode)
    34  		// closing the discovery process prevents situations where another peer finds
    35  		// our node in the wild and attempts to connect to it while we are trying
    36  		// to connect to that node at the same time. This causes a dial failure.
    37  		nodes[i].Discovery.Close()
    38  	}
    39  	defer func() {
    40  		for _, node := range nodes {
    41  			node.GoOffline()
    42  		}
    43  	}()
    44  
    45  	nodeWithRef := nodes[numNodes-1]
    46  
    47  	// set up bus & listener for `ETP2PQriPeerConnected` events
    48  	// this is how we will be sure that all the nodes have exchanged qri profiles
    49  	// before moving forward
    50  	bus := event.NewBus(ctx)
    51  	qriPeerConnWaitCh := make(chan struct{})
    52  	connectedPeersMu := sync.Mutex{}
    53  	connectedPeers := peer.IDSlice{}
    54  
    55  	node := &QriNode{}
    56  
    57  	watchP2PQriEvents := func(_ context.Context, e event.Event) error {
    58  		pro, ok := e.Payload.(*profile.Profile)
    59  		if !ok {
    60  			t.Error("payload for event.ETP2PQriPeerConnected not a *profile.Profile as expected")
    61  			return fmt.Errorf("payload for event.ETP2PQriPeerConnected not a *profile.Profile as expected")
    62  		}
    63  		if pro == nil {
    64  			t.Error("error: event payload is a nil profile")
    65  			return fmt.Errorf("err: event payload is a nil profile")
    66  		}
    67  		pid := pro.PeerIDs[0]
    68  		expectedPeer := false
    69  		for _, peer := range testPeers {
    70  			if pid == peer.Host().ID() {
    71  				expectedPeer = true
    72  				break
    73  			}
    74  		}
    75  		if !expectedPeer {
    76  			t.Logf("peer %q event occurred, but not an expected peer", pid)
    77  			return nil
    78  		}
    79  		if e.Type == event.ETP2PQriPeerConnected {
    80  			connectedPeersMu.Lock()
    81  			defer connectedPeersMu.Unlock()
    82  			t.Log("Qri Peer Connected: ", pid)
    83  			for _, id := range connectedPeers {
    84  				if pid == id {
    85  					t.Logf("peer %q has already been connected", pid)
    86  					return nil
    87  				}
    88  			}
    89  			connectedPeers = append(connectedPeers, pid)
    90  			if len(connectedPeers) == numNodes {
    91  				close(qriPeerConnWaitCh)
    92  			}
    93  		}
    94  		return nil
    95  	}
    96  	bus.SubscribeTypes(watchP2PQriEvents, event.ETP2PQriPeerConnected)
    97  
    98  	// create a new, disconnected node
    99  	testnode, err := p2ptest.NewNodeWithBus(ctx, factory, bus)
   100  	if err != nil {
   101  		t.Fatal(err)
   102  	}
   103  	node = testnode.(*QriNode)
   104  	// closing the discovery process prevents situations where another peer finds
   105  	// our node in the wild and attempts to connect to it while we are trying
   106  	// to connect to that node at the same time. This causes a dial failure.
   107  	node.Discovery.Close()
   108  	defer node.GoOffline()
   109  	t.Log("main test node id: ", node.host.ID())
   110  
   111  	// explicitly connect the main test node to each other node in the network
   112  	for _, groupNode := range nodes {
   113  		addrInfo := peer.AddrInfo{
   114  			ID:    groupNode.Host().ID(),
   115  			Addrs: groupNode.Host().Addrs(),
   116  		}
   117  		err := node.Host().Connect(context.Background(), addrInfo)
   118  		if err != nil {
   119  			t.Logf("error connecting to peer %q: %s", groupNode.Host().ID(), err)
   120  		}
   121  	}
   122  
   123  	<-qriPeerConnWaitCh
   124  
   125  	p2pRefResolver := node.NewP2PRefResolver()
   126  
   127  	dsrefspec.AssertResolverSpec(t, p2pRefResolver, func(r dsref.Ref, author *profile.Profile, _ *oplog.Log) error {
   128  		builder := dscache.NewBuilder()
   129  		kid, err := key.IDFromPubKey(author.PubKey)
   130  		builder.AddUser(r.Username, kid)
   131  		if err != nil {
   132  			return err
   133  		}
   134  		builder.AddDsVersionInfo(dsref.VersionInfo{
   135  			Username:  r.Username,
   136  			InitID:    r.InitID,
   137  			Path:      r.Path,
   138  			ProfileID: kid,
   139  			Name:      r.Name,
   140  		})
   141  		cache := builder.Build()
   142  		nodeWithRef.Repo.Dscache().Assign(cache)
   143  		testResolveRef := &dsref.Ref{
   144  			Username: r.Username,
   145  			Name:     r.Name,
   146  		}
   147  		nodeWithRef.Repo.Dscache().ResolveRef(ctx, testResolveRef)
   148  		return nil
   149  	})
   150  }