func ExampleEventLogger() { { log := EventLogger(nil) e := log.EventBegin(context.Background(), "dial") e.Done() } { log := EventLogger(nil) e := log.EventBegin(context.Background(), "dial") _ = e.Close() // implements io.Closer for convenience } }
func TestSecureClose(t *testing.T) { // t.Skip("Skipping in favor of another test") ctx := context.Background() c1, c2, p1, p2 := setupSingleConn(t, ctx) done := make(chan error) go secureHandshake(t, ctx, p1.PrivKey, c1, done) go secureHandshake(t, ctx, p2.PrivKey, c2, done) for i := 0; i < 2; i++ { if err := <-done; err != nil { t.Fatal(err) } } testOneSendRecv(t, c1, c2) c1.Close() testNotOneSendRecv(t, c1, c2) c2.Close() testNotOneSendRecv(t, c1, c2) testNotOneSendRecv(t, c2, c1) }
func TestFilterBounds(t *testing.T) { ctx := context.Background() swarms := makeSwarms(ctx, t, 2) conns := make(chan struct{}, 8) swarms[0].SetConnHandler(func(conn *Conn) { conns <- struct{}{} }) // Address that we wont be dialing from _, block, err := net.ParseCIDR("192.0.0.1/8") if err != nil { t.Fatal(err) } // set filter on both sides, shouldnt matter swarms[1].Filters.AddDialFilter(block) swarms[0].Filters.AddDialFilter(block) connectSwarms(t, ctx, swarms) select { case <-time.After(time.Second): t.Fatal("should have gotten connection") case <-conns: t.Log("got connect") } }
func TestDialBadAddrs(t *testing.T) { m := func(s string) ma.Multiaddr { maddr, err := ma.NewMultiaddr(s) if err != nil { t.Fatal(err) } return maddr } ctx := context.Background() s := makeSwarms(ctx, t, 1)[0] test := func(a ma.Multiaddr) { p := testutil.RandPeerIDFatal(t) s.peers.AddAddr(p, a, peer.PermanentAddrTTL) if _, err := s.Dial(ctx, p); err == nil { t.Error("swarm should not dial: %s", m) } } test(m("/ip6/fe80::1")) // link local test(m("/ip6/fe80::100")) // link local test(m("/ip4/127.0.0.1/udp/1234/utp")) // utp }
func TestAddrBlocking(t *testing.T) { ctx := context.Background() swarms := makeSwarms(ctx, t, 2) swarms[0].SetConnHandler(func(conn *Conn) { t.Fatal("no connections should happen!") }) _, block, err := net.ParseCIDR("127.0.0.1/8") if err != nil { t.Fatal(err) } swarms[1].Filters.AddDialFilter(block) swarms[1].peers.AddAddr(swarms[0].LocalPeer(), swarms[0].ListenAddresses()[0], peer.PermanentAddrTTL) _, err = swarms[1].Dial(ctx, swarms[0].LocalPeer()) if err == nil { t.Fatal("dial should have failed") } swarms[0].peers.AddAddr(swarms[1].LocalPeer(), swarms[1].ListenAddresses()[0], peer.PermanentAddrTTL) _, err = swarms[0].Dial(ctx, swarms[1].LocalPeer()) if err == nil { t.Fatal("dial should have failed") } }
func TestConnHandler(t *testing.T) { // t.Skip("skipping for another test") t.Parallel() ctx := context.Background() swarms := makeSwarms(ctx, t, 5) gotconn := make(chan struct{}, 10) swarms[0].SetConnHandler(func(conn *Conn) { gotconn <- struct{}{} }) connectSwarms(t, ctx, swarms) <-time.After(time.Millisecond) // should've gotten 5 by now. swarms[0].SetConnHandler(nil) expect := 4 for i := 0; i < expect; i++ { select { case <-time.After(time.Second): t.Fatal("failed to get connections") case <-gotconn: } } select { case <-gotconn: t.Fatalf("should have connected to %d swarms", expect) default: } }
func TestSimultOpen(t *testing.T) { // t.Skip("skipping for another test") t.Parallel() ctx := context.Background() swarms := makeSwarms(ctx, t, 2) // connect everyone { var wg sync.WaitGroup connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) { // copy for other peer log.Debugf("TestSimultOpen: connecting: %s --> %s (%s)", s.local, dst, addr) s.peers.AddAddr(dst, addr, peer.PermanentAddrTTL) if _, err := s.Dial(ctx, dst); err != nil { t.Fatal("error swarm dialing to peer", err) } wg.Done() } log.Info("Connecting swarms simultaneously.") wg.Add(2) go connect(swarms[0], swarms[1].local, swarms[1].ListenAddresses()[0]) go connect(swarms[1], swarms[0].local, swarms[0].ListenAddresses()[0]) wg.Wait() } for _, s := range swarms { s.Close() } }
func TestNoTimeout(t *testing.T) { ctx := context.Background() resp, err := doRequest(ctx) if resp == nil || err != nil { t.Fatalf("error received from client: %v %v", err, resp) } }
func TestLimitedStreams(t *testing.T) { mn, err := FullMeshConnected(context.Background(), 2) if err != nil { t.Fatal(err) } var wg sync.WaitGroup messages := 4 messageSize := 500 handler := func(s inet.Stream) { b := make([]byte, messageSize) for i := 0; i < messages; i++ { if _, err := io.ReadFull(s, b); err != nil { log.Fatal(err) } if !bytes.Equal(b[:4], []byte("ping")) { log.Fatal("bytes mismatch") } wg.Done() } s.Close() } hosts := mn.Hosts() for _, h := range mn.Hosts() { h.SetStreamHandler(protocol.TestingID, handler) } peers := mn.Peers() links := mn.LinksBetweenPeers(peers[0], peers[1]) // 1000 byte per second bandwidth bps := float64(1000) opts := links[0].Options() opts.Bandwidth = bps for _, link := range links { link.SetOptions(opts) } s, err := hosts[0].NewStream(protocol.TestingID, hosts[1].ID()) if err != nil { t.Fatal(err) } filler := make([]byte, messageSize-4) data := append([]byte("ping"), filler...) before := time.Now() for i := 0; i < messages; i++ { wg.Add(1) if _, err := s.Write(data); err != nil { panic(err) } } wg.Wait() if !within(time.Since(before), time.Duration(time.Second*2), time.Second/3) { t.Fatal("Expected 2ish seconds but got ", time.Since(before)) } }
func TestSimultDials(t *testing.T) { // t.Skip("skipping for another test") t.Parallel() ctx := context.Background() swarms := makeSwarms(ctx, t, 2) // connect everyone { var wg sync.WaitGroup connect := func(s *Swarm, dst peer.ID, addr ma.Multiaddr) { // copy for other peer log.Debugf("TestSimultOpen: connecting: %s --> %s (%s)", s.local, dst, addr) s.peers.AddAddr(dst, addr, peer.TempAddrTTL) if _, err := s.Dial(ctx, dst); err != nil { t.Fatal("error swarm dialing to peer", err) } wg.Done() } ifaceAddrs0, err := swarms[0].InterfaceListenAddresses() if err != nil { t.Fatal(err) } ifaceAddrs1, err := swarms[1].InterfaceListenAddresses() if err != nil { t.Fatal(err) } log.Info("Connecting swarms simultaneously.") for i := 0; i < 10; i++ { // connect 10x for each. wg.Add(2) go connect(swarms[0], swarms[1].local, ifaceAddrs1[0]) go connect(swarms[1], swarms[0].local, ifaceAddrs0[0]) } wg.Wait() } // should still just have 1, at most 2 connections :) c01l := len(swarms[0].ConnectionsToPeer(swarms[1].local)) if c01l > 2 { t.Error("0->1 has", c01l) } c10l := len(swarms[1].ConnectionsToPeer(swarms[0].local)) if c10l > 2 { t.Error("1->0 has", c10l) } for _, s := range swarms { s.Close() } }
func ExampleWithTimeout() { // Pass a context with a timeout to tell a blocking function that it // should abandon its work after the timeout elapses. ctx, _ := context.WithTimeout(context.Background(), 100*time.Millisecond) select { case <-time.After(200 * time.Millisecond): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) // prints "context deadline exceeded" } // Output: // context deadline exceeded }
func TestCancelAfterRequest(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) resp, err := doRequest(ctx) // Cancel before reading the body. // Request.Body should still be readable after the context is canceled. cancel() b, err := ioutil.ReadAll(resp.Body) if err != nil || string(b) != requestBody { t.Fatalf("could not read body: %q %v", b, err) } }
func TestHostSimple(t *testing.T) { ctx := context.Background() h1 := testutil.GenHostSwarm(t, ctx) h2 := testutil.GenHostSwarm(t, ctx) defer h1.Close() defer h2.Close() h2pi := h2.Peerstore().PeerInfo(h2.ID()) if err := h1.Connect(ctx, h2pi); err != nil { t.Fatal(err) } piper, pipew := io.Pipe() h2.SetStreamHandler(protocol.TestingID, func(s inet.Stream) { defer s.Close() w := io.MultiWriter(s, pipew) io.Copy(w, s) // mirror everything }) s, err := h1.NewStream(protocol.TestingID, h2pi.ID) if err != nil { t.Fatal(err) } // write to the stream buf1 := []byte("abcdefghijkl") if _, err := s.Write(buf1); err != nil { t.Fatal(err) } // get it from the stream (echoed) buf2 := make([]byte, len(buf1)) if _, err := io.ReadFull(s, buf2); err != nil { t.Fatal(err) } if !bytes.Equal(buf1, buf2) { t.Fatal("buf1 != buf2 -- %x != %x", buf1, buf2) } // get it from the pipe (tee) buf3 := make([]byte, len(buf1)) if _, err := io.ReadFull(piper, buf3); err != nil { t.Fatal(err) } if !bytes.Equal(buf1, buf3) { t.Fatal("buf1 != buf3 -- %x != %x", buf1, buf3) } }
func TestContextContainsMetadata(t *testing.T) { t.Parallel() m := Metadata{"foo": "bar"} ctx := ContextWithLoggable(context.Background(), m) got, err := MetadataFromContext(ctx) if err != nil { t.Fatal(err) } _, exists := got["foo"] if !exists { t.Fail() } }
func TestCancel(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) go func() { time.Sleep(requestDuration / 2) cancel() }() resp, err := doRequest(ctx) if resp != nil || err == nil { t.Fatalf("expected error, didn't get one. resp: %v", resp) } if err != ctx.Err() { t.Fatalf("expected error from context but got: %v", err) } }
func TestClose(t *testing.T) { // t.Skip("Skipping in favor of another test") ctx, cancel := context.WithCancel(context.Background()) defer cancel() c1, c2, _, _ := setupSingleConn(t, ctx) testOneSendRecv(t, c1, c2) testOneSendRecv(t, c2, c1) c1.Close() testNotOneSendRecv(t, c1, c2) c2.Close() testNotOneSendRecv(t, c2, c1) testNotOneSendRecv(t, c1, c2) }
func TestSecureHandshakeFailsWithWrongKeys(t *testing.T) { // t.Skip("Skipping in favor of another test") ctx, cancel := context.WithCancel(context.Background()) defer cancel() c1, c2, p1, p2 := setupSingleConn(t, ctx) done := make(chan error) go secureHandshake(t, ctx, p2.PrivKey, c1, done) go secureHandshake(t, ctx, p1.PrivKey, c2, done) for i := 0; i < 2; i++ { if err := <-done; err == nil { t.Fatal("wrong keys should've errored out.") } } }
func TestSecureCancelHandshake(t *testing.T) { // t.Skip("Skipping in favor of another test") ctx, cancel := context.WithCancel(context.Background()) c1, c2, p1, p2 := setupSingleConn(t, ctx) done := make(chan error) go secureHandshake(t, ctx, p1.PrivKey, c1, done) time.Sleep(time.Millisecond) cancel() // cancel ctx go secureHandshake(t, ctx, p2.PrivKey, c2, done) for i := 0; i < 2; i++ { if err := <-done; err == nil { t.Error("cancel should've errored out") } } }
func testPing(t *testing.T, ps *PingService, p peer.ID) { pctx, cancel := context.WithCancel(context.Background()) defer cancel() ts, err := ps.Ping(pctx, p) if err != nil { t.Fatal(err) } for i := 0; i < 5; i++ { select { case took := <-ts: t.Log("ping took: ", took) case <-time.After(time.Second * 4): t.Fatal("failed to receive ping") } } }
// TestReconnect tests whether hosts are able to disconnect and reconnect. func TestReconnect2(t *testing.T) { ctx := context.Background() h1 := testutil.GenHostSwarm(t, ctx) h2 := testutil.GenHostSwarm(t, ctx) hosts := []host.Host{h1, h2} h1.SetStreamHandler(protocol.TestingID, EchoStreamHandler) h2.SetStreamHandler(protocol.TestingID, EchoStreamHandler) rounds := 8 if testing.Short() { rounds = 4 } for i := 0; i < rounds; i++ { log.Debugf("TestReconnect: %d/%d\n", i, rounds) SubtestConnSendDisc(t, hosts) } }
// TestConnectednessCorrect starts a few networks, connects a few // and tests Connectedness value is correct. func TestConnectednessCorrect(t *testing.T) { ctx := context.Background() nets := make([]inet.Network, 4) for i := 0; i < 4; i++ { nets[i] = testutil.GenSwarmNetwork(t, ctx) } // connect 0-1, 0-2, 0-3, 1-2, 2-3 dial := func(a, b inet.Network) { testutil.DivulgeAddresses(b, a) if _, err := a.DialPeer(ctx, b.LocalPeer()); err != nil { t.Fatalf("Failed to dial: %s", err) } } dial(nets[0], nets[1]) dial(nets[0], nets[3]) dial(nets[1], nets[2]) dial(nets[3], nets[2]) // there's something wrong with dial, i think. it's not finishing // completely. there must be some async stuff. <-time.After(100 * time.Millisecond) // test those connected show up correctly // test connected expectConnectedness(t, nets[0], nets[1], inet.Connected) expectConnectedness(t, nets[0], nets[3], inet.Connected) expectConnectedness(t, nets[1], nets[2], inet.Connected) expectConnectedness(t, nets[3], nets[2], inet.Connected) // test not connected expectConnectedness(t, nets[0], nets[2], inet.NotConnected) expectConnectedness(t, nets[1], nets[3], inet.NotConnected) for _, n := range nets { n.Close() } }
func TestStreams(t *testing.T) { mn, err := FullMeshConnected(context.Background(), 3) if err != nil { t.Fatal(err) } handler := func(s inet.Stream) { b := make([]byte, 4) if _, err := io.ReadFull(s, b); err != nil { panic(err) } if !bytes.Equal(b, []byte("beep")) { panic("bytes mismatch") } if _, err := s.Write([]byte("boop")); err != nil { panic(err) } s.Close() } hosts := mn.Hosts() for _, h := range mn.Hosts() { h.SetStreamHandler(protocol.TestingID, handler) } s, err := hosts[0].NewStream(protocol.TestingID, hosts[1].ID()) if err != nil { t.Fatal(err) } if _, err := s.Write([]byte("beep")); err != nil { panic(err) } b := make([]byte, 4) if _, err := io.ReadFull(s, b); err != nil { panic(err) } if !bytes.Equal(b, []byte("boop")) { panic("bytes mismatch 2") } }
func TestContextWithPreexistingMetadata(t *testing.T) { t.Parallel() ctx := ContextWithLoggable(context.Background(), Metadata{"hello": "world"}) ctx = ContextWithLoggable(ctx, Metadata{"goodbye": "earth"}) got, err := MetadataFromContext(ctx) if err != nil { t.Fatal(err) } _, exists := got["hello"] if !exists { t.Fatal("original key not present") } _, exists = got["goodbye"] if !exists { t.Fatal("new key not present") } }
func TestDialWait(t *testing.T) { // t.Skip("skipping for another test") t.Parallel() ctx := context.Background() swarms := makeSwarms(ctx, t, 1) s1 := swarms[0] defer s1.Close() s1.dialT = time.Millisecond * 300 // lower timeout for tests. if ci.IsRunning() { s1.dialT = time.Second } // dial to a non-existent peer. s2p, s2addr, s2l := newSilentPeer(t) go acceptAndHang(s2l) defer s2l.Close() s1.peers.AddAddr(s2p, s2addr, peer.PermanentAddrTTL) before := time.Now() if c, err := s1.Dial(ctx, s2p); err == nil { defer c.Close() t.Fatal("error swarm dialing to unknown peer worked...", err) } else { t.Log("correctly got error:", err) } duration := time.Now().Sub(before) dt := s1.dialT if duration < dt*dialAttempts { t.Error("< DialTimeout * dialAttempts not being respected", duration, dt*dialAttempts) } if duration > 2*dt*dialAttempts { t.Error("> 2*DialTimeout * dialAttempts not being respected", duration, 2*dt*dialAttempts) } if !s1.backf.Backoff(s2p) { t.Error("s2 should now be on backoff") } }
func TestPing(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() h1 := netutil.GenHostSwarm(t, ctx) h2 := netutil.GenHostSwarm(t, ctx) err := h1.Connect(ctx, peer.PeerInfo{ ID: h2.ID(), Addrs: h2.Addrs(), }) if err != nil { t.Fatal(err) } ps1 := NewPingService(h1) ps2 := NewPingService(h2) testPing(t, ps1, h2.ID()) testPing(t, ps2, h1.ID()) }
func subtestIDService(t *testing.T, postDialWait time.Duration) { // the generated networks should have the id service wired in. ctx := context.Background() h1 := testutil.GenHostSwarm(t, ctx) h2 := testutil.GenHostSwarm(t, ctx) h1p := h1.ID() h2p := h2.ID() testKnowsAddrs(t, h1, h2p, []ma.Multiaddr{}) // nothing testKnowsAddrs(t, h2, h1p, []ma.Multiaddr{}) // nothing h2pi := h2.Peerstore().PeerInfo(h2p) if err := h1.Connect(ctx, h2pi); err != nil { t.Fatal(err) } // we need to wait here if Dial returns before ID service is finished. if postDialWait > 0 { <-time.After(postDialWait) } // the IDService should be opened automatically, by the network. // what we should see now is that both peers know about each others listen addresses. testKnowsAddrs(t, h1, h2p, h2.Peerstore().Addrs(h2p)) // has them testHasProtocolVersions(t, h1, h2p) // now, this wait we do have to do. it's the wait for the Listening side // to be done identifying the connection. c := h2.Network().ConnsToPeer(h1.ID()) if len(c) < 1 { t.Fatal("should have connection by now at least.") } <-h2.IDService().IdentifyWait(c[0]) // and the protocol versions. testKnowsAddrs(t, h2, h1p, h1.Peerstore().Addrs(h1p)) // has them testHasProtocolVersions(t, h2, h1p) }
// connHandler is called by the StreamSwarm whenever a new connection is added // here we configure it slightly. Note that this is sequential, so if anything // will take a while do it in a goroutine. // See https://godoc.org/github.com/jbenet/go-peerstream for more information func (s *Swarm) connHandler(c *ps.Conn) *Conn { ctx := context.Background() // this context is for running the handshake, which -- when receiveing connections // -- we have no bound on beyond what the transport protocol bounds it at. // note that setup + the handshake are bounded by underlying io. // (i.e. if TCP or UDP disconnects (or the swarm closes), we're done. // Q: why not have a shorter handshake? think about an HTTP server on really slow conns. // as long as the conn is live (TCP says its online), it tries its best. we follow suit.) sc, err := s.newConnSetup(ctx, c) if err != nil { log.Debug(err) log.Event(ctx, "newConnHandlerDisconnect", lgbl.NetConn(c.NetConn()), lgbl.Error(err)) c.Close() // boom. close it. return nil } // if a peer dials us, remove from dial backoff. s.backf.Clear(sc.RemotePeer()) return sc }
func TestStreamsStress(t *testing.T) { nnodes := 100 if detectrace.WithRace() { nnodes = 50 } mn, err := FullMeshConnected(context.Background(), nnodes) if err != nil { t.Fatal(err) } hosts := mn.Hosts() for _, h := range hosts { ponger := makePonger(string(protocol.TestingID)) h.SetStreamHandler(protocol.TestingID, ponger) } var wg sync.WaitGroup for i := 0; i < 1000; i++ { wg.Add(1) go func(i int) { defer wg.Done() from := rand.Intn(len(hosts)) to := rand.Intn(len(hosts)) s, err := hosts[from].NewStream(protocol.TestingID, hosts[to].ID()) if err != nil { log.Debugf("%d (%s) %d (%s)", from, hosts[from], to, hosts[to]) panic(err) } log.Infof("%d start pinging", i) makePinger("pingpong", rand.Intn(100))(s) log.Infof("%d done pinging", i) }(i) } wg.Wait() }
func TestDialBackoffClears(t *testing.T) { // t.Skip("skipping for another test") t.Parallel() ctx := context.Background() swarms := makeSwarms(ctx, t, 2) s1 := swarms[0] s2 := swarms[1] defer s1.Close() defer s2.Close() s1.dialT = time.Millisecond * 300 // lower timeout for tests. s2.dialT = time.Millisecond * 300 // lower timeout for tests. if ci.IsRunning() { s1.dialT = 2 * time.Second s2.dialT = 2 * time.Second } // use another address first, that accept and hang on conns _, s2bad, s2l := newSilentPeer(t) go acceptAndHang(s2l) defer s2l.Close() // phase 1 -- dial to non-operational addresses s1.peers.AddAddr(s2.local, s2bad, peer.PermanentAddrTTL) before := time.Now() if c, err := s1.Dial(ctx, s2.local); err == nil { t.Fatal("dialing to broken addr worked...", err) defer c.Close() } else { t.Log("correctly got error:", err) } duration := time.Now().Sub(before) dt := s1.dialT if duration < dt*dialAttempts { t.Error("< DialTimeout * dialAttempts not being respected", duration, dt*dialAttempts) } if duration > 2*dt*dialAttempts { t.Error("> 2*DialTimeout * dialAttempts not being respected", duration, 2*dt*dialAttempts) } if !s1.backf.Backoff(s2.local) { t.Error("s2 should now be on backoff") } else { t.Log("correctly added to backoff") } // phase 2 -- add the working address. dial should succeed. ifaceAddrs1, err := swarms[1].InterfaceListenAddresses() if err != nil { t.Fatal(err) } s1.peers.AddAddrs(s2.local, ifaceAddrs1, peer.PermanentAddrTTL) if _, err := s1.Dial(ctx, s2.local); err == nil { t.Fatal("should have failed to dial backed off peer") } time.Sleep(baseBackoffTime) if c, err := s1.Dial(ctx, s2.local); err != nil { t.Fatal(err) } else { c.Close() t.Log("correctly connected") } if s1.backf.Backoff(s2.local) { t.Error("s2 should no longer be on backoff") } else { t.Log("correctly cleared backoff") } }
func TestDialBackoff(t *testing.T) { // t.Skip("skipping for another test") if ci.IsRunning() { t.Skip("travis and jenkins will never have fun with this test") } t.Parallel() ctx := context.Background() swarms := makeSwarms(ctx, t, 2) s1 := swarms[0] s2 := swarms[1] defer s1.Close() defer s2.Close() s1.dialT = time.Second // lower timeout for tests. s2.dialT = time.Second // lower timeout for tests. s2addrs, err := s2.InterfaceListenAddresses() if err != nil { t.Fatal(err) } s1.peers.AddAddrs(s2.local, s2addrs, peer.PermanentAddrTTL) // dial to a non-existent peer. s3p, s3addr, s3l := newSilentPeer(t) go acceptAndHang(s3l) defer s3l.Close() s1.peers.AddAddr(s3p, s3addr, peer.PermanentAddrTTL) // in this test we will: // 1) dial 10x to each node. // 2) all dials should hang // 3) s1->s2 should succeed. // 4) s1->s3 should not (and should place s3 on backoff) // 5) disconnect entirely // 6) dial 10x to each node again // 7) s3 dials should all return immediately (except 1) // 8) s2 dials should all hang, and succeed // 9) last s3 dial ends, unsuccessful dialOnlineNode := func(dst peer.ID, times int) <-chan bool { ch := make(chan bool) for i := 0; i < times; i++ { go func() { if _, err := s1.Dial(ctx, dst); err != nil { t.Error("error dialing", dst, err) ch <- false } else { ch <- true } }() } return ch } dialOfflineNode := func(dst peer.ID, times int) <-chan bool { ch := make(chan bool) for i := 0; i < times; i++ { go func() { if c, err := s1.Dial(ctx, dst); err != nil { ch <- false } else { t.Error("succeeded in dialing", dst) ch <- true c.Close() } }() } return ch } { // 1) dial 10x to each node. N := 10 s2done := dialOnlineNode(s2.local, N) s3done := dialOfflineNode(s3p, N) // when all dials should be done by: dialTimeout1x := time.After(s1.dialT) // dialTimeout1Ax := time.After(s1.dialT * 2) // dialAttempts) dialTimeout10Ax := time.After(s1.dialT * 2 * 10) // dialAttempts * 10) // 2) all dials should hang select { case <-s2done: t.Error("s2 should not happen immediately") case <-s3done: t.Error("s3 should not happen yet") case <-time.After(time.Millisecond): // s2 may finish very quickly, so let's get out. } // 3) s1->s2 should succeed. for i := 0; i < N; i++ { select { case r := <-s2done: if !r { t.Error("s2 should not fail") } case <-s3done: t.Error("s3 should not happen yet") case <-dialTimeout1x: t.Error("s2 took too long") } } select { case <-s2done: t.Error("s2 should have no more") case <-s3done: t.Error("s3 should not happen yet") case <-dialTimeout1x: // let it pass } // 4) s1->s3 should not (and should place s3 on backoff) // N-1 should finish before dialTimeout1x * 2 for i := 0; i < N; i++ { select { case <-s2done: t.Error("s2 should have no more") case r := <-s3done: if r { t.Error("s3 should not succeed") } case <-(dialTimeout1x): if i < (N - 1) { t.Fatal("s3 took too long") } t.Log("dialTimeout1x * 1.3 hit for last peer") case <-dialTimeout10Ax: t.Fatal("s3 took too long") } } // check backoff state if s1.backf.Backoff(s2.local) { t.Error("s2 should not be on backoff") } if !s1.backf.Backoff(s3p) { t.Error("s3 should be on backoff") } // 5) disconnect entirely for _, c := range s1.Connections() { c.Close() } for i := 0; i < 100 && len(s1.Connections()) > 0; i++ { <-time.After(time.Millisecond) } if len(s1.Connections()) > 0 { t.Fatal("s1 conns must exit") } } { // 6) dial 10x to each node again N := 10 s2done := dialOnlineNode(s2.local, N) s3done := dialOfflineNode(s3p, N) // when all dials should be done by: dialTimeout1x := time.After(s1.dialT) // dialTimeout1Ax := time.After(s1.dialT * 2) // dialAttempts) dialTimeout10Ax := time.After(s1.dialT * 2 * 10) // dialAttempts * 10) // 7) s3 dials should all return immediately (except 1) for i := 0; i < N-1; i++ { select { case <-s2done: t.Error("s2 should not succeed yet") case r := <-s3done: if r { t.Error("s3 should not succeed") } case <-dialTimeout1x: t.Fatal("s3 took too long") } } // 8) s2 dials should all hang, and succeed for i := 0; i < N; i++ { select { case r := <-s2done: if !r { t.Error("s2 should succeed") } // case <-s3done: case <-(dialTimeout1x): t.Fatal("s3 took too long") } } // 9) the last s3 should return, failed. select { case <-s2done: t.Error("s2 should have no more") case r := <-s3done: if r { t.Error("s3 should not succeed") } case <-dialTimeout10Ax: t.Fatal("s3 took too long") } // check backoff state (the same) if s1.backf.Backoff(s2.local) { t.Error("s2 should not be on backoff") } if !s1.backf.Backoff(s3p) { t.Error("s3 should be on backoff") } } }