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 }