github.com/zignig/go-ipfs@v0.0.0-20141111235910-c9e5fdf55a52/routing/dht/ext_test.go (about)

     1  package dht
     2  
     3  import (
     4  	"testing"
     5  
     6  	crand "crypto/rand"
     7  	context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
     8  	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
     9  
    10  	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
    11  	msg "github.com/jbenet/go-ipfs/net/message"
    12  	mux "github.com/jbenet/go-ipfs/net/mux"
    13  	peer "github.com/jbenet/go-ipfs/peer"
    14  	"github.com/jbenet/go-ipfs/routing"
    15  	pb "github.com/jbenet/go-ipfs/routing/dht/pb"
    16  	u "github.com/jbenet/go-ipfs/util"
    17  
    18  	"sync"
    19  	"time"
    20  )
    21  
    22  // mesHandleFunc is a function that takes in outgoing messages
    23  // and can respond to them, simulating other peers on the network.
    24  // returning nil will chose not to respond and pass the message onto the
    25  // next registered handler
    26  type mesHandleFunc func(msg.NetMessage) msg.NetMessage
    27  
    28  // fauxNet is a standin for a swarm.Network in order to more easily recreate
    29  // different testing scenarios
    30  type fauxSender struct {
    31  	sync.Mutex
    32  	handlers []mesHandleFunc
    33  }
    34  
    35  func (f *fauxSender) AddHandler(fn func(msg.NetMessage) msg.NetMessage) {
    36  	f.Lock()
    37  	defer f.Unlock()
    38  
    39  	f.handlers = append(f.handlers, fn)
    40  }
    41  
    42  func (f *fauxSender) SendRequest(ctx context.Context, m msg.NetMessage) (msg.NetMessage, error) {
    43  	f.Lock()
    44  	handlers := make([]mesHandleFunc, len(f.handlers))
    45  	copy(handlers, f.handlers)
    46  	f.Unlock()
    47  
    48  	for _, h := range handlers {
    49  		reply := h(m)
    50  		if reply != nil {
    51  			return reply, nil
    52  		}
    53  	}
    54  
    55  	// no reply? ok force a timeout
    56  	select {
    57  	case <-ctx.Done():
    58  	}
    59  
    60  	return nil, ctx.Err()
    61  }
    62  
    63  func (f *fauxSender) SendMessage(ctx context.Context, m msg.NetMessage) error {
    64  	f.Lock()
    65  	handlers := make([]mesHandleFunc, len(f.handlers))
    66  	copy(handlers, f.handlers)
    67  	f.Unlock()
    68  
    69  	for _, h := range handlers {
    70  		reply := h(m)
    71  		if reply != nil {
    72  			return nil
    73  		}
    74  	}
    75  	return nil
    76  }
    77  
    78  // fauxNet is a standin for a swarm.Network in order to more easily recreate
    79  // different testing scenarios
    80  type fauxNet struct {
    81  }
    82  
    83  // DialPeer attempts to establish a connection to a given peer
    84  func (f *fauxNet) DialPeer(context.Context, peer.Peer) error {
    85  	return nil
    86  }
    87  
    88  // ClosePeer connection to peer
    89  func (f *fauxNet) ClosePeer(peer.Peer) error {
    90  	return nil
    91  }
    92  
    93  // IsConnected returns whether a connection to given peer exists.
    94  func (f *fauxNet) IsConnected(peer.Peer) (bool, error) {
    95  	return true, nil
    96  }
    97  
    98  // GetProtocols returns the protocols registered in the network.
    99  func (f *fauxNet) GetProtocols() *mux.ProtocolMap { return nil }
   100  
   101  // SendMessage sends given Message out
   102  func (f *fauxNet) SendMessage(msg.NetMessage) error {
   103  	return nil
   104  }
   105  
   106  func (f *fauxNet) GetPeerList() []peer.Peer {
   107  	return nil
   108  }
   109  
   110  func (f *fauxNet) GetBandwidthTotals() (uint64, uint64) {
   111  	return 0, 0
   112  }
   113  
   114  // Close terminates all network operation
   115  func (f *fauxNet) Close() error { return nil }
   116  
   117  func TestGetFailures(t *testing.T) {
   118  	// t.Skip("skipping test because it makes a lot of output")
   119  
   120  	ctx := context.Background()
   121  	fn := &fauxNet{}
   122  	fs := &fauxSender{}
   123  
   124  	peerstore := peer.NewPeerstore()
   125  	local := peer.WithIDString("test_peer")
   126  
   127  	d := NewDHT(ctx, local, peerstore, fn, fs, ds.NewMapDatastore())
   128  	other := peer.WithIDString("other_peer")
   129  	d.Update(other)
   130  
   131  	// This one should time out
   132  	// u.POut("Timout Test\n")
   133  	ctx1, _ := context.WithTimeout(context.Background(), time.Second)
   134  	_, err := d.GetValue(ctx1, u.Key("test"))
   135  	if err != nil {
   136  		if err != context.DeadlineExceeded {
   137  			t.Fatal("Got different error than we expected", err)
   138  		}
   139  	} else {
   140  		t.Fatal("Did not get expected error!")
   141  	}
   142  
   143  	// u.POut("NotFound Test\n")
   144  	// Reply with failures to every message
   145  	fs.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
   146  		pmes := new(pb.Message)
   147  		err := proto.Unmarshal(mes.Data(), pmes)
   148  		if err != nil {
   149  			t.Fatal(err)
   150  		}
   151  
   152  		resp := &pb.Message{
   153  			Type: pmes.Type,
   154  		}
   155  		m, err := msg.FromObject(mes.Peer(), resp)
   156  		return m
   157  	})
   158  
   159  	// This one should fail with NotFound
   160  	ctx2, _ := context.WithTimeout(context.Background(), time.Second)
   161  	_, err = d.GetValue(ctx2, u.Key("test"))
   162  	if err != nil {
   163  		if err != routing.ErrNotFound {
   164  			t.Fatalf("Expected ErrNotFound, got: %s", err)
   165  		}
   166  	} else {
   167  		t.Fatal("expected error, got none.")
   168  	}
   169  
   170  	fs.handlers = nil
   171  	// Now we test this DHT's handleGetValue failure
   172  	typ := pb.Message_GET_VALUE
   173  	str := "hello"
   174  	req := pb.Message{
   175  		Type:  &typ,
   176  		Key:   &str,
   177  		Value: []byte{0},
   178  	}
   179  
   180  	// u.POut("handleGetValue Test\n")
   181  	mes, err := msg.FromObject(other, &req)
   182  	if err != nil {
   183  		t.Error(err)
   184  	}
   185  
   186  	mes = d.HandleMessage(ctx, mes)
   187  
   188  	pmes := new(pb.Message)
   189  	err = proto.Unmarshal(mes.Data(), pmes)
   190  	if err != nil {
   191  		t.Fatal(err)
   192  	}
   193  	if pmes.GetValue() != nil {
   194  		t.Fatal("shouldnt have value")
   195  	}
   196  	if pmes.GetCloserPeers() != nil {
   197  		t.Fatal("shouldnt have closer peers")
   198  	}
   199  	if pmes.GetProviderPeers() != nil {
   200  		t.Fatal("shouldnt have provider peers")
   201  	}
   202  
   203  }
   204  
   205  // TODO: Maybe put these in some sort of "ipfs_testutil" package
   206  func _randPeer() peer.Peer {
   207  	id := make(peer.ID, 16)
   208  	crand.Read(id)
   209  	p := peer.WithID(id)
   210  	return p
   211  }
   212  
   213  func TestNotFound(t *testing.T) {
   214  	// t.Skip("skipping test because it makes a lot of output")
   215  
   216  	ctx := context.Background()
   217  	fn := &fauxNet{}
   218  	fs := &fauxSender{}
   219  
   220  	local := peer.WithIDString("test_peer")
   221  	peerstore := peer.NewPeerstore()
   222  	peerstore.Add(local)
   223  
   224  	d := NewDHT(ctx, local, peerstore, fn, fs, ds.NewMapDatastore())
   225  
   226  	var ps []peer.Peer
   227  	for i := 0; i < 5; i++ {
   228  		ps = append(ps, _randPeer())
   229  		d.Update(ps[i])
   230  	}
   231  
   232  	// Reply with random peers to every message
   233  	fs.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
   234  		pmes := new(pb.Message)
   235  		err := proto.Unmarshal(mes.Data(), pmes)
   236  		if err != nil {
   237  			t.Fatal(err)
   238  		}
   239  
   240  		switch pmes.GetType() {
   241  		case pb.Message_GET_VALUE:
   242  			resp := &pb.Message{Type: pmes.Type}
   243  
   244  			peers := []peer.Peer{}
   245  			for i := 0; i < 7; i++ {
   246  				peers = append(peers, _randPeer())
   247  			}
   248  			resp.CloserPeers = pb.PeersToPBPeers(peers)
   249  			mes, err := msg.FromObject(mes.Peer(), resp)
   250  			if err != nil {
   251  				t.Error(err)
   252  			}
   253  			return mes
   254  		default:
   255  			panic("Shouldnt recieve this.")
   256  		}
   257  
   258  	})
   259  
   260  	ctx, _ = context.WithTimeout(ctx, time.Second*5)
   261  	v, err := d.GetValue(ctx, u.Key("hello"))
   262  	log.Debugf("get value got %v", v)
   263  	if err != nil {
   264  		switch err {
   265  		case routing.ErrNotFound:
   266  			//Success!
   267  			return
   268  		case u.ErrTimeout:
   269  			t.Fatal("Should not have gotten timeout!")
   270  		default:
   271  			t.Fatalf("Got unexpected error: %s", err)
   272  		}
   273  	}
   274  	t.Fatal("Expected to recieve an error.")
   275  }
   276  
   277  // If less than K nodes are in the entire network, it should fail when we make
   278  // a GET rpc and nobody has the value
   279  func TestLessThanKResponses(t *testing.T) {
   280  	// t.Skip("skipping test because it makes a lot of output")
   281  
   282  	ctx := context.Background()
   283  	u.Debug = false
   284  	fn := &fauxNet{}
   285  	fs := &fauxSender{}
   286  	local := peer.WithIDString("test_peer")
   287  	peerstore := peer.NewPeerstore()
   288  	peerstore.Add(local)
   289  
   290  	d := NewDHT(ctx, local, peerstore, fn, fs, ds.NewMapDatastore())
   291  
   292  	var ps []peer.Peer
   293  	for i := 0; i < 5; i++ {
   294  		ps = append(ps, _randPeer())
   295  		d.Update(ps[i])
   296  	}
   297  	other := _randPeer()
   298  
   299  	// Reply with random peers to every message
   300  	fs.AddHandler(func(mes msg.NetMessage) msg.NetMessage {
   301  		pmes := new(pb.Message)
   302  		err := proto.Unmarshal(mes.Data(), pmes)
   303  		if err != nil {
   304  			t.Fatal(err)
   305  		}
   306  
   307  		switch pmes.GetType() {
   308  		case pb.Message_GET_VALUE:
   309  			resp := &pb.Message{
   310  				Type:        pmes.Type,
   311  				CloserPeers: pb.PeersToPBPeers([]peer.Peer{other}),
   312  			}
   313  
   314  			mes, err := msg.FromObject(mes.Peer(), resp)
   315  			if err != nil {
   316  				t.Error(err)
   317  			}
   318  			return mes
   319  		default:
   320  			panic("Shouldnt recieve this.")
   321  		}
   322  
   323  	})
   324  
   325  	ctx, _ = context.WithTimeout(ctx, time.Second*30)
   326  	_, err := d.GetValue(ctx, u.Key("hello"))
   327  	if err != nil {
   328  		switch err {
   329  		case routing.ErrNotFound:
   330  			//Success!
   331  			return
   332  		case u.ErrTimeout:
   333  			t.Fatal("Should not have gotten timeout!")
   334  		default:
   335  			t.Fatalf("Got unexpected error: %s", err)
   336  		}
   337  	}
   338  	t.Fatal("Expected to recieve an error.")
   339  }