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  }