github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/p2p/test/reconnects/reconnect_test.go (about) 1 package reconnect 2 3 import ( 4 "io" 5 "math/rand" 6 "sync" 7 "testing" 8 "time" 9 10 host "github.com/ipfs/go-ipfs/p2p/host" 11 inet "github.com/ipfs/go-ipfs/p2p/net" 12 swarm "github.com/ipfs/go-ipfs/p2p/net/swarm" 13 protocol "github.com/ipfs/go-ipfs/p2p/protocol" 14 testutil "github.com/ipfs/go-ipfs/p2p/test/util" 15 eventlog "github.com/ipfs/go-ipfs/thirdparty/eventlog" 16 u "github.com/ipfs/go-ipfs/util" 17 18 ps "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-peerstream" 19 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 20 ) 21 22 func init() { 23 // change the garbage collect timeout for testing. 24 ps.GarbageCollectTimeout = 10 * time.Millisecond 25 } 26 27 var log = eventlog.Logger("reconnect") 28 29 func EchoStreamHandler(stream inet.Stream) { 30 c := stream.Conn() 31 log.Debugf("%s echoing %s", c.LocalPeer(), c.RemotePeer()) 32 go func() { 33 defer stream.Close() 34 io.Copy(stream, stream) 35 }() 36 } 37 38 type sendChans struct { 39 send chan struct{} 40 sent chan struct{} 41 read chan struct{} 42 close_ chan struct{} 43 closed chan struct{} 44 } 45 46 func newSendChans() sendChans { 47 return sendChans{ 48 send: make(chan struct{}), 49 sent: make(chan struct{}), 50 read: make(chan struct{}), 51 close_: make(chan struct{}), 52 closed: make(chan struct{}), 53 } 54 } 55 56 func newSender() (chan sendChans, func(s inet.Stream)) { 57 scc := make(chan sendChans) 58 return scc, func(s inet.Stream) { 59 sc := newSendChans() 60 scc <- sc 61 62 defer func() { 63 s.Close() 64 sc.closed <- struct{}{} 65 }() 66 67 buf := make([]byte, 65536) 68 buf2 := make([]byte, 65536) 69 u.NewTimeSeededRand().Read(buf) 70 71 for { 72 select { 73 case <-sc.close_: 74 return 75 case <-sc.send: 76 } 77 78 // send a randomly sized subchunk 79 from := rand.Intn(len(buf) / 2) 80 to := rand.Intn(len(buf) / 2) 81 sendbuf := buf[from : from+to] 82 83 log.Debugf("sender sending %d bytes", len(sendbuf)) 84 n, err := s.Write(sendbuf) 85 if err != nil { 86 log.Debug("sender error. exiting:", err) 87 return 88 } 89 90 log.Debugf("sender wrote %d bytes", n) 91 sc.sent <- struct{}{} 92 93 if n, err = io.ReadFull(s, buf2[:len(sendbuf)]); err != nil { 94 log.Debug("sender error. failed to read:", err) 95 return 96 } 97 98 log.Debugf("sender read %d bytes", n) 99 sc.read <- struct{}{} 100 } 101 } 102 } 103 104 // TestReconnect tests whether hosts are able to disconnect and reconnect. 105 func TestReconnect2(t *testing.T) { 106 ctx := context.Background() 107 h1 := testutil.GenHostSwarm(t, ctx) 108 h2 := testutil.GenHostSwarm(t, ctx) 109 hosts := []host.Host{h1, h2} 110 111 h1.SetStreamHandler(protocol.TestingID, EchoStreamHandler) 112 h2.SetStreamHandler(protocol.TestingID, EchoStreamHandler) 113 114 rounds := 8 115 if testing.Short() { 116 rounds = 4 117 } 118 for i := 0; i < rounds; i++ { 119 log.Debugf("TestReconnect: %d/%d\n", i, rounds) 120 SubtestConnSendDisc(t, hosts) 121 } 122 } 123 124 // TestReconnect tests whether hosts are able to disconnect and reconnect. 125 func TestReconnect5(t *testing.T) { 126 ctx := context.Background() 127 h1 := testutil.GenHostSwarm(t, ctx) 128 h2 := testutil.GenHostSwarm(t, ctx) 129 h3 := testutil.GenHostSwarm(t, ctx) 130 h4 := testutil.GenHostSwarm(t, ctx) 131 h5 := testutil.GenHostSwarm(t, ctx) 132 hosts := []host.Host{h1, h2, h3, h4, h5} 133 134 h1.SetStreamHandler(protocol.TestingID, EchoStreamHandler) 135 h2.SetStreamHandler(protocol.TestingID, EchoStreamHandler) 136 h3.SetStreamHandler(protocol.TestingID, EchoStreamHandler) 137 h4.SetStreamHandler(protocol.TestingID, EchoStreamHandler) 138 h5.SetStreamHandler(protocol.TestingID, EchoStreamHandler) 139 140 rounds := 4 141 if testing.Short() { 142 rounds = 2 143 } 144 for i := 0; i < rounds; i++ { 145 log.Debugf("TestReconnect: %d/%d\n", i, rounds) 146 SubtestConnSendDisc(t, hosts) 147 } 148 } 149 150 func SubtestConnSendDisc(t *testing.T, hosts []host.Host) { 151 152 ctx := context.Background() 153 numStreams := 3 * len(hosts) 154 numMsgs := 10 155 156 if testing.Short() { 157 numStreams = 5 * len(hosts) 158 numMsgs = 4 159 } 160 161 ss, sF := newSender() 162 163 for _, h1 := range hosts { 164 for _, h2 := range hosts { 165 if h1.ID() >= h2.ID() { 166 continue 167 } 168 169 h2pi := h2.Peerstore().PeerInfo(h2.ID()) 170 log.Debugf("dialing %s", h2pi.Addrs) 171 if err := h1.Connect(ctx, h2pi); err != nil { 172 t.Fatalf("Failed to connect:", err) 173 } 174 } 175 } 176 177 var wg sync.WaitGroup 178 for i := 0; i < numStreams; i++ { 179 h1 := hosts[i%len(hosts)] 180 h2 := hosts[(i+1)%len(hosts)] 181 s, err := h1.NewStream(protocol.TestingID, h2.ID()) 182 if err != nil { 183 t.Error(err) 184 } 185 186 wg.Add(1) 187 go func(j int) { 188 defer wg.Done() 189 190 go sF(s) 191 log.Debugf("getting handle %d", j) 192 sc := <-ss // wait to get handle. 193 log.Debugf("spawning worker %d", j) 194 195 for k := 0; k < numMsgs; k++ { 196 sc.send <- struct{}{} 197 <-sc.sent 198 log.Debugf("%d sent %d", j, k) 199 <-sc.read 200 log.Debugf("%d read %d", j, k) 201 } 202 sc.close_ <- struct{}{} 203 <-sc.closed 204 log.Debugf("closed %d", j) 205 }(i) 206 } 207 wg.Wait() 208 209 for i, h1 := range hosts { 210 log.Debugf("host %d has %d conns", i, len(h1.Network().Conns())) 211 } 212 213 for _, h1 := range hosts { 214 // close connection 215 cs := h1.Network().Conns() 216 for _, c := range cs { 217 sc := c.(*swarm.Conn) 218 if sc.LocalPeer() > sc.RemotePeer() { 219 continue // only close it on one side. 220 } 221 222 log.Debugf("closing: %s", sc.RawConn()) 223 sc.Close() 224 } 225 } 226 227 <-time.After(20 * time.Millisecond) 228 229 for i, h := range hosts { 230 if len(h.Network().Conns()) > 0 { 231 t.Fatalf("host %d %s has %d conns! not zero.", i, h.ID(), len(h.Network().Conns())) 232 } 233 } 234 }