Skip to content

Commit

Permalink
feat(p2p.test): add TestableNode struct that satisfies the `Testabl…
Browse files Browse the repository at this point in the history
…ePeerNode` interface

currently using `TestableNode` to test the p2ptest functions
  • Loading branch information
ramfox committed Oct 23, 2018
1 parent 5de179a commit 2c53a49
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 0 deletions.
4 changes: 4 additions & 0 deletions p2p/test/p2ptest.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ func NewAvailableTestNode(r repo.Repo, f *TestNodeFactory) (TestablePeerNode, er
// remote peer.
// Take a look at https://github.com/libp2p/go-libp2p-host/blob/623ffaa4ef2b8dad77933159d0848a393a91c41e/host.go#L36
// for more info
// Connect should always:
// - add a connections to the peer
// - add the addrs of the peer to the peerstore
// - add a tag for each peer in the connmanager
func ConnectNodes(ctx context.Context, nodes []TestablePeerNode) error {
var wg sync.WaitGroup
connect := func(n TestablePeerNode, pinfo pstore.PeerInfo) error {
Expand Down
49 changes: 49 additions & 0 deletions p2p/test/p2ptest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package p2ptest

import (
"context"
"testing"
)

// Ensure that when we use ConnectNodes, we are creating a basic connection
// between two nodes
// - we have connections to each peer
// - we have the addrs of each peer
// - we have a tag on each peer
func TestConnectNodes(t *testing.T) {
ctx := context.Background()
f := NewTestNodeFactory(NewTestableNode)
testNodes, err := NewTestDirNetwork(ctx, f)
if err != nil {
t.Error(err)
return
}

if err := ConnectNodes(ctx, testNodes); err != nil {
t.Error(err)
}

for _, node := range testNodes {
// test that each conn has a connection to at least one peer id
pid := node.SimplePeerInfo().ID
for _, rnode := range testNodes {
rpid := rnode.SimplePeerInfo().ID
// dont need to check for connections to self
if pid == rpid {
continue
}
conns := node.Host().Network().ConnsToPeer(rpid)
if len(conns) == 0 {
t.Errorf("node %s has no connections to node %s", pid, rpid)
}
addrs := node.Host().Peerstore().Addrs(rpid)
if len(addrs) == 0 {
t.Errorf("node %s has no addrs for node %s", pid, rpid)
}
tag := node.Host().ConnManager().GetTagInfo(rpid)
if tag == nil {
t.Errorf("node %s has not tag info on node %s", pid, rpid)
}
}
}
}
108 changes: 108 additions & 0 deletions p2p/test/testable_node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package p2ptest

import (
"context"
"fmt"
"time"

"github.com/qri-io/qri/config"
"github.com/qri-io/qri/repo"

// net "gx/ipfs/QmPjvxTpVH8qJyQDnxnsxF9kv9jezKD1kozz1hs3fCGsNh/go-libp2p-net"
libp2p "gx/ipfs/QmY51bqSM5XgxQZqsBrQcRkKTnCb8EKpJpR9K6Qax7Njco/go-libp2p"
// ma "gx/ipfs/QmYmsdtJ3HsodkePE3eU3TsCaP2YvPZJ4LoXnNkDE5Tpt7/go-multiaddr"
connmgr "gx/ipfs/QmYAL9JsqVVPFWwM1ZzHNsofmTzRYQHJ2KqQaBmFJjJsNx/go-libp2p-connmgr"
pstore "gx/ipfs/QmZR2XWVVBCtbgBWnQhWk2xcQfaR3W8faQPriAiaaj7rsr/go-libp2p-peerstore"
host "gx/ipfs/Qmb8T6YBBsjYsVGfrihQLfCJveczZnneSBqBKkYEBWDjge/go-libp2p-host"
peer "gx/ipfs/QmdVrMn1LhB4ybb8hMVaMLXnA8XRSewMnK6YqXKXoTcRvN/go-libp2p-peer"
)

// TestableNode satisfies the TestablePeerNode interface
// It is used for testing inside the p2ptest package
type TestableNode struct {
host host.Host
cfg *config.P2P
Repo repo.Repo
}

// TestProtocolID is the key used to set the stream handler to our
// testing protocol
var TestProtocolID = "qri"

// Host returns the node's underlying host
func (n *TestableNode) Host() host.Host {
return n.host
}

// SimplePeerInfo returns the PeerInfo of the TestableNode
func (n *TestableNode) SimplePeerInfo() pstore.PeerInfo {
return pstore.PeerInfo{
ID: n.Host().ID(),
Addrs: n.Host().Addrs(),
}
}

// UpgradeQriConnection upgrades the connection from a basic connection
// to a Qri connection
func (n *TestableNode) UpgradeQriConnection(pstore.PeerInfo) error {
return nil
}

// GoOnline assumes the TestNode is not online, it will set
// the StreamHandler and updates our profile with the underlying peerIDs
func (n *TestableNode) GoOnline() error {

// add multistream handler for qri protocol to the host
// for more info on multistreams check github.com/multformats/go-multistream
// n.Host().SetStreamHandler(QriProtocolID, n.QriStreamHandler)

p, err := n.Repo.Profile()
if err != nil {
return fmt.Errorf("error getting repo profile: %s", err.Error())
}
p.PeerIDs = []peer.ID{n.Host().ID()}

// update profile with our p2p addresses
if err := n.Repo.SetProfile(p); err != nil {
return err
}

return nil
}

// NewTestableNode creates a testable node from a repo and a config.P2P
// it creates a basic host
func NewTestableNode(r repo.Repo, p2pconf *config.P2P) (TestablePeerNode, error) {
ctx := context.Background()
ps := pstore.NewPeerstore()
// this is essentially what is located in the p2p.makeBasicHost function
pk, err := p2pconf.DecodePrivateKey()
if err != nil {
return nil, err
}

pid, err := p2pconf.DecodePeerID()
if err != nil {
return nil, err
}
ps.AddPrivKey(pid, pk)
ps.AddPubKey(pid, pk.GetPublic())
opts := []libp2p.Option{
libp2p.ListenAddrs(p2pconf.Addrs...),
libp2p.Identity(pk),
libp2p.Peerstore(ps),
libp2p.ConnectionManager(connmgr.NewConnManager(1000, 0, time.Millisecond)),
}
basicHost, err := libp2p.New(ctx, opts...)
if err != nil {
return nil, err
}
return &TestableNode{
host: basicHost,
Repo: r,
cfg: p2pconf,
}, nil
}

var _ TestablePeerNode = (*TestableNode)(nil)
var _ NodeMakerFunc = NewTestableNode

0 comments on commit 2c53a49

Please sign in to comment.