]> Sergey Matveev's repositories - btrtrc.git/blobdiff - ut-holepunching_test.go
Synchronize holepunch connect messages with existing rendezvous
[btrtrc.git] / ut-holepunching_test.go
diff --git a/ut-holepunching_test.go b/ut-holepunching_test.go
new file mode 100644 (file)
index 0000000..1b4b7d0
--- /dev/null
@@ -0,0 +1,105 @@
+package torrent
+
+import (
+       "os"
+       "sync"
+       "testing"
+       "testing/iotest"
+
+       "github.com/anacrolix/torrent/internal/testutil"
+       qt "github.com/frankban/quicktest"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+// Check that after completing leeching, a leecher transitions to a seeding
+// correctly. Connected in a chain like so: Seeder <-> Leecher <-> LeecherLeecher.
+func TestHolepunchConnect(t *testing.T) {
+       greetingTempDir, mi := testutil.GreetingTestTorrent()
+       defer os.RemoveAll(greetingTempDir)
+
+       cfg := TestingConfig(t)
+       cfg.Seed = true
+       cfg.MaxAllocPeerRequestDataPerConn = 4
+       cfg.DataDir = greetingTempDir
+       cfg.DisablePEX = true
+       //cfg.Debug = true
+       cfg.AcceptPeerConnections = false
+       seeder, err := NewClient(cfg)
+       require.NoError(t, err)
+       defer seeder.Close()
+       defer testutil.ExportStatusWriter(seeder, "s", t)()
+       seederTorrent, ok, err := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
+       require.NoError(t, err)
+       assert.True(t, ok)
+       seederTorrent.VerifyData()
+
+       cfg = TestingConfig(t)
+       cfg.Seed = true
+       cfg.DataDir = t.TempDir()
+       cfg.AlwaysWantConns = true
+       // This way the leecher leecher will still try to use this peer as a relay, but won't be told
+       // about the seeder via PEX.
+       //cfg.DisablePEX = true
+       //cfg.Debug = true
+       leecher, err := NewClient(cfg)
+       require.NoError(t, err)
+       defer leecher.Close()
+       defer testutil.ExportStatusWriter(leecher, "l", t)()
+
+       cfg = TestingConfig(t)
+       cfg.Seed = false
+       cfg.DataDir = t.TempDir()
+       cfg.MaxAllocPeerRequestDataPerConn = 4
+       cfg.Debug = true
+       //cfg.DisableUTP = true
+       leecherLeecher, _ := NewClient(cfg)
+       require.NoError(t, err)
+       defer leecherLeecher.Close()
+       defer testutil.ExportStatusWriter(leecherLeecher, "ll", t)()
+       leecherGreeting, ok, err := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
+               ret = TorrentSpecFromMetaInfo(mi)
+               ret.ChunkSize = 2
+               return
+       }())
+       _ = leecherGreeting
+       require.NoError(t, err)
+       assert.True(t, ok)
+       llg, ok, err := leecherLeecher.AddTorrentSpec(func() (ret *TorrentSpec) {
+               ret = TorrentSpecFromMetaInfo(mi)
+               ret.ChunkSize = 3
+               return
+       }())
+       require.NoError(t, err)
+       assert.True(t, ok)
+
+       var wg sync.WaitGroup
+       wg.Add(1)
+       go func() {
+               defer wg.Done()
+               r := llg.NewReader()
+               defer r.Close()
+               qt.Check(t, iotest.TestReader(r, []byte(testutil.GreetingFileContents)), qt.IsNil)
+       }()
+       go seederTorrent.AddClientPeer(leecher)
+       waitForConns(seederTorrent)
+       go llg.AddClientPeer(leecher)
+       waitForConns(llg)
+       llg.cl.lock()
+       llg.initiateConn(PeerInfo{
+               Addr: seeder.ListenAddrs()[0],
+       }, true, false)
+       llg.cl.unlock()
+       wg.Wait()
+}
+
+func waitForConns(t *Torrent) {
+       t.cl.lock()
+       defer t.cl.unlock()
+       for {
+               for range t.conns {
+                       return
+               }
+               t.cl.event.Wait()
+       }
+}