Commit 616f7760 authored by Jeromy's avatar Jeromy Committed by Brian Tiger Chow

implement a mock dht for use in testing

parent 022bf05e
......@@ -16,6 +16,7 @@ import (
strategy "github.com/jbenet/go-ipfs/exchange/bitswap/strategy"
tn "github.com/jbenet/go-ipfs/exchange/bitswap/testnet"
peer "github.com/jbenet/go-ipfs/peer"
mock "github.com/jbenet/go-ipfs/routing/mock"
util "github.com/jbenet/go-ipfs/util"
testutil "github.com/jbenet/go-ipfs/util/testutil"
)
......@@ -23,7 +24,7 @@ import (
func TestGetBlockTimeout(t *testing.T) {
net := tn.VirtualNetwork()
rs := tn.VirtualRoutingServer()
rs := mock.VirtualRoutingServer()
g := NewSessionGenerator(net, rs)
self := g.Next()
......@@ -40,7 +41,7 @@ func TestGetBlockTimeout(t *testing.T) {
func TestProviderForKeyButNetworkCannotFind(t *testing.T) {
net := tn.VirtualNetwork()
rs := tn.VirtualRoutingServer()
rs := mock.VirtualRoutingServer()
g := NewSessionGenerator(net, rs)
block := testutil.NewBlockOrFail(t, "block")
......@@ -61,7 +62,7 @@ func TestProviderForKeyButNetworkCannotFind(t *testing.T) {
func TestGetBlockFromPeerAfterPeerAnnounces(t *testing.T) {
net := tn.VirtualNetwork()
rs := tn.VirtualRoutingServer()
rs := mock.VirtualRoutingServer()
block := testutil.NewBlockOrFail(t, "block")
g := NewSessionGenerator(net, rs)
......@@ -90,7 +91,7 @@ func TestGetBlockFromPeerAfterPeerAnnounces(t *testing.T) {
func TestSwarm(t *testing.T) {
net := tn.VirtualNetwork()
rs := tn.VirtualRoutingServer()
rs := mock.VirtualRoutingServer()
sg := NewSessionGenerator(net, rs)
bg := NewBlockGenerator(t)
......@@ -151,7 +152,7 @@ func TestSendToWantingPeer(t *testing.T) {
util.Debug = true
net := tn.VirtualNetwork()
rs := tn.VirtualRoutingServer()
rs := mock.VirtualRoutingServer()
sg := NewSessionGenerator(net, rs)
bg := NewBlockGenerator(t)
......@@ -237,7 +238,7 @@ func (bg *BlockGenerator) Blocks(n int) []*blocks.Block {
}
func NewSessionGenerator(
net tn.Network, rs tn.RoutingServer) SessionGenerator {
net tn.Network, rs mock.RoutingServer) SessionGenerator {
return SessionGenerator{
net: net,
rs: rs,
......@@ -248,7 +249,7 @@ func NewSessionGenerator(
type SessionGenerator struct {
seq int
net tn.Network
rs tn.RoutingServer
rs mock.RoutingServer
}
func (g *SessionGenerator) Next() instance {
......@@ -276,11 +277,12 @@ type instance struct {
// NB: It's easy make mistakes by providing the same peer ID to two different
// sessions. To safeguard, use the SessionGenerator to generate sessions. It's
// just a much better idea.
func session(net tn.Network, rs tn.RoutingServer, id peer.ID) instance {
func session(net tn.Network, rs mock.RoutingServer, id peer.ID) instance {
p := &peer.Peer{ID: id}
adapter := net.Adapter(p)
htc := rs.Client(p)
htc := mock.NewMockRouter(p, nil)
htc.SetRoutingServer(rs)
blockstore := bstore.NewBlockstore(ds.NewMapDatastore())
const alwaysSendToPeer = true
......
package bitswap
import (
"math/rand"
"sync"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
bsnet "github.com/jbenet/go-ipfs/exchange/bitswap/network"
peer "github.com/jbenet/go-ipfs/peer"
u "github.com/jbenet/go-ipfs/util"
)
type RoutingServer interface {
Announce(*peer.Peer, u.Key) error
Providers(u.Key) []*peer.Peer
// Returns a Routing instance configured to query this hash table
Client(*peer.Peer) bsnet.Routing
}
func VirtualRoutingServer() RoutingServer {
return &hashTable{
providers: make(map[u.Key]peer.Map),
}
}
type hashTable struct {
lock sync.RWMutex
providers map[u.Key]peer.Map
}
func (rs *hashTable) Announce(p *peer.Peer, k u.Key) error {
rs.lock.Lock()
defer rs.lock.Unlock()
_, ok := rs.providers[k]
if !ok {
rs.providers[k] = make(peer.Map)
}
rs.providers[k][p.Key()] = p
return nil
}
func (rs *hashTable) Providers(k u.Key) []*peer.Peer {
rs.lock.RLock()
defer rs.lock.RUnlock()
ret := make([]*peer.Peer, 0)
peerset, ok := rs.providers[k]
if !ok {
return ret
}
for _, peer := range peerset {
ret = append(ret, peer)
}
for i := range ret {
j := rand.Intn(i + 1)
ret[i], ret[j] = ret[j], ret[i]
}
return ret
}
func (rs *hashTable) Client(p *peer.Peer) bsnet.Routing {
return &routingClient{
peer: p,
hashTable: rs,
}
}
type routingClient struct {
peer *peer.Peer
hashTable RoutingServer
}
func (a *routingClient) FindProvidersAsync(ctx context.Context, k u.Key, max int) <-chan *peer.Peer {
out := make(chan *peer.Peer)
go func() {
defer close(out)
for i, p := range a.hashTable.Providers(k) {
if max <= i {
return
}
select {
case out <- p:
case <-ctx.Done():
return
}
}
}()
return out
}
func (a *routingClient) Provide(_ context.Context, key u.Key) error {
return a.hashTable.Announce(a.peer, key)
}
......@@ -5,19 +5,15 @@ import (
"testing"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
)
import (
"github.com/jbenet/go-ipfs/peer"
mock "github.com/jbenet/go-ipfs/routing/mock"
u "github.com/jbenet/go-ipfs/util"
)
func TestKeyNotFound(t *testing.T) {
rs := func() RoutingServer {
// TODO fields
return &hashTable{}
}()
empty := rs.Providers(u.Key("not there"))
vrs := mock.VirtualRoutingServer()
empty := vrs.Providers(u.Key("not there"))
if len(empty) != 0 {
t.Fatal("should be empty")
}
......@@ -29,7 +25,7 @@ func TestSetAndGet(t *testing.T) {
ID: pid,
}
k := u.Key("42")
rs := VirtualRoutingServer()
rs := mock.VirtualRoutingServer()
err := rs.Announce(p, k)
if err != nil {
t.Fatal(err)
......@@ -50,8 +46,9 @@ func TestClientFindProviders(t *testing.T) {
peer := &peer.Peer{
ID: []byte("42"),
}
rs := VirtualRoutingServer()
client := rs.Client(peer)
rs := mock.VirtualRoutingServer()
client := mock.NewMockRouter(peer, nil)
client.SetRoutingServer(rs)
k := u.Key("hello")
err := client.Provide(context.Background(), k)
if err != nil {
......@@ -83,7 +80,7 @@ func TestClientFindProviders(t *testing.T) {
}
func TestClientOverMax(t *testing.T) {
rs := VirtualRoutingServer()
rs := mock.VirtualRoutingServer()
k := u.Key("hello")
numProvidersForHelloKey := 100
for i := 0; i < numProvidersForHelloKey; i++ {
......@@ -102,7 +99,8 @@ func TestClientOverMax(t *testing.T) {
}
max := 10
client := rs.Client(&peer.Peer{ID: []byte("TODO")})
client := mock.NewMockRouter(&peer.Peer{ID: []byte("TODO")}, nil)
client.SetRoutingServer(rs)
providersFromClient := client.FindProvidersAsync(context.Background(), k, max)
i := 0
for _ = range providersFromClient {
......@@ -115,7 +113,7 @@ func TestClientOverMax(t *testing.T) {
// TODO does dht ensure won't receive self as a provider? probably not.
func TestCanceledContext(t *testing.T) {
rs := VirtualRoutingServer()
rs := mock.VirtualRoutingServer()
k := u.Key("hello")
t.Log("async'ly announce infinite stream of providers for key")
......@@ -133,7 +131,9 @@ func TestCanceledContext(t *testing.T) {
}
}()
client := rs.Client(&peer.Peer{ID: []byte("peer id doesn't matter")})
local := &peer.Peer{ID: []byte("peer id doesn't matter")}
client := mock.NewMockRouter(local, nil)
client.SetRoutingServer(rs)
t.Log("warning: max is finite so this test is non-deterministic")
t.Log("context cancellation could simply take lower priority")
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment