mirror of
https://github.com/libp2p/go-libp2p.git
synced 2025-10-16 13:10:47 +08:00
chore: add tests for examples
This commit is contained in:
@@ -40,6 +40,7 @@ import (
|
||||
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/libp2p/go-libp2p-core/peerstore"
|
||||
@@ -58,6 +59,7 @@ func handleStream(s network.Stream) {
|
||||
|
||||
// stream 's' will stay open until you close it (or the other side closes it).
|
||||
}
|
||||
|
||||
func readData(rw *bufio.ReadWriter) {
|
||||
for {
|
||||
str, _ := rw.ReadString('\n')
|
||||
@@ -80,18 +82,20 @@ func writeData(rw *bufio.ReadWriter) {
|
||||
for {
|
||||
fmt.Print("> ")
|
||||
sendData, err := stdReader.ReadString('\n')
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
rw.WriteString(fmt.Sprintf("%s\n", sendData))
|
||||
rw.Flush()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
sourcePort := flag.Int("sp", 0, "Source port number")
|
||||
dest := flag.String("d", "", "Destination multiaddr string")
|
||||
help := flag.Bool("help", false, "Display help")
|
||||
@@ -119,36 +123,62 @@ func main() {
|
||||
r = rand.Reader
|
||||
}
|
||||
|
||||
// Creates a new RSA key pair for this host.
|
||||
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
|
||||
h, err := makeHost(ctx, *sourcePort, r)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 0.0.0.0 will listen on any interface device.
|
||||
sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *sourcePort))
|
||||
|
||||
// libp2p.New constructs a new libp2p Host.
|
||||
// Other options can be added here.
|
||||
host, err := libp2p.New(
|
||||
context.Background(),
|
||||
libp2p.ListenAddrs(sourceMultiAddr),
|
||||
libp2p.Identity(prvKey),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if *dest == "" {
|
||||
startPeer(ctx, h, handleStream)
|
||||
} else {
|
||||
rw, err := startPeerAndConnect(ctx, h, *dest)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Create a thread to read and write data.
|
||||
go writeData(rw)
|
||||
go readData(rw)
|
||||
|
||||
}
|
||||
|
||||
// Wait until canceled
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
|
||||
func makeHost(ctx context.Context, port int, randomness io.Reader) (host.Host, error) {
|
||||
// Creates a new RSA key pair for this host.
|
||||
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, randomness)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 0.0.0.0 will listen on any interface device.
|
||||
sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port))
|
||||
|
||||
// libp2p.New constructs a new libp2p Host.
|
||||
// Other options can be added here.
|
||||
return libp2p.New(
|
||||
ctx,
|
||||
libp2p.ListenAddrs(sourceMultiAddr),
|
||||
libp2p.Identity(prvKey),
|
||||
)
|
||||
}
|
||||
|
||||
func startPeer(ctx context.Context, h host.Host, streamHandler network.StreamHandler) {
|
||||
// Set a function as stream handler.
|
||||
// This function is called when a peer connects, and starts a stream with this protocol.
|
||||
// Only applies on the receiving side.
|
||||
host.SetStreamHandler("/chat/1.0.0", handleStream)
|
||||
h.SetStreamHandler("/chat/1.0.0", streamHandler)
|
||||
|
||||
// Let's get the actual TCP port from our listen multiaddr, in case we're using 0 (default; random available port).
|
||||
var port string
|
||||
for _, la := range host.Network().ListenAddresses() {
|
||||
for _, la := range h.Network().ListenAddresses() {
|
||||
if p, err := la.ValueForProtocol(multiaddr.P_TCP); err == nil {
|
||||
port = p
|
||||
break
|
||||
@@ -156,53 +186,52 @@ func main() {
|
||||
}
|
||||
|
||||
if port == "" {
|
||||
panic("was not able to find actual local port")
|
||||
log.Println("was not able to find actual local port")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Run './chat -d /ip4/127.0.0.1/tcp/%v/p2p/%s' on another console.\n", port, host.ID().Pretty())
|
||||
fmt.Println("You can replace 127.0.0.1 with public IP as well.")
|
||||
fmt.Printf("\nWaiting for incoming connection\n\n")
|
||||
log.Printf("Run './chat -d /ip4/127.0.0.1/tcp/%v/p2p/%s' on another console.\n", port, h.ID().Pretty())
|
||||
log.Println("You can replace 127.0.0.1 with public IP as well.")
|
||||
log.Println("Waiting for incoming connection")
|
||||
log.Println()
|
||||
}
|
||||
|
||||
// Hang forever
|
||||
<-make(chan struct{})
|
||||
} else {
|
||||
fmt.Println("This node's multiaddresses:")
|
||||
for _, la := range host.Addrs() {
|
||||
fmt.Printf(" - %v\n", la)
|
||||
func startPeerAndConnect(ctx context.Context, h host.Host, destination string) (*bufio.ReadWriter, error) {
|
||||
log.Println("This node's multiaddresses:")
|
||||
for _, la := range h.Addrs() {
|
||||
log.Printf(" - %v\n", la)
|
||||
}
|
||||
fmt.Println()
|
||||
log.Println()
|
||||
|
||||
// Turn the destination into a multiaddr.
|
||||
maddr, err := multiaddr.NewMultiaddr(*dest)
|
||||
maddr, err := multiaddr.NewMultiaddr(destination)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Extract the peer ID from the multiaddr.
|
||||
info, err := peer.AddrInfoFromP2pAddr(maddr)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add the destination's peer multiaddress in the peerstore.
|
||||
// This will be used during connection and stream creation by libp2p.
|
||||
host.Peerstore().AddAddrs(info.ID, info.Addrs, peerstore.PermanentAddrTTL)
|
||||
h.Peerstore().AddAddrs(info.ID, info.Addrs, peerstore.PermanentAddrTTL)
|
||||
|
||||
// Start a stream with the destination.
|
||||
// Multiaddress of the destination peer is fetched from the peerstore using 'peerId'.
|
||||
s, err := host.NewStream(context.Background(), info.ID, "/chat/1.0.0")
|
||||
s, err := h.NewStream(context.Background(), info.ID, "/chat/1.0.0")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Println(err)
|
||||
return nil, err
|
||||
}
|
||||
log.Println("Established connection to destination")
|
||||
|
||||
// Create a buffered stream so that read and writes are non blocking.
|
||||
rw := bufio.NewReadWriter(bufio.NewReader(s), bufio.NewWriter(s))
|
||||
|
||||
// Create a thread to read and write data.
|
||||
go writeData(rw)
|
||||
go readData(rw)
|
||||
|
||||
// Hang forever.
|
||||
select {}
|
||||
}
|
||||
return rw, nil
|
||||
}
|
||||
|
72
examples/chat/chat_test.go
Normal file
72
examples/chat/chat_test.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
|
||||
"github.com/libp2p/go-libp2p/examples/testutils"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
var h testutils.LogHarness
|
||||
h.Expect("Waiting for incoming connection")
|
||||
h.Expect("Established connection to destination")
|
||||
h.Expect("Got a new stream!")
|
||||
|
||||
h.Run(t, func() {
|
||||
// Create a context that will stop the hosts when the tests end
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
port1, err := testutils.FindFreePort(t, "", 5)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
port2, err := testutils.FindFreePort(t, "", 5)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
h1, err := makeHost(ctx, port1, rand.Reader)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
go startPeer(ctx, h1, func(network.Stream) {
|
||||
log.Println("Got a new stream!")
|
||||
cancel() // end the test
|
||||
})
|
||||
|
||||
dest := fmt.Sprintf("/ip4/127.0.0.1/tcp/%v/p2p/%s", port1, h1.ID().Pretty())
|
||||
|
||||
h2, err := makeHost(ctx, port2, rand.Reader)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
rw, err := startPeerAndConnect(ctx, h2, dest)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
rw.WriteString("test message")
|
||||
rw.Flush()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
}
|
||||
})
|
||||
}
|
@@ -22,13 +22,42 @@ import (
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// LibP2P code uses golog to log messages. They log with different
|
||||
// string IDs (i.e. "swarm"). We can control the verbosity level for
|
||||
// all loggers with:
|
||||
golog.SetAllLoggers(golog.LevelInfo) // Change to INFO for extra info
|
||||
|
||||
// Parse options from the command line
|
||||
listenF := flag.Int("l", 0, "wait for incoming connections")
|
||||
targetF := flag.String("d", "", "target peer to dial")
|
||||
insecureF := flag.Bool("insecure", false, "use an unencrypted connection")
|
||||
seedF := flag.Int64("seed", 0, "set random seed for id generation")
|
||||
flag.Parse()
|
||||
|
||||
if *listenF == 0 {
|
||||
log.Fatal("Please provide a port to bind on with -l")
|
||||
}
|
||||
|
||||
// Make a host that listens on the given multiaddress
|
||||
ha, err := makeBasicHost(*listenF, *insecureF, *seedF)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if *targetF == "" {
|
||||
runListener(ctx, ha, *listenF, *insecureF)
|
||||
} else {
|
||||
runSender(ctx, ha, *targetF)
|
||||
}
|
||||
}
|
||||
|
||||
// makeBasicHost creates a LibP2P host with a random peer ID listening on the
|
||||
// given multiaddress. It won't encrypt the connection if insecure is true.
|
||||
func makeBasicHost(listenPort int, insecure bool, randseed int64) (host.Host, error) {
|
||||
|
||||
// If the seed is zero, use real cryptographic randomness. Otherwise, use a
|
||||
// deterministic randomness source to make generated keys stay the same
|
||||
// across multiple runs
|
||||
var r io.Reader
|
||||
if randseed == 0 {
|
||||
r = rand.Reader
|
||||
@@ -53,55 +82,27 @@ func makeBasicHost(listenPort int, insecure bool, randseed int64) (host.Host, er
|
||||
opts = append(opts, libp2p.NoSecurity)
|
||||
}
|
||||
|
||||
basicHost, err := libp2p.New(context.Background(), opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return libp2p.New(context.Background(), opts...)
|
||||
}
|
||||
|
||||
func getHostAddress(ha host.Host) string {
|
||||
// Build host multiaddress
|
||||
hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", basicHost.ID().Pretty()))
|
||||
hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", ha.ID().Pretty()))
|
||||
|
||||
// Now we can build a full multiaddress to reach this host
|
||||
// by encapsulating both addresses:
|
||||
addr := basicHost.Addrs()[0]
|
||||
fullAddr := addr.Encapsulate(hostAddr)
|
||||
log.Printf("I am %s\n", fullAddr)
|
||||
if insecure {
|
||||
log.Printf("Now run \"./echo -l %d -d %s -insecure\" on a different terminal\n", listenPort+1, fullAddr)
|
||||
} else {
|
||||
log.Printf("Now run \"./echo -l %d -d %s\" on a different terminal\n", listenPort+1, fullAddr)
|
||||
}
|
||||
|
||||
return basicHost, nil
|
||||
addr := ha.Addrs()[0]
|
||||
return addr.Encapsulate(hostAddr).String()
|
||||
}
|
||||
|
||||
func main() {
|
||||
// LibP2P code uses golog to log messages. They log with different
|
||||
// string IDs (i.e. "swarm"). We can control the verbosity level for
|
||||
// all loggers with:
|
||||
golog.SetAllLoggers(golog.LevelInfo) // Change to INFO for extra info
|
||||
|
||||
// Parse options from the command line
|
||||
listenF := flag.Int("l", 0, "wait for incoming connections")
|
||||
target := flag.String("d", "", "target peer to dial")
|
||||
insecure := flag.Bool("insecure", false, "use an unencrypted connection")
|
||||
seed := flag.Int64("seed", 0, "set random seed for id generation")
|
||||
flag.Parse()
|
||||
|
||||
if *listenF == 0 {
|
||||
log.Fatal("Please provide a port to bind on with -l")
|
||||
}
|
||||
|
||||
// Make a host that listens on the given multiaddress
|
||||
ha, err := makeBasicHost(*listenF, *insecure, *seed)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
func runListener(ctx context.Context, ha host.Host, listenPort int, insecure bool) {
|
||||
fullAddr := getHostAddress(ha)
|
||||
log.Printf("I am %s\n", fullAddr)
|
||||
|
||||
// Set a stream handler on host A. /echo/1.0.0 is
|
||||
// a user-defined protocol name.
|
||||
ha.SetStreamHandler("/echo/1.0.0", func(s network.Stream) {
|
||||
log.Println("Got a new stream!")
|
||||
log.Println("listener received new stream")
|
||||
if err := doEcho(s); err != nil {
|
||||
log.Println(err)
|
||||
s.Reset()
|
||||
@@ -110,27 +111,54 @@ func main() {
|
||||
}
|
||||
})
|
||||
|
||||
if *target == "" {
|
||||
log.Println("listening for connections")
|
||||
select {} // hang forever
|
||||
|
||||
if insecure {
|
||||
log.Printf("Now run \"./echo -l %d -d %s -insecure\" on a different terminal\n", listenPort+1, fullAddr)
|
||||
} else {
|
||||
log.Printf("Now run \"./echo -l %d -d %s\" on a different terminal\n", listenPort+1, fullAddr)
|
||||
}
|
||||
/**** This is where the listener code ends ****/
|
||||
|
||||
// Wait until canceled
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}
|
||||
|
||||
func runSender(ctx context.Context, ha host.Host, targetPeer string) {
|
||||
fullAddr := getHostAddress(ha)
|
||||
log.Printf("I am %s\n", fullAddr)
|
||||
|
||||
// Set a stream handler on host A. /echo/1.0.0 is
|
||||
// a user-defined protocol name.
|
||||
ha.SetStreamHandler("/echo/1.0.0", func(s network.Stream) {
|
||||
log.Println("sender received new stream")
|
||||
if err := doEcho(s); err != nil {
|
||||
log.Println(err)
|
||||
s.Reset()
|
||||
} else {
|
||||
s.Close()
|
||||
}
|
||||
})
|
||||
|
||||
// The following code extracts target's the peer ID from the
|
||||
// given multiaddress
|
||||
ipfsaddr, err := ma.NewMultiaddr(*target)
|
||||
ipfsaddr, err := ma.NewMultiaddr(targetPeer)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
peerid, err := peer.IDB58Decode(pid)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Decapsulate the /ipfs/<peerID> part from the target
|
||||
@@ -142,23 +170,27 @@ func main() {
|
||||
// so LibP2P knows how to contact it
|
||||
ha.Peerstore().AddAddr(peerid, targetAddr, peerstore.PermanentAddrTTL)
|
||||
|
||||
log.Println("opening stream")
|
||||
log.Println("sender opening stream")
|
||||
// make a new stream from host B to host A
|
||||
// it should be handled on host A by the handler we set above because
|
||||
// we use the same /echo/1.0.0 protocol
|
||||
s, err := ha.NewStream(context.Background(), peerid, "/echo/1.0.0")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Println("sender saying hello")
|
||||
_, err = s.Write([]byte("Hello, world!\n"))
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
out, err := ioutil.ReadAll(s)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("read reply: %q\n", out)
|
||||
@@ -172,7 +204,7 @@ func doEcho(s network.Stream) error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Printf("read: %s\n", str)
|
||||
log.Printf("read: %s", str)
|
||||
_, err = s.Write([]byte(str))
|
||||
return err
|
||||
}
|
||||
|
58
examples/echo/main_test.go
Normal file
58
examples/echo/main_test.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/libp2p/go-libp2p/examples/testutils"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
var h testutils.LogHarness
|
||||
h.Expect("listening for connections")
|
||||
h.Expect("sender opening stream")
|
||||
h.Expect("sender saying hello")
|
||||
h.Expect("listener received new stream")
|
||||
h.Expect("read: Hello, world!")
|
||||
h.Expect(`read reply: "Hello, world!\n"`)
|
||||
|
||||
h.Run(t, func() {
|
||||
// Create a context that will stop the hosts when the tests end
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
// Get a tcp port for the listener
|
||||
lport, err := testutils.FindFreePort(t, "", 5)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Get a tcp port for the sender
|
||||
sport, err := testutils.FindFreePort(t, "", 5)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Make listener
|
||||
lh, err := makeBasicHost(lport, true, 1)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
go runListener(ctx, lh, lport, true)
|
||||
|
||||
// Make sender
|
||||
listenAddr := getHostAddress(lh)
|
||||
sh, err := makeBasicHost(sport, true, 2)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
runSender(ctx, sh, listenAddr)
|
||||
})
|
||||
}
|
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-libp2p"
|
||||
@@ -17,6 +17,10 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
run()
|
||||
}
|
||||
|
||||
func run() {
|
||||
// The context governs the lifetime of the libp2p node.
|
||||
// Cancelling it will stop the the host.
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
@@ -28,7 +32,7 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
fmt.Printf("Hello World, my hosts ID is %s\n", h.ID())
|
||||
log.Printf("Hello World, my hosts ID is %s\n", h.ID())
|
||||
|
||||
// Now, normally you do not just want a simple host, you want
|
||||
// that is fully configured to best support your p2p application.
|
||||
@@ -105,5 +109,5 @@ func main() {
|
||||
h2.Connect(ctx, *pi)
|
||||
}
|
||||
*/
|
||||
fmt.Printf("Hello World, my second hosts ID is %s\n", h2.ID())
|
||||
log.Printf("Hello World, my second hosts ID is %s\n", h2.ID())
|
||||
}
|
||||
|
14
examples/libp2p-host/host_test.go
Normal file
14
examples/libp2p-host/host_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/libp2p/go-libp2p/examples/testutils"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
var h testutils.LogHarness
|
||||
h.ExpectPrefix("Hello World, my hosts ID is ")
|
||||
h.ExpectPrefix("Hello World, my second hosts ID is ")
|
||||
h.Run(t, run)
|
||||
}
|
@@ -13,6 +13,23 @@ import (
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Choose random ports between 10000-10100
|
||||
rand.Seed(666)
|
||||
port1 := rand.Intn(100) + 10000
|
||||
port2 := port1 + 1
|
||||
|
||||
done := make(chan bool, 1)
|
||||
|
||||
// Make 2 hosts
|
||||
h1 := makeRandomNode(port1, done)
|
||||
h2 := makeRandomNode(port2, done)
|
||||
|
||||
log.Printf("This is a conversation between %s and %s\n", h1.ID(), h2.ID())
|
||||
|
||||
run(h1, h2, done)
|
||||
}
|
||||
|
||||
// helper method - create a lib-p2p host to listen on a port
|
||||
func makeRandomNode(port int, done chan bool) *Node {
|
||||
// Ignoring most errors for brevity
|
||||
@@ -28,22 +45,11 @@ func makeRandomNode(port int, done chan bool) *Node {
|
||||
return NewNode(host, done)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Choose random ports between 10000-10100
|
||||
rand.Seed(666)
|
||||
port1 := rand.Intn(100) + 10000
|
||||
port2 := port1 + 1
|
||||
|
||||
done := make(chan bool, 1)
|
||||
|
||||
// Make 2 hosts
|
||||
h1 := makeRandomNode(port1, done)
|
||||
h2 := makeRandomNode(port2, done)
|
||||
func run(h1, h2 *Node, done <-chan bool) {
|
||||
// connect peers
|
||||
h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), peerstore.PermanentAddrTTL)
|
||||
h2.Peerstore().AddAddrs(h1.ID(), h1.Addrs(), peerstore.PermanentAddrTTL)
|
||||
|
||||
log.Printf("This is a conversation between %s and %s\n", h1.ID(), h2.ID())
|
||||
|
||||
// send messages using the protocols
|
||||
h1.Ping(h2.Host)
|
||||
h2.Ping(h1.Host)
|
||||
|
55
examples/multipro/main_test.go
Normal file
55
examples/multipro/main_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"github.com/libp2p/go-libp2p/examples/testutils"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
port1, err := testutils.FindFreePort(t, "", 5)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
port2, err := testutils.FindFreePort(t, "", 5)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
done := make(chan bool, 1)
|
||||
h1 := makeRandomNode(port1, done)
|
||||
h2 := makeRandomNode(port2, done)
|
||||
|
||||
var h testutils.LogHarness
|
||||
|
||||
// Sequence of log messages when h1 pings h2
|
||||
pingh1h2 := h.NewSequence("ping h1->h2")
|
||||
pingh1h2.ExpectPrefix(fmt.Sprintf("%s: Sending ping to: %s", h1.ID(), h2.ID()))
|
||||
pingh1h2.ExpectPrefix(fmt.Sprintf("%s: Received ping request from %s", h2.ID(), h1.ID()))
|
||||
pingh1h2.ExpectPrefix(fmt.Sprintf("%s: Received ping response from %s", h1.ID(), h2.ID()))
|
||||
|
||||
// Sequence of log messages when h2 pings h1
|
||||
pingh2h1 := h.NewSequence("ping h2->h1")
|
||||
pingh2h1.ExpectPrefix(fmt.Sprintf("%s: Sending ping to: %s", h2.ID(), h1.ID()))
|
||||
pingh2h1.ExpectPrefix(fmt.Sprintf("%s: Received ping request from %s", h1.ID(), h2.ID()))
|
||||
pingh2h1.ExpectPrefix(fmt.Sprintf("%s: Received ping response from %s", h2.ID(), h1.ID()))
|
||||
|
||||
// Sequence of log messages when h1 sends echo to h2
|
||||
echoh1h2 := h.NewSequence("echo h1->h2")
|
||||
echoh1h2.ExpectPrefix(fmt.Sprintf("%s: Sending echo to: %s", h1.ID(), h2.ID()))
|
||||
echoh1h2.ExpectPrefix(fmt.Sprintf("%s: Echo response to %s", h2.ID(), h1.ID()))
|
||||
|
||||
// Sequence of log messages when h1 sends echo to h2
|
||||
echoh2h1 := h.NewSequence("echo h2->h1")
|
||||
echoh2h1.ExpectPrefix(fmt.Sprintf("%s: Sending echo to: %s", h2.ID(), h1.ID()))
|
||||
echoh2h1.ExpectPrefix(fmt.Sprintf("%s: Echo response to %s", h1.ID(), h2.ID()))
|
||||
|
||||
h.Run(t, func() {
|
||||
run(h1, h2, done)
|
||||
})
|
||||
}
|
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/libp2p/go-libp2p"
|
||||
"github.com/libp2p/go-libp2p-core/network"
|
||||
@@ -14,27 +14,34 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
run()
|
||||
}
|
||||
|
||||
func run() {
|
||||
// Create three libp2p hosts, enable relay client capabilities on all
|
||||
// of them.
|
||||
|
||||
// Tell the host to monitor for relays.
|
||||
h1, err := libp2p.New(context.Background(), libp2p.EnableRelay(circuit.OptDiscovery))
|
||||
// Tell the host use relays
|
||||
h1, err := libp2p.New(context.Background(), libp2p.EnableRelay())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Printf("Failed to create h1: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Tell the host to relay connections for other peers (The ability to *use*
|
||||
// a relay vs the ability to *be* a relay)
|
||||
h2, err := libp2p.New(context.Background(), libp2p.EnableRelay(circuit.OptHop))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Printf("Failed to create h2: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Zero out the listen addresses for the host, so it can only communicate
|
||||
// via p2p-circuit for our example
|
||||
h3, err := libp2p.New(context.Background(), libp2p.ListenAddrs(), libp2p.EnableRelay())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Printf("Failed to create h3: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
h2info := peer.AddrInfo{
|
||||
@@ -44,30 +51,33 @@ func main() {
|
||||
|
||||
// Connect both h1 and h3 to h2, but not to each other
|
||||
if err := h1.Connect(context.Background(), h2info); err != nil {
|
||||
panic(err)
|
||||
log.Printf("Failed to connect h1 and h2: %v", err)
|
||||
return
|
||||
}
|
||||
if err := h3.Connect(context.Background(), h2info); err != nil {
|
||||
panic(err)
|
||||
log.Printf("Failed to connect h3 and h2: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Now, to test things, let's set up a protocol handler on h3
|
||||
h3.SetStreamHandler("/cats", func(s network.Stream) {
|
||||
fmt.Println("Meow! It worked!")
|
||||
log.Println("Meow! It worked!")
|
||||
s.Close()
|
||||
})
|
||||
|
||||
_, err = h1.NewStream(context.Background(), h3.ID(), "/cats")
|
||||
if err == nil {
|
||||
fmt.Println("Didnt actually expect to get a stream here. What happened?")
|
||||
log.Println("Didnt actually expect to get a stream here. What happened?")
|
||||
return
|
||||
}
|
||||
fmt.Println("Okay, no connection from h1 to h3: ", err)
|
||||
fmt.Println("Just as we suspected")
|
||||
log.Printf("Okay, no connection from h1 to h3: %v", err)
|
||||
log.Println("Just as we suspected")
|
||||
|
||||
// Creates a relay address
|
||||
relayaddr, err := ma.NewMultiaddr("/p2p-circuit/ipfs/" + h3.ID().Pretty())
|
||||
// Creates a relay address to h3 using h2 as the relay
|
||||
relayaddr, err := ma.NewMultiaddr("/p2p/" + h2.ID().Pretty() + "/p2p-circuit/ipfs/" + h3.ID().Pretty())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Since we just tried and failed to dial, the dialer system will, by default
|
||||
@@ -81,13 +91,14 @@ func main() {
|
||||
Addrs: []ma.Multiaddr{relayaddr},
|
||||
}
|
||||
if err := h1.Connect(context.Background(), h3relayInfo); err != nil {
|
||||
panic(err)
|
||||
log.Printf("Failed to connect h1 and h3: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Woohoo! we're connected!
|
||||
s, err := h1.NewStream(context.Background(), h3.ID(), "/cats")
|
||||
if err != nil {
|
||||
fmt.Println("huh, this should have worked: ", err)
|
||||
log.Println("huh, this should have worked: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
|
14
examples/relay/main_test.go
Normal file
14
examples/relay/main_test.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/libp2p/go-libp2p/examples/testutils"
|
||||
)
|
||||
|
||||
func TestMain(t *testing.T) {
|
||||
var h testutils.LogHarness
|
||||
h.ExpectPrefix("Okay, no connection from h1 to h3")
|
||||
h.ExpectPrefix("Meow! It worked!")
|
||||
h.Run(t, run)
|
||||
}
|
122
examples/testutils/logharness.go
Normal file
122
examples/testutils/logharness.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// A LogHarness runs sets of assertions against the log output of a function. Assertions are grouped
|
||||
// into sequences of messages that are expected to be found in the log output. Calling one of the Expect
|
||||
// methods on the harness adds an expectation to the default sequence of messages. Additional sequences
|
||||
// can be created by calling NewSequence.
|
||||
type LogHarness struct {
|
||||
buf bytes.Buffer
|
||||
sequences []*Sequence
|
||||
}
|
||||
|
||||
type Expectation interface {
|
||||
IsMatch(line string) bool
|
||||
String() string
|
||||
}
|
||||
|
||||
// Run executes the function f and captures any output written using Go's standard log. Each sequence
|
||||
// of expected messages is then
|
||||
func (h *LogHarness) Run(t *testing.T, f func()) {
|
||||
// Capture raw log output
|
||||
fl := log.Flags()
|
||||
log.SetFlags(0)
|
||||
log.SetOutput(&h.buf)
|
||||
f()
|
||||
log.SetFlags(fl)
|
||||
log.SetOutput(os.Stderr)
|
||||
|
||||
for _, seq := range h.sequences {
|
||||
seq.Assert(t, bufio.NewScanner(bytes.NewReader(h.buf.Bytes())))
|
||||
}
|
||||
}
|
||||
|
||||
// Expect adds an expectation to the default sequence that the log contains a line equal to s
|
||||
func (h *LogHarness) Expect(s string) {
|
||||
if len(h.sequences) == 0 {
|
||||
h.sequences = append(h.sequences, &Sequence{name: ""})
|
||||
}
|
||||
h.sequences[0].Expect(s)
|
||||
}
|
||||
|
||||
// ExpectPrefix adds an to the default sequence expectation that the log contains a line starting with s
|
||||
func (h *LogHarness) ExpectPrefix(s string) {
|
||||
if len(h.sequences) == 0 {
|
||||
h.sequences = append(h.sequences, &Sequence{name: ""})
|
||||
}
|
||||
h.sequences[0].ExpectPrefix(s)
|
||||
}
|
||||
|
||||
// NewSequence creates a new sequence of expected log messages
|
||||
func (h *LogHarness) NewSequence(name string) *Sequence {
|
||||
seq := &Sequence{name: name}
|
||||
h.sequences = append(h.sequences, seq)
|
||||
return seq
|
||||
}
|
||||
|
||||
type prefix string
|
||||
|
||||
func (p prefix) IsMatch(line string) bool {
|
||||
return strings.HasPrefix(line, string(p))
|
||||
}
|
||||
|
||||
func (p prefix) String() string {
|
||||
return fmt.Sprintf("prefix %q", string(p))
|
||||
}
|
||||
|
||||
type text string
|
||||
|
||||
func (t text) IsMatch(line string) bool {
|
||||
return line == string(t)
|
||||
}
|
||||
|
||||
func (t text) String() string {
|
||||
return fmt.Sprintf("text %q", string(t))
|
||||
}
|
||||
|
||||
type Sequence struct {
|
||||
name string
|
||||
exp []Expectation
|
||||
}
|
||||
|
||||
func (seq *Sequence) Assert(t *testing.T, s *bufio.Scanner) {
|
||||
var tag string
|
||||
if seq.name != "" {
|
||||
tag = fmt.Sprintf("[%s] ", seq.name)
|
||||
}
|
||||
// Match raw log lines against expectations
|
||||
exploop:
|
||||
for _, e := range seq.exp {
|
||||
for s.Scan() {
|
||||
if e.IsMatch(s.Text()) {
|
||||
t.Logf("%ssaw: %s", tag, s.Text())
|
||||
continue exploop
|
||||
}
|
||||
}
|
||||
if s.Err() == nil {
|
||||
t.Errorf("%sdid not see expected %s", tag, e.String())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Expect adds an expectation that the log contains a line equal to s
|
||||
func (seq *Sequence) Expect(s string) {
|
||||
seq.exp = append(seq.exp, text(s))
|
||||
}
|
||||
|
||||
// ExpectPrefix adds an expectation that the log contains a line starting with s
|
||||
func (seq *Sequence) ExpectPrefix(s string) {
|
||||
seq.exp = append(seq.exp, prefix(s))
|
||||
}
|
37
examples/testutils/net.go
Normal file
37
examples/testutils/net.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package testutils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// FindFreePort attempts to find an unused tcp port
|
||||
func FindFreePort(t *testing.T, host string, maxAttempts int) (int, error) {
|
||||
t.Helper()
|
||||
|
||||
if host == "" {
|
||||
host = "localhost"
|
||||
}
|
||||
|
||||
for i := 0; i < maxAttempts; i++ {
|
||||
addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, "0"))
|
||||
if err != nil {
|
||||
t.Logf("unable to resolve tcp addr: %v", err)
|
||||
continue
|
||||
}
|
||||
l, err := net.ListenTCP("tcp", addr)
|
||||
if err != nil {
|
||||
l.Close()
|
||||
t.Logf("unable to listen on addr %q: %v", addr, err)
|
||||
continue
|
||||
}
|
||||
|
||||
port := l.Addr().(*net.TCPAddr).Port
|
||||
l.Close()
|
||||
return port, nil
|
||||
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("no free port found")
|
||||
}
|
Reference in New Issue
Block a user