go-libp2p-kad-dht/ext_test.go

346 lines
7.7 KiB
Go
Raw Normal View History

2014-08-10 21:40:17 -07:00
package dht
import (
"testing"
2014-08-19 19:14:52 -07:00
crand "crypto/rand"
2014-11-10 14:22:56 -08:00
2014-09-17 10:30:38 -07:00
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
2014-10-21 15:10:58 -07:00
ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
2014-09-17 10:30:38 -07:00
msg "github.com/jbenet/go-ipfs/net/message"
mux "github.com/jbenet/go-ipfs/net/mux"
2014-08-10 21:40:17 -07:00
peer "github.com/jbenet/go-ipfs/peer"
"github.com/jbenet/go-ipfs/routing"
pb "github.com/jbenet/go-ipfs/routing/dht/pb"
u "github.com/jbenet/go-ipfs/util"
2014-08-10 21:40:17 -07:00
2014-11-05 08:49:55 -08:00
"sync"
2014-08-10 21:40:17 -07:00
"time"
)
2014-09-18 19:30:04 -07:00
// mesHandleFunc is a function that takes in outgoing messages
// and can respond to them, simulating other peers on the network.
// returning nil will chose not to respond and pass the message onto the
// next registered handler
type mesHandleFunc func(msg.NetMessage) msg.NetMessage
2014-08-10 21:40:17 -07:00
// fauxNet is a standin for a swarm.Network in order to more easily recreate
// different testing scenarios
2014-09-17 10:30:38 -07:00
type fauxSender struct {
2014-11-05 08:49:55 -08:00
sync.Mutex
handlers []mesHandleFunc
2014-08-10 21:40:17 -07:00
}
2014-09-18 19:30:04 -07:00
func (f *fauxSender) AddHandler(fn func(msg.NetMessage) msg.NetMessage) {
2014-11-05 08:49:55 -08:00
f.Lock()
defer f.Unlock()
2014-09-18 19:30:04 -07:00
f.handlers = append(f.handlers, fn)
}
2014-08-10 21:40:17 -07:00
2014-09-18 19:30:04 -07:00
func (f *fauxSender) SendRequest(ctx context.Context, m msg.NetMessage) (msg.NetMessage, error) {
2014-11-05 08:49:55 -08:00
f.Lock()
handlers := make([]mesHandleFunc, len(f.handlers))
copy(handlers, f.handlers)
f.Unlock()
for _, h := range handlers {
2014-09-17 10:30:38 -07:00
reply := h(m)
if reply != nil {
return reply, nil
}
}
2014-08-10 21:40:17 -07:00
2014-09-18 19:30:04 -07:00
// no reply? ok force a timeout
select {
case <-ctx.Done():
}
return nil, ctx.Err()
2014-08-10 21:40:17 -07:00
}
2014-09-17 10:30:38 -07:00
func (f *fauxSender) SendMessage(ctx context.Context, m msg.NetMessage) error {
2014-11-05 08:49:55 -08:00
f.Lock()
handlers := make([]mesHandleFunc, len(f.handlers))
copy(handlers, f.handlers)
f.Unlock()
for _, h := range handlers {
2014-09-17 10:30:38 -07:00
reply := h(m)
if reply != nil {
return nil
2014-08-10 21:40:17 -07:00
}
2014-09-17 10:30:38 -07:00
}
2014-08-10 21:40:17 -07:00
return nil
}
2014-09-17 10:30:38 -07:00
// fauxNet is a standin for a swarm.Network in order to more easily recreate
// different testing scenarios
type fauxNet struct {
}
2014-08-10 21:40:17 -07:00
2014-09-17 10:30:38 -07:00
// DialPeer attempts to establish a connection to a given peer
2014-11-05 04:26:30 -08:00
func (f *fauxNet) DialPeer(context.Context, peer.Peer) error {
2014-09-17 10:30:38 -07:00
return nil
}
2014-09-17 10:30:38 -07:00
// ClosePeer connection to peer
func (f *fauxNet) ClosePeer(peer.Peer) error {
2014-09-17 10:30:38 -07:00
return nil
2014-08-10 21:40:17 -07:00
}
2014-09-17 10:30:38 -07:00
// IsConnected returns whether a connection to given peer exists.
func (f *fauxNet) IsConnected(peer.Peer) (bool, error) {
2014-09-17 10:30:38 -07:00
return true, nil
}
2014-09-17 10:30:38 -07:00
// GetProtocols returns the protocols registered in the network.
func (f *fauxNet) GetProtocols() *mux.ProtocolMap { return nil }
// SendMessage sends given Message out
func (f *fauxNet) SendMessage(msg.NetMessage) error {
return nil
2014-08-19 19:14:52 -07:00
}
func (f *fauxNet) GetPeerList() []peer.Peer {
return nil
}
func (f *fauxNet) GetBandwidthTotals() (uint64, uint64) {
return 0, 0
}
2014-09-17 10:30:38 -07:00
// Close terminates all network operation
func (f *fauxNet) Close() error { return nil }
func TestGetFailures(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
2014-09-19 18:11:05 -07:00
2014-09-17 10:30:38 -07:00
ctx := context.Background()
fn := &fauxNet{}
fs := &fauxSender{}
2014-08-10 21:40:17 -07:00
2014-09-17 10:30:38 -07:00
peerstore := peer.NewPeerstore()
local := makePeer(nil)
2014-08-10 21:40:17 -07:00
2014-10-18 04:19:12 -07:00
d := NewDHT(ctx, local, peerstore, fn, fs, ds.NewMapDatastore())
other := makePeer(nil)
d.Update(ctx, other)
// This one should time out
2014-09-18 19:30:04 -07:00
// u.POut("Timout Test\n")
ctx1, _ := context.WithTimeout(context.Background(), time.Second)
_, err := d.GetValue(ctx1, u.Key("test"))
2014-08-10 21:40:17 -07:00
if err != nil {
2014-09-18 19:30:04 -07:00
if err != context.DeadlineExceeded {
t.Fatal("Got different error than we expected", err)
}
} else {
t.Fatal("Did not get expected error!")
2014-08-10 21:40:17 -07:00
}
2014-09-18 19:30:04 -07:00
// u.POut("NotFound Test\n")
// Reply with failures to every message
2014-09-18 19:30:04 -07:00
fs.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
pmes := new(pb.Message)
2014-09-17 10:30:38 -07:00
err := proto.Unmarshal(mes.Data(), pmes)
if err != nil {
t.Fatal(err)
}
resp := &pb.Message{
2014-09-17 10:30:38 -07:00
Type: pmes.Type,
}
2014-09-17 10:30:38 -07:00
m, err := msg.FromObject(mes.Peer(), resp)
return m
})
// This one should fail with NotFound
ctx2, _ := context.WithTimeout(context.Background(), time.Second)
_, err = d.GetValue(ctx2, u.Key("test"))
if err != nil {
if err != routing.ErrNotFound {
t.Fatalf("Expected ErrNotFound, got: %s", err)
}
} else {
t.Fatal("expected error, got none.")
}
2014-09-18 19:30:04 -07:00
fs.handlers = nil
// Now we test this DHT's handleGetValue failure
typ := pb.Message_GET_VALUE
2014-09-17 10:30:38 -07:00
str := "hello"
rec, err := d.makePutRecord(u.Key(str), []byte("blah"))
if err != nil {
t.Fatal(err)
}
req := pb.Message{
Type: &typ,
Key: &str,
Record: rec,
}
2014-09-17 10:30:38 -07:00
2014-09-18 19:30:04 -07:00
// u.POut("handleGetValue Test\n")
2014-09-17 10:30:38 -07:00
mes, err := msg.FromObject(other, &req)
if err != nil {
t.Error(err)
}
mes = d.HandleMessage(ctx, mes)
pmes := new(pb.Message)
2014-09-18 19:30:04 -07:00
err = proto.Unmarshal(mes.Data(), pmes)
if err != nil {
t.Fatal(err)
}
if pmes.GetRecord() != nil {
2014-09-18 19:30:04 -07:00
t.Fatal("shouldnt have value")
}
if pmes.GetProviderPeers() != nil {
t.Fatal("shouldnt have provider peers")
}
2014-08-10 21:40:17 -07:00
}
2014-08-19 19:14:52 -07:00
// TODO: Maybe put these in some sort of "ipfs_testutil" package
func _randPeer() peer.Peer {
id := make(peer.ID, 16)
crand.Read(id)
p := peer.WithID(id)
2014-08-19 19:14:52 -07:00
return p
}
func TestNotFound(t *testing.T) {
if testing.Short() {
t.SkipNow()
}
2014-09-19 18:11:05 -07:00
2014-10-18 04:19:12 -07:00
ctx := context.Background()
2014-09-17 10:30:38 -07:00
fn := &fauxNet{}
fs := &fauxSender{}
2014-08-19 19:14:52 -07:00
local := makePeer(nil)
2014-09-17 10:30:38 -07:00
peerstore := peer.NewPeerstore()
peerstore.Add(local)
2014-08-19 19:14:52 -07:00
2014-10-18 04:19:12 -07:00
d := NewDHT(ctx, local, peerstore, fn, fs, ds.NewMapDatastore())
2014-08-19 19:14:52 -07:00
var ps []peer.Peer
2014-08-19 19:14:52 -07:00
for i := 0; i < 5; i++ {
ps = append(ps, _randPeer())
d.Update(ctx, ps[i])
2014-08-19 19:14:52 -07:00
}
// Reply with random peers to every message
2014-09-18 19:30:04 -07:00
fs.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
pmes := new(pb.Message)
2014-09-17 10:30:38 -07:00
err := proto.Unmarshal(mes.Data(), pmes)
2014-08-19 19:14:52 -07:00
if err != nil {
t.Fatal(err)
}
switch pmes.GetType() {
case pb.Message_GET_VALUE:
resp := &pb.Message{Type: pmes.Type}
2014-08-19 19:14:52 -07:00
peers := []peer.Peer{}
2014-08-19 19:14:52 -07:00
for i := 0; i < 7; i++ {
2014-09-17 10:30:38 -07:00
peers = append(peers, _randPeer())
}
resp.CloserPeers = pb.PeersToPBPeers(peers)
2014-09-17 10:30:38 -07:00
mes, err := msg.FromObject(mes.Peer(), resp)
if err != nil {
t.Error(err)
2014-08-19 19:14:52 -07:00
}
2014-09-17 10:30:38 -07:00
return mes
2014-08-19 19:14:52 -07:00
default:
panic("Shouldnt recieve this.")
}
})
2014-10-18 04:19:12 -07:00
ctx, _ = context.WithTimeout(ctx, time.Second*5)
v, err := d.GetValue(ctx, u.Key("hello"))
2014-10-30 06:35:29 -07:00
log.Debugf("get value got %v", v)
2014-08-19 19:14:52 -07:00
if err != nil {
switch err {
case routing.ErrNotFound:
2014-08-19 19:14:52 -07:00
//Success!
return
case u.ErrTimeout:
t.Fatal("Should not have gotten timeout!")
default:
t.Fatalf("Got unexpected error: %s", err)
}
}
t.Fatal("Expected to recieve an error.")
}
// If less than K nodes are in the entire network, it should fail when we make
// a GET rpc and nobody has the value
func TestLessThanKResponses(t *testing.T) {
2014-09-19 18:11:05 -07:00
// t.Skip("skipping test because it makes a lot of output")
2014-10-18 04:19:12 -07:00
ctx := context.Background()
u.Debug = false
2014-09-17 10:30:38 -07:00
fn := &fauxNet{}
fs := &fauxSender{}
local := makePeer(nil)
2014-09-17 10:30:38 -07:00
peerstore := peer.NewPeerstore()
peerstore.Add(local)
2014-10-18 04:19:12 -07:00
d := NewDHT(ctx, local, peerstore, fn, fs, ds.NewMapDatastore())
var ps []peer.Peer
for i := 0; i < 5; i++ {
ps = append(ps, _randPeer())
d.Update(ctx, ps[i])
}
other := _randPeer()
// Reply with random peers to every message
2014-09-18 19:30:04 -07:00
fs.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
pmes := new(pb.Message)
2014-09-17 10:30:38 -07:00
err := proto.Unmarshal(mes.Data(), pmes)
if err != nil {
t.Fatal(err)
}
switch pmes.GetType() {
case pb.Message_GET_VALUE:
resp := &pb.Message{
2014-09-17 10:30:38 -07:00
Type: pmes.Type,
CloserPeers: pb.PeersToPBPeers([]peer.Peer{other}),
}
2014-09-17 10:30:38 -07:00
mes, err := msg.FromObject(mes.Peer(), resp)
if err != nil {
t.Error(err)
}
return mes
default:
panic("Shouldnt recieve this.")
}
})
2014-10-18 04:19:12 -07:00
ctx, _ = context.WithTimeout(ctx, time.Second*30)
_, err := d.GetValue(ctx, u.Key("hello"))
if err != nil {
switch err {
case routing.ErrNotFound:
//Success!
return
case u.ErrTimeout:
t.Fatal("Should not have gotten timeout!")
default:
t.Fatalf("Got unexpected error: %s", err)
}
}
t.Fatal("Expected to recieve an error.")
}