"encoding/binary"
"fmt"
"io"
- "io/ioutil"
+ "net"
+ "net/netip"
"os"
"path/filepath"
"reflect"
"testing/iotest"
"time"
- "github.com/bradfitz/iter"
- "github.com/frankban/quicktest"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-
"github.com/anacrolix/dht/v2"
+ "github.com/anacrolix/log"
"github.com/anacrolix/missinggo/v2"
"github.com/anacrolix/missinggo/v2/filecache"
+ "github.com/frankban/quicktest"
+ qt "github.com/frankban/quicktest"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
"github.com/anacrolix/torrent/bencode"
"github.com/anacrolix/torrent/internal/testutil"
func TestClientDefault(t *testing.T) {
cl, err := NewClient(TestingConfig(t))
require.NoError(t, err)
- cl.Close()
+ require.Empty(t, cl.Close())
}
func TestClientNilConfig(t *testing.T) {
+ // The default config will put crap in the working directory.
+ origDir, _ := os.Getwd()
+ defer os.Chdir(origDir)
+ os.Chdir(t.TempDir())
cl, err := NewClient(nil)
require.NoError(t, err)
- cl.Close()
+ require.Empty(t, cl.Close())
}
func TestAddDropTorrent(t *testing.T) {
func TestTorrentInitialState(t *testing.T) {
dir, mi := testutil.GreetingTestTorrent()
defer os.RemoveAll(dir)
- cl := &Client{
- config: TestingConfig(t),
- }
+ var cl Client
+ cl.init(TestingConfig(t))
cl.initLogger()
tor := cl.newTorrent(
mi.HashInfoBytes(),
)
tor.setChunkSize(2)
tor.cl.lock()
- err := tor.setInfoBytes(mi.InfoBytes)
+ err := tor.setInfoBytesLocked(mi.InfoBytes)
tor.cl.unlock()
require.NoError(t, err)
require.Len(t, tor.pieces, 3)
cl, err := NewClient(TestingConfig(t))
require.NoError(t, err)
defer cl.Close()
- for i := range iter.N(1000) {
+ for i := 0; i < 1000; i += 1 {
var spec TorrentSpec
binary.PutVarint(spec.InfoHash[:], int64(i))
tt, new, err := cl.AddTorrentSpec(&spec)
require.NoError(b, err)
defer cl.Close()
b.ReportAllocs()
- for range iter.N(b.N) {
+ for i := 0; i < b.N; i += 1 {
t, err := cl.AddTorrentFromFile("testdata/bootstrap.dat.torrent")
if err != nil {
b.Fatal(err)
defer seeder.Close()
seederTorrent, _, _ := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
seederTorrent.VerifyData()
- leecherDataDir, err := ioutil.TempDir("", "")
+ leecherDataDir := t.TempDir()
+ cfg = TestingConfig(t)
+ cfg.DataDir = leecherDataDir
+ leecher, err := NewClient(cfg)
require.Nil(t, err)
- defer os.RemoveAll(leecherDataDir)
+ defer leecher.Close()
+ leecherTorrent, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
+ ret = TorrentSpecFromMetaInfo(mi)
+ ret.ChunkSize = 2
+ return
+ }())
+ leecherTorrent.AddClientPeer(seeder)
+ reader := leecherTorrent.NewReader()
+ defer reader.Close()
+ reader.SetReadahead(0)
+ reader.SetResponsive()
+ b := make([]byte, 2)
+ _, err = reader.Seek(3, io.SeekStart)
+ require.NoError(t, err)
+ _, err = io.ReadFull(reader, b)
+ assert.Nil(t, err)
+ assert.EqualValues(t, "lo", string(b))
+ _, err = reader.Seek(11, io.SeekStart)
+ require.NoError(t, err)
+ n, err := io.ReadFull(reader, b)
+ assert.Nil(t, err)
+ assert.EqualValues(t, 2, n)
+ assert.EqualValues(t, "d\n", string(b))
+}
+
+// TestResponsive was the first test to fail if uTP is disabled and TCP sockets dial from the
+// listening port.
+func TestResponsiveTcpOnly(t *testing.T) {
+ seederDataDir, mi := testutil.GreetingTestTorrent()
+ defer os.RemoveAll(seederDataDir)
+ cfg := TestingConfig(t)
+ cfg.DisableUTP = true
+ cfg.Seed = true
+ cfg.DataDir = seederDataDir
+ seeder, err := NewClient(cfg)
+ require.Nil(t, err)
+ defer seeder.Close()
+ seederTorrent, _, _ := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
+ seederTorrent.VerifyData()
+ leecherDataDir := t.TempDir()
cfg = TestingConfig(t)
cfg.DataDir = leecherDataDir
leecher, err := NewClient(cfg)
defer seeder.Close()
seederTorrent, _, _ := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
seederTorrent.VerifyData()
- leecherDataDir, err := ioutil.TempDir("", "")
- require.Nil(t, err)
- defer os.RemoveAll(leecherDataDir)
+ leecherDataDir := t.TempDir()
cfg = TestingConfig(t)
cfg.DataDir = leecherDataDir
leecher, err := NewClient(cfg)
_, err = io.ReadFull(reader, b)
assert.Nil(t, err)
assert.EqualValues(t, "lo", string(b))
- go leecherTorrent.Drop()
_, err = reader.Seek(11, io.SeekStart)
require.NoError(t, err)
+ leecherTorrent.Drop()
n, err := reader.Read(b)
assert.EqualError(t, err, "torrent closed")
assert.EqualValues(t, 0, n)
}
func writeTorrentData(ts *storage.Torrent, info metainfo.Info, b []byte) {
- for i := range iter.N(info.NumPieces()) {
+ for i := 0; i < info.NumPieces(); i += 1 {
p := info.Piece(i)
ts.Piece(p).WriteAt(b[p.Offset():p.Offset()+p.Length()], 0)
}
}
func testAddTorrentPriorPieceCompletion(t *testing.T, alreadyCompleted bool, csf func(*filecache.Cache) storage.ClientImpl) {
- fileCacheDir, err := ioutil.TempDir("", "")
- require.NoError(t, err)
- defer os.RemoveAll(fileCacheDir)
+ fileCacheDir := t.TempDir()
fileCache, err := filecache.NewCache(fileCacheDir)
require.NoError(t, err)
greetingDataTempDir, greetingMetainfo := testutil.GreetingTestTorrent()
defer testutil.ExportStatusWriter(seeder, "s", t)()
seederTorrent, _, _ := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
seederTorrent.VerifyData()
- leecherDataDir, err := ioutil.TempDir("", "")
- require.NoError(t, err)
- defer os.RemoveAll(leecherDataDir)
+ leecherDataDir := t.TempDir()
fc, err := filecache.NewCache(leecherDataDir)
require.NoError(t, err)
if ps.SetLeecherStorageCapacity {
leecherGreeting.cl.lock()
leecherGreeting.downloadPiecesLocked(0, leecherGreeting.numPieces())
if ps.Cancel {
- leecherGreeting.cancelPiecesLocked(0, leecherGreeting.NumPieces())
+ leecherGreeting.cancelPiecesLocked(0, leecherGreeting.NumPieces(), "")
}
leecherGreeting.cl.unlock()
done := make(chan struct{})
}
}()
for !reflect.DeepEqual(completes, expected) {
- _v := <-psc.Values
- v := _v.(PieceStateChange)
+ v := <-psc.Values
completes[v.Index] = v.Complete
}
}
assert.True(t, _new)
defer tt.Drop()
cn := &PeerConn{Peer: Peer{
- t: tt,
+ t: tt,
+ callbacks: &cfg.Callbacks,
}}
+ tt.conns[cn] = struct{}{}
cn.peerImpl = cn
cl.lock()
defer cl.unlock()
cfg.DataDir = greetingTempDir
seeder, err := NewClient(TestingConfig(t))
require.NoError(t, err)
+ defer seeder.Close()
seeder.AddTorrentSpec(&TorrentSpec{
InfoBytes: greetingMetainfo.InfoBytes,
})
cfg := TestingConfig(t)
cfg.DisableAcceptRateLimiting = true
cfg.DropDuplicatePeerIds = true
- for i := range iter.N(3) {
+ for i := 0; i < 3; i += 1 {
cl, err := NewClient(cfg)
require.NoError(t, err)
defer cl.Close()
// Creates a file containing its own name as data. Make a metainfo from that, adds it to the given
// client, and returns a magnet link.
-func makeMagnet(t *testing.T, cl *Client, dir string, name string) string {
- os.MkdirAll(dir, 0770)
+func makeMagnet(t *testing.T, cl *Client, dir, name string) string {
+ os.MkdirAll(dir, 0o770)
file, err := os.Create(filepath.Join(dir, name))
require.NoError(t, err)
file.Write([]byte(name))
// Test that the leecher can download a torrent in its entirety from the seeder. Note that the
// seeder config is done first.
-func testSeederLeecherPair(t *testing.T, seeder func(*ClientConfig), leecher func(*ClientConfig)) {
+func testSeederLeecherPair(t *testing.T, seeder, leecher func(*ClientConfig)) {
cfg := TestingConfig(t)
cfg.Seed = true
cfg.DataDir = filepath.Join(cfg.DataDir, "server")
- os.Mkdir(cfg.DataDir, 0755)
+ os.Mkdir(cfg.DataDir, 0o755)
seeder(cfg)
server, err := NewClient(cfg)
require.NoError(t, err)
}
func TestClientAddressInUse(t *testing.T) {
- s, _ := NewUtpSocket("udp", ":50007", nil)
+ s, _ := NewUtpSocket("udp", "localhost:50007", nil, log.Default)
if s != nil {
defer s.Close()
}
- cfg := TestingConfig(t).SetListenAddr(":50007")
+ cfg := TestingConfig(t).SetListenAddr("localhost:50007")
+ cfg.DisableUTP = false
cl, err := NewClient(cfg)
+ if err == nil {
+ assert.Nil(t, cl.Close())
+ }
require.Error(t, err)
require.Nil(t, cl)
}
assert.Empty(t, cl.listeners)
assert.NotEmpty(t, cl.DhtServers())
}
+
+func TestBadPeerIpPort(t *testing.T) {
+ for _, tc := range []struct {
+ title string
+ ip net.IP
+ port int
+ expectedOk bool
+ setup func(*Client)
+ }{
+ {"empty both", nil, 0, true, func(*Client) {}},
+ {"empty/nil ip", nil, 6666, true, func(*Client) {}},
+ {
+ "empty port",
+ net.ParseIP("127.0.0.1/32"),
+ 0, true,
+ func(*Client) {},
+ },
+ {
+ "in doppleganger addresses",
+ net.ParseIP("127.0.0.1/32"),
+ 2322,
+ true,
+ func(cl *Client) {
+ cl.dopplegangerAddrs["10.0.0.1:2322"] = struct{}{}
+ },
+ },
+ {
+ "in IP block list",
+ net.ParseIP("10.0.0.1"),
+ 2322,
+ true,
+ func(cl *Client) {
+ cl.ipBlockList = iplist.New([]iplist.Range{
+ {First: net.ParseIP("10.0.0.1"), Last: net.ParseIP("10.0.0.255")},
+ })
+ },
+ },
+ {
+ "in bad peer IPs",
+ net.ParseIP("10.0.0.1"),
+ 2322,
+ true,
+ func(cl *Client) {
+ ipAddr, ok := netip.AddrFromSlice(net.ParseIP("10.0.0.1"))
+ require.True(t, ok)
+ cl.badPeerIPs = map[netip.Addr]struct{}{}
+ cl.badPeerIPs[ipAddr] = struct{}{}
+ },
+ },
+ {
+ "good",
+ net.ParseIP("10.0.0.1"),
+ 2322,
+ false,
+ func(cl *Client) {},
+ },
+ } {
+ t.Run(tc.title, func(t *testing.T) {
+ cfg := TestingConfig(t)
+ cfg.DisableTCP = true
+ cfg.DisableUTP = true
+ cfg.NoDHT = false
+ cl, err := NewClient(cfg)
+ require.NoError(t, err)
+ defer cl.Close()
+
+ tc.setup(cl)
+ require.Equal(t, tc.expectedOk, cl.badPeerIPPort(tc.ip, tc.port))
+ })
+ }
+}
+
+// https://github.com/anacrolix/torrent/issues/837
+func TestClientConfigSetHandlerNotIgnored(t *testing.T) {
+ cfg := TestingConfig(t)
+ cfg.Logger.SetHandlers(log.DiscardHandler)
+ c := qt.New(t)
+ cl, err := NewClient(cfg)
+ c.Assert(err, qt.IsNil)
+ defer cl.Close()
+ c.Assert(cl.logger.Handlers, qt.HasLen, 1)
+ h := cl.logger.Handlers[0].(log.StreamHandler)
+ c.Check(h.W, qt.Equals, io.Discard)
+}