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 }