15 _ "github.com/anacrolix/envpprof"
16 "github.com/anacrolix/utp"
17 "github.com/bradfitz/iter"
18 "github.com/stretchr/testify/assert"
21 "github.com/anacrolix/torrent/bencode"
22 "github.com/anacrolix/torrent/data"
23 "github.com/anacrolix/torrent/data/blob"
24 "github.com/anacrolix/torrent/internal/testutil"
25 "github.com/anacrolix/torrent/metainfo"
26 "github.com/anacrolix/torrent/util"
30 log.SetFlags(log.LstdFlags | log.Lshortfile)
33 var TestingConfig = Config{
34 ListenAddr: "localhost:0",
36 DisableTrackers: true,
37 NoDefaultBlocklist: true,
38 DisableMetainfoCache: true,
39 DataDir: filepath.Join(os.TempDir(), "anacrolix"),
42 func TestClientDefault(t *testing.T) {
43 cl, err := NewClient(&TestingConfig)
50 func TestAddDropTorrent(t *testing.T) {
51 cl, err := NewClient(&TestingConfig)
56 dir, mi := testutil.GreetingTestTorrent()
57 defer os.RemoveAll(dir)
58 tt, new, err := cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
68 func TestAddTorrentNoSupportedTrackerSchemes(t *testing.T) {
72 func TestAddTorrentNoUsableURLs(t *testing.T) {
76 func TestAddPeersToUnknownTorrent(t *testing.T) {
80 func TestPieceHashSize(t *testing.T) {
81 if pieceHash.Size() != 20 {
86 func TestTorrentInitialState(t *testing.T) {
87 dir, mi := testutil.GreetingTestTorrent()
88 defer os.RemoveAll(dir)
89 tor, err := newTorrent(func() (ih InfoHash) {
90 util.CopyExact(ih[:], mi.Info.Hash)
97 err = tor.setMetadata(&mi.Info.Info, mi.Info.Bytes, nil)
101 if len(tor.Pieces) != 3 {
102 t.Fatal("wrong number of pieces")
105 tor.pendAllChunkSpecs(0)
106 assert.EqualValues(t, 3, p.numPendingChunks())
107 assert.EqualValues(t, chunkSpec{4, 1}, chunkIndexSpec(2, tor.pieceLength(0), tor.chunkSize))
110 func TestUnmarshalPEXMsg(t *testing.T) {
111 var m peerExchangeMessage
112 if err := bencode.Unmarshal([]byte("d5:added12:\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0ce"), &m); err != nil {
115 if len(m.Added) != 2 {
118 if m.Added[0].Port != 0x506 {
123 func TestReducedDialTimeout(t *testing.T) {
124 for _, _case := range []struct {
128 ExpectedReduced time.Duration
130 {nominalDialTimeout, 40, 0, nominalDialTimeout},
131 {nominalDialTimeout, 40, 1, nominalDialTimeout},
132 {nominalDialTimeout, 40, 39, nominalDialTimeout},
133 {nominalDialTimeout, 40, 40, nominalDialTimeout / 2},
134 {nominalDialTimeout, 40, 80, nominalDialTimeout / 3},
135 {nominalDialTimeout, 40, 4000, nominalDialTimeout / 101},
137 reduced := reducedDialTimeout(_case.Max, _case.HalfOpenLimit, _case.PendingPeers)
138 expected := _case.ExpectedReduced
139 if expected < minDialTimeout {
140 expected = minDialTimeout
142 if reduced != expected {
143 t.Fatalf("expected %s, got %s", _case.ExpectedReduced, reduced)
148 func TestUTPRawConn(t *testing.T) {
149 l, err := utp.NewSocket("")
162 // Connect a UTP peer to see if the RawConn will still work.
163 utpPeer, err := func() *utp.Socket {
164 s, _ := utp.NewSocket("")
166 }().Dial(fmt.Sprintf("localhost:%d", util.AddrPort(l.Addr())))
168 t.Fatalf("error dialing utp listener: %s", err)
170 defer utpPeer.Close()
171 peer, err := net.ListenPacket("udp", ":0")
178 // How many messages to send. I've set this to double the channel buffer
179 // size in the raw packetConn.
181 readerStopped := make(chan struct{})
182 // The reader goroutine.
184 defer close(readerStopped)
185 b := make([]byte, 500)
186 for i := 0; i < N; i++ {
187 n, _, err := l.PacketConn().ReadFrom(b)
189 t.Fatalf("error reading from raw conn: %s", err)
193 fmt.Sscan(string(b[:n]), &d)
195 log.Printf("got wrong number: expected %d, got %d", i, d)
199 udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", util.AddrPort(l.Addr())))
203 for i := 0; i < N; i++ {
204 _, err := peer.WriteTo([]byte(fmt.Sprintf("%d", i)), udpAddr)
208 time.Sleep(time.Microsecond)
211 case <-readerStopped:
212 case <-time.After(time.Second):
213 t.Fatal("reader timed out")
215 if msgsReceived != N {
216 t.Fatalf("messages received: %d", msgsReceived)
220 func TestTwoClientsArbitraryPorts(t *testing.T) {
221 for i := 0; i < 2; i++ {
222 cl, err := NewClient(&TestingConfig)
230 func TestAddDropManyTorrents(t *testing.T) {
231 cl, _ := NewClient(&TestingConfig)
233 for i := range iter.N(1000) {
235 binary.PutVarint(spec.InfoHash[:], int64(i))
236 tt, new, err := cl.AddTorrentSpec(&spec)
247 func TestClientTransfer(t *testing.T) {
248 greetingTempDir, mi := testutil.GreetingTestTorrent()
249 defer os.RemoveAll(greetingTempDir)
252 cfg.DataDir = greetingTempDir
253 seeder, err := NewClient(&cfg)
258 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
259 leecherDataDir, err := ioutil.TempDir("", "")
263 defer os.RemoveAll(leecherDataDir)
264 // cfg.TorrentDataOpener = func(info *metainfo.Info) (data.Data, error) {
265 // return blob.TorrentData(info, leecherDataDir), nil
267 cfg.TorrentDataOpener = blob.NewStore(leecherDataDir).OpenTorrent
268 leecher, _ := NewClient(&cfg)
269 defer leecher.Close()
270 leecherGreeting, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
271 ret = TorrentSpecFromMetaInfo(mi)
275 leecherGreeting.AddPeers([]Peer{
277 IP: util.AddrIP(seeder.ListenAddr()),
278 Port: util.AddrPort(seeder.ListenAddr()),
281 r := leecherGreeting.NewReader()
283 _greeting, err := ioutil.ReadAll(r)
285 t.Fatalf("%q %s", string(_greeting), err)
287 greeting := string(_greeting)
288 if greeting != testutil.GreetingFileContents {
293 func TestReadaheadPieces(t *testing.T) {
294 for _, case_ := range []struct {
295 readaheadBytes, pieceLength int64
298 {5 * 1024 * 1024, 256 * 1024, 19},
299 {5 * 1024 * 1024, 5 * 1024 * 1024, 1},
300 {5*1024*1024 - 1, 5 * 1024 * 1024, 1},
301 {5 * 1024 * 1024, 5*1024*1024 - 1, 2},
302 {0, 5 * 1024 * 1024, 0},
303 {5 * 1024 * 1024, 1048576, 4},
305 pieces := readaheadPieces(case_.readaheadBytes, case_.pieceLength)
306 assert.Equal(t, case_.readaheadPieces, pieces, "%v", case_)
310 func (suite) TestMergingTrackersByAddingSpecs(c *check.C) {
311 cl, _ := NewClient(&TestingConfig)
313 spec := TorrentSpec{}
314 T, new, _ := cl.AddTorrentSpec(&spec)
318 spec.Trackers = [][]string{{"http://a"}, {"udp://b"}}
319 _, new, _ = cl.AddTorrentSpec(&spec)
323 c.Assert(T.Trackers[0][0].URL(), check.Equals, "http://a")
324 c.Assert(T.Trackers[1][0].URL(), check.Equals, "udp://b")
327 type badData struct {
330 func (me badData) WriteAt(b []byte, off int64) (int, error) {
334 func (me badData) WriteSectionTo(w io.Writer, off, n int64) (int64, error) {
338 func (me badData) PieceComplete(piece int) bool {
342 func (me badData) PieceCompleted(piece int) error {
346 func (me badData) ReadAt(b []byte, off int64) (n int, err error) {
351 n = copy(b, []byte("hello")[off:])
355 var _ StatefulData = badData{}
357 // We read from a piece which is marked completed, but is missing data.
358 func TestCompletedPieceWrongSize(t *testing.T) {
360 cfg.TorrentDataOpener = func(*metainfo.Info) data.Data {
363 cl, _ := NewClient(&cfg)
365 tt, new, err := cl.AddTorrentSpec(&TorrentSpec{
366 Info: &metainfo.InfoEx{
369 Pieces: make([]byte, 20),
370 Files: []metainfo.FileInfo{
371 metainfo.FileInfo{Path: []string{"greeting"}, Length: 13},
380 t.Fatal("expected new")
384 b := make([]byte, 20)
385 n, err := io.ReadFull(r, b)
386 if n != 5 || err != io.ErrUnexpectedEOF {
392 func BenchmarkAddLargeTorrent(b *testing.B) {
394 cfg.DisableTCP = true
395 cfg.DisableUTP = true
396 cfg.ListenAddr = "redonk"
397 cl, _ := NewClient(&cfg)
399 for range iter.N(b.N) {
400 t, err := cl.AddTorrentFromFile("testdata/bootstrap.dat.torrent")