2014-08-10 21:40:17 -07:00
|
|
|
package dht
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
2014-08-11 09:06:20 -07:00
|
|
|
"code.google.com/p/goprotobuf/proto"
|
|
|
|
|
2014-08-10 21:40:17 -07:00
|
|
|
peer "github.com/jbenet/go-ipfs/peer"
|
|
|
|
swarm "github.com/jbenet/go-ipfs/swarm"
|
2014-08-11 09:06:20 -07:00
|
|
|
u "github.com/jbenet/go-ipfs/util"
|
|
|
|
ma "github.com/jbenet/go-multiaddr"
|
2014-08-10 21:40:17 -07:00
|
|
|
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
// fauxNet is a standin for a swarm.Network in order to more easily recreate
|
|
|
|
// different testing scenarios
|
|
|
|
type fauxNet struct {
|
2014-08-11 20:11:23 -07:00
|
|
|
Chan *swarm.Chan
|
|
|
|
handlers []mesHandleFunc
|
2014-08-10 21:40:17 -07:00
|
|
|
|
|
|
|
swarm.Network
|
|
|
|
}
|
|
|
|
|
2014-08-11 20:11:23 -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
|
2014-08-10 21:40:17 -07:00
|
|
|
type mesHandleFunc func(*swarm.Message) *swarm.Message
|
|
|
|
|
|
|
|
func newFauxNet() *fauxNet {
|
|
|
|
fn := new(fauxNet)
|
|
|
|
fn.Chan = swarm.NewChan(8)
|
|
|
|
|
|
|
|
return fn
|
|
|
|
}
|
|
|
|
|
2014-08-11 20:11:23 -07:00
|
|
|
// Instead of 'Listening' Start up a goroutine that will check
|
|
|
|
// all outgoing messages against registered message handlers,
|
|
|
|
// and reply if needed
|
2014-08-10 21:40:17 -07:00
|
|
|
func (f *fauxNet) Listen() error {
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case in := <-f.Chan.Outgoing:
|
2014-08-11 09:06:20 -07:00
|
|
|
for _, h := range f.handlers {
|
2014-08-10 21:40:17 -07:00
|
|
|
reply := h(in)
|
|
|
|
if reply != nil {
|
|
|
|
f.Chan.Incoming <- reply
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fauxNet) AddHandler(fn func(*swarm.Message) *swarm.Message) {
|
|
|
|
f.handlers = append(f.handlers, fn)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *fauxNet) Send(mes *swarm.Message) {
|
2014-08-11 09:06:20 -07:00
|
|
|
f.Chan.Outgoing <- mes
|
|
|
|
}
|
2014-08-10 21:40:17 -07:00
|
|
|
|
2014-08-11 09:06:20 -07:00
|
|
|
func (f *fauxNet) GetChan() *swarm.Chan {
|
|
|
|
return f.Chan
|
2014-08-10 21:40:17 -07:00
|
|
|
}
|
|
|
|
|
2014-08-11 09:06:20 -07:00
|
|
|
func (f *fauxNet) Connect(addr *ma.Multiaddr) (*peer.Peer, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetFailures(t *testing.T) {
|
2014-08-10 21:40:17 -07:00
|
|
|
fn := newFauxNet()
|
|
|
|
fn.Listen()
|
|
|
|
|
|
|
|
local := new(peer.Peer)
|
2014-08-11 09:06:20 -07:00
|
|
|
local.ID = peer.ID("test_peer")
|
2014-08-10 21:40:17 -07:00
|
|
|
|
|
|
|
d := NewDHT(local, fn)
|
|
|
|
|
2014-08-11 09:06:20 -07:00
|
|
|
other := &peer.Peer{ID: peer.ID("other_peer")}
|
|
|
|
|
2014-08-10 21:40:17 -07:00
|
|
|
d.Start()
|
|
|
|
|
2014-08-11 09:06:20 -07:00
|
|
|
d.Update(other)
|
|
|
|
|
|
|
|
// This one should time out
|
2014-08-15 09:39:38 -07:00
|
|
|
_, err := d.GetValue(u.Key("test"), time.Millisecond*10)
|
2014-08-10 21:40:17 -07:00
|
|
|
if err != nil {
|
2014-08-15 09:39:38 -07:00
|
|
|
if err != u.ErrTimeout {
|
2014-08-11 09:06:20 -07:00
|
|
|
t.Fatal("Got different error than we expected.")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
t.Fatal("Did not get expected error!")
|
2014-08-10 21:40:17 -07:00
|
|
|
}
|
|
|
|
|
2014-08-11 20:11:23 -07:00
|
|
|
// Reply with failures to every message
|
2014-08-11 09:06:20 -07:00
|
|
|
fn.AddHandler(func(mes *swarm.Message) *swarm.Message {
|
|
|
|
pmes := new(PBDHTMessage)
|
|
|
|
err := proto.Unmarshal(mes.Data, pmes)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2014-08-16 23:48:03 -07:00
|
|
|
resp := Message{
|
2014-08-11 09:06:20 -07:00
|
|
|
Type: pmes.GetType(),
|
2014-08-16 23:48:03 -07:00
|
|
|
ID: pmes.GetId(),
|
2014-08-11 09:06:20 -07:00
|
|
|
Response: true,
|
|
|
|
Success: false,
|
|
|
|
}
|
|
|
|
return swarm.NewMessage(mes.Peer, resp.ToProtobuf())
|
|
|
|
})
|
|
|
|
|
|
|
|
// This one should fail with NotFound
|
2014-08-15 09:39:38 -07:00
|
|
|
_, err = d.GetValue(u.Key("test"), time.Millisecond*1000)
|
2014-08-11 09:06:20 -07:00
|
|
|
if err != nil {
|
|
|
|
if err != u.ErrNotFound {
|
2014-08-15 09:39:38 -07:00
|
|
|
t.Fatalf("Expected ErrNotFound, got: %s", err)
|
2014-08-11 09:06:20 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
t.Fatal("expected error, got none.")
|
|
|
|
}
|
2014-08-11 20:11:23 -07:00
|
|
|
|
|
|
|
success := make(chan struct{})
|
|
|
|
fn.handlers = nil
|
|
|
|
fn.AddHandler(func(mes *swarm.Message) *swarm.Message {
|
|
|
|
resp := new(PBDHTMessage)
|
|
|
|
err := proto.Unmarshal(mes.Data, resp)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if resp.GetSuccess() {
|
|
|
|
t.Fatal("Get returned success when it shouldnt have.")
|
|
|
|
}
|
|
|
|
success <- struct{}{}
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
// Now we test this DHT's handleGetValue failure
|
2014-08-16 23:48:03 -07:00
|
|
|
req := Message{
|
2014-08-11 20:11:23 -07:00
|
|
|
Type: PBDHTMessage_GET_VALUE,
|
|
|
|
Key: "hello",
|
2014-08-16 23:48:03 -07:00
|
|
|
ID: GenerateMessageID(),
|
2014-08-11 20:11:23 -07:00
|
|
|
Value: []byte{0},
|
|
|
|
}
|
|
|
|
fn.Chan.Incoming <- swarm.NewMessage(other, req.ToProtobuf())
|
|
|
|
|
|
|
|
<-success
|
2014-08-10 21:40:17 -07:00
|
|
|
}
|