19 _ "github.com/anacrolix/envpprof"
20 "github.com/anacrolix/missinggo"
21 "github.com/anacrolix/missinggo/filecache"
22 "github.com/anacrolix/utp"
23 "github.com/bradfitz/iter"
24 "github.com/stretchr/testify/assert"
25 "github.com/stretchr/testify/require"
27 "github.com/anacrolix/torrent/bencode"
28 "github.com/anacrolix/torrent/dht"
29 "github.com/anacrolix/torrent/internal/testutil"
30 "github.com/anacrolix/torrent/iplist"
31 "github.com/anacrolix/torrent/metainfo"
32 "github.com/anacrolix/torrent/storage"
36 log.SetFlags(log.LstdFlags | log.Llongfile)
39 var TestingConfig = Config{
40 ListenAddr: "localhost:0",
42 DisableTrackers: true,
43 NoDefaultBlocklist: true,
44 DisableMetainfoCache: true,
46 DHTConfig: dht.ServerConfig{
47 NoDefaultBootstrap: true,
51 func TestClientDefault(t *testing.T) {
52 cl, err := NewClient(&TestingConfig)
53 require.NoError(t, err)
57 func TestAddDropTorrent(t *testing.T) {
58 cl, err := NewClient(&TestingConfig)
59 require.NoError(t, err)
61 dir, mi := testutil.GreetingTestTorrent()
62 defer os.RemoveAll(dir)
63 tt, new, err := cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
64 require.NoError(t, err)
69 func TestAddTorrentNoSupportedTrackerSchemes(t *testing.T) {
73 func TestAddTorrentNoUsableURLs(t *testing.T) {
77 func TestAddPeersToUnknownTorrent(t *testing.T) {
81 func TestPieceHashSize(t *testing.T) {
82 if pieceHash.Size() != 20 {
87 func TestTorrentInitialState(t *testing.T) {
88 dir, mi := testutil.GreetingTestTorrent()
89 defer os.RemoveAll(dir)
90 tor := newTorrent(func() (ih metainfo.Hash) {
91 missinggo.CopyExact(ih[:], mi.Info.Hash)
95 tor.storageOpener = storage.NewFile(dir)
96 // Needed to lock for asynchronous piece verification.
98 err := tor.setMetadata(&mi.Info.Info, mi.Info.Bytes)
99 require.NoError(t, err)
100 require.Len(t, tor.pieces, 3)
101 tor.pendAllChunkSpecs(0)
102 assert.EqualValues(t, 3, tor.pieceNumPendingChunks(0))
103 assert.EqualValues(t, chunkSpec{4, 1}, chunkIndexSpec(2, tor.pieceLength(0), tor.chunkSize))
106 func TestUnmarshalPEXMsg(t *testing.T) {
107 var m peerExchangeMessage
108 if err := bencode.Unmarshal([]byte("d5:added12:\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0ce"), &m); err != nil {
111 if len(m.Added) != 2 {
114 if m.Added[0].Port != 0x506 {
119 func TestReducedDialTimeout(t *testing.T) {
120 for _, _case := range []struct {
124 ExpectedReduced time.Duration
126 {nominalDialTimeout, 40, 0, nominalDialTimeout},
127 {nominalDialTimeout, 40, 1, nominalDialTimeout},
128 {nominalDialTimeout, 40, 39, nominalDialTimeout},
129 {nominalDialTimeout, 40, 40, nominalDialTimeout / 2},
130 {nominalDialTimeout, 40, 80, nominalDialTimeout / 3},
131 {nominalDialTimeout, 40, 4000, nominalDialTimeout / 101},
133 reduced := reducedDialTimeout(_case.Max, _case.HalfOpenLimit, _case.PendingPeers)
134 expected := _case.ExpectedReduced
135 if expected < minDialTimeout {
136 expected = minDialTimeout
138 if reduced != expected {
139 t.Fatalf("expected %s, got %s", _case.ExpectedReduced, reduced)
144 func TestUTPRawConn(t *testing.T) {
145 l, err := utp.NewSocket("udp", "")
158 // Connect a UTP peer to see if the RawConn will still work.
159 s, _ := utp.NewSocket("udp", "")
161 utpPeer, err := s.Dial(fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr())))
163 t.Fatalf("error dialing utp listener: %s", err)
165 defer utpPeer.Close()
166 peer, err := net.ListenPacket("udp", ":0")
173 // How many messages to send. I've set this to double the channel buffer
174 // size in the raw packetConn.
176 readerStopped := make(chan struct{})
177 // The reader goroutine.
179 defer close(readerStopped)
180 b := make([]byte, 500)
181 for i := 0; i < N; i++ {
182 n, _, err := l.ReadFrom(b)
184 t.Fatalf("error reading from raw conn: %s", err)
188 fmt.Sscan(string(b[:n]), &d)
190 log.Printf("got wrong number: expected %d, got %d", i, d)
194 udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr())))
198 for i := 0; i < N; i++ {
199 _, err := peer.WriteTo([]byte(fmt.Sprintf("%d", i)), udpAddr)
203 time.Sleep(time.Microsecond)
206 case <-readerStopped:
207 case <-time.After(time.Second):
208 t.Fatal("reader timed out")
210 if msgsReceived != N {
211 t.Fatalf("messages received: %d", msgsReceived)
215 func TestTwoClientsArbitraryPorts(t *testing.T) {
216 for i := 0; i < 2; i++ {
217 cl, err := NewClient(&TestingConfig)
225 func TestAddDropManyTorrents(t *testing.T) {
226 cl, err := NewClient(&TestingConfig)
227 require.NoError(t, err)
229 for i := range iter.N(1000) {
231 binary.PutVarint(spec.InfoHash[:], int64(i))
232 tt, new, err := cl.AddTorrentSpec(&spec)
233 assert.NoError(t, err)
239 func TestClientTransferDefault(t *testing.T) {
240 testClientTransfer(t, testClientTransferParams{
241 ExportClientStatus: true,
245 func TestClientTransferSmallCache(t *testing.T) {
246 testClientTransfer(t, testClientTransferParams{
247 SetLeecherStorageCapacity: true,
248 // Going below the piece length means it can't complete a piece so
249 // that it can be hashed.
250 LeecherStorageCapacity: 5,
252 // Can't readahead too far or the cache will thrash and drop data we
255 ExportClientStatus: true,
259 func TestClientTransferVarious(t *testing.T) {
260 for _, ss := range []func(string) storage.I{
264 for _, responsive := range []bool{false, true} {
265 testClientTransfer(t, testClientTransferParams{
266 Responsive: responsive,
269 for _, readahead := range []int64{-1, 0, 1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15, 20} {
270 testClientTransfer(t, testClientTransferParams{
272 Responsive: responsive,
274 Readahead: readahead,
281 type testClientTransferParams struct {
285 ExportClientStatus bool
286 SetLeecherStorageCapacity bool
287 LeecherStorageCapacity int64
288 SeederStorage func(string) storage.I
291 func testClientTransfer(t *testing.T, ps testClientTransferParams) {
292 greetingTempDir, mi := testutil.GreetingTestTorrent()
293 defer os.RemoveAll(greetingTempDir)
296 if ps.SeederStorage != nil {
297 cfg.DefaultStorage = ps.SeederStorage(greetingTempDir)
299 cfg.DataDir = greetingTempDir
301 seeder, err := NewClient(&cfg)
302 require.NoError(t, err)
304 if ps.ExportClientStatus {
305 testutil.ExportStatusWriter(seeder, "s")
307 _, new, err := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
308 require.NoError(t, err)
310 leecherDataDir, err := ioutil.TempDir("", "")
311 require.NoError(t, err)
312 defer os.RemoveAll(leecherDataDir)
313 fc, err := filecache.NewCache(leecherDataDir)
314 require.NoError(t, err)
315 if ps.SetLeecherStorageCapacity {
316 fc.SetCapacity(ps.LeecherStorageCapacity)
318 cfg.DefaultStorage = storage.NewPieceFileStorage(fc.AsFileStore())
319 leecher, err := NewClient(&cfg)
320 require.NoError(t, err)
321 defer leecher.Close()
322 if ps.ExportClientStatus {
323 testutil.ExportStatusWriter(leecher, "l")
325 leecherGreeting, new, err := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
326 ret = TorrentSpecFromMetaInfo(mi)
328 ret.Storage = storage.NewFile(leecherDataDir)
331 require.NoError(t, err)
333 leecherGreeting.AddPeers([]Peer{
335 IP: missinggo.AddrIP(seeder.ListenAddr()),
336 Port: missinggo.AddrPort(seeder.ListenAddr()),
339 r := leecherGreeting.NewReader()
345 r.SetReadahead(ps.Readahead)
347 for range iter.N(2) {
348 pos, err := r.Seek(0, os.SEEK_SET)
349 assert.NoError(t, err)
350 assert.EqualValues(t, 0, pos)
351 _greeting, err := ioutil.ReadAll(r)
352 assert.NoError(t, err)
353 assert.EqualValues(t, testutil.GreetingFileContents, _greeting)
357 // Check that after completing leeching, a leecher transitions to a seeding
358 // correctly. Connected in a chain like so: Seeder <-> Leecher <-> LeecherLeecher.
359 func TestSeedAfterDownloading(t *testing.T) {
360 greetingTempDir, mi := testutil.GreetingTestTorrent()
361 defer os.RemoveAll(greetingTempDir)
364 cfg.DataDir = greetingTempDir
365 seeder, err := NewClient(&cfg)
366 require.NoError(t, err)
368 testutil.ExportStatusWriter(seeder, "s")
369 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
370 cfg.DataDir, err = ioutil.TempDir("", "")
371 require.NoError(t, err)
372 defer os.RemoveAll(cfg.DataDir)
373 leecher, err := NewClient(&cfg)
374 require.NoError(t, err)
375 defer leecher.Close()
376 testutil.ExportStatusWriter(leecher, "l")
378 // cfg.TorrentDataOpener = nil
379 cfg.DataDir, err = ioutil.TempDir("", "")
380 require.NoError(t, err)
381 defer os.RemoveAll(cfg.DataDir)
382 leecherLeecher, _ := NewClient(&cfg)
383 defer leecherLeecher.Close()
384 testutil.ExportStatusWriter(leecherLeecher, "ll")
385 leecherGreeting, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
386 ret = TorrentSpecFromMetaInfo(mi)
390 llg, _, _ := leecherLeecher.AddTorrentSpec(func() (ret *TorrentSpec) {
391 ret = TorrentSpecFromMetaInfo(mi)
395 // Simultaneously DownloadAll in Leecher, and read the contents
396 // consecutively in LeecherLeecher. This non-deterministically triggered a
397 // case where the leecher wouldn't unchoke the LeecherLeecher.
398 var wg sync.WaitGroup
404 b, err := ioutil.ReadAll(r)
405 require.NoError(t, err)
406 assert.EqualValues(t, testutil.GreetingFileContents, b)
408 leecherGreeting.AddPeers([]Peer{
410 IP: missinggo.AddrIP(seeder.ListenAddr()),
411 Port: missinggo.AddrPort(seeder.ListenAddr()),
414 IP: missinggo.AddrIP(leecherLeecher.ListenAddr()),
415 Port: missinggo.AddrPort(leecherLeecher.ListenAddr()),
421 leecherGreeting.DownloadAll()
427 func TestReadaheadPieces(t *testing.T) {
428 for _, case_ := range []struct {
429 readaheadBytes, pieceLength int64
432 {5 * 1024 * 1024, 256 * 1024, 19},
433 {5 * 1024 * 1024, 5 * 1024 * 1024, 1},
434 {5*1024*1024 - 1, 5 * 1024 * 1024, 1},
435 {5 * 1024 * 1024, 5*1024*1024 - 1, 2},
436 {0, 5 * 1024 * 1024, 0},
437 {5 * 1024 * 1024, 1048576, 4},
439 pieces := readaheadPieces(case_.readaheadBytes, case_.pieceLength)
440 assert.Equal(t, case_.readaheadPieces, pieces, "%v", case_)
444 func TestMergingTrackersByAddingSpecs(t *testing.T) {
445 cl, err := NewClient(&TestingConfig)
446 require.NoError(t, err)
448 spec := TorrentSpec{}
449 T, new, _ := cl.AddTorrentSpec(&spec)
453 spec.Trackers = [][]string{{"http://a"}, {"udp://b"}}
454 _, new, _ = cl.AddTorrentSpec(&spec)
458 assert.EqualValues(t, T.trackers[0][0], "http://a")
459 assert.EqualValues(t, T.trackers[1][0], "udp://b")
462 type badStorage struct{}
464 func (me badStorage) OpenTorrent(*metainfo.InfoEx) (storage.Torrent, error) {
468 func (me badStorage) Close() error {
472 func (me badStorage) Piece(p metainfo.Piece) storage.Piece {
473 return badStoragePiece{p}
476 type badStoragePiece struct {
480 func (me badStoragePiece) WriteAt(b []byte, off int64) (int, error) {
484 func (me badStoragePiece) GetIsComplete() bool {
488 func (me badStoragePiece) MarkComplete() error {
489 return errors.New("psyyyyyyyche")
492 func (me badStoragePiece) randomlyTruncatedDataString() string {
493 return "hello, world\n"[:rand.Intn(14)]
496 func (me badStoragePiece) ReadAt(b []byte, off int64) (n int, err error) {
497 r := strings.NewReader(me.randomlyTruncatedDataString())
498 return r.ReadAt(b, off+me.p.Offset())
501 // We read from a piece which is marked completed, but is missing data.
502 func TestCompletedPieceWrongSize(t *testing.T) {
504 cfg.DefaultStorage = badStorage{}
505 cl, _ := NewClient(&cfg)
507 tt, new, err := cl.AddTorrentSpec(&TorrentSpec{
508 Info: &metainfo.InfoEx{
511 Pieces: make([]byte, 20),
512 Files: []metainfo.FileInfo{
513 metainfo.FileInfo{Path: []string{"greeting"}, Length: 13},
518 require.NoError(t, err)
523 b, err := ioutil.ReadAll(r)
525 assert.NoError(t, err)
528 func BenchmarkAddLargeTorrent(b *testing.B) {
530 cfg.DisableTCP = true
531 cfg.DisableUTP = true
532 cfg.ListenAddr = "redonk"
533 cl, _ := NewClient(&cfg)
535 for range iter.N(b.N) {
536 t, err := cl.AddTorrentFromFile("testdata/bootstrap.dat.torrent")
544 func TestResponsive(t *testing.T) {
545 seederDataDir, mi := testutil.GreetingTestTorrent()
546 defer os.RemoveAll(seederDataDir)
549 cfg.DataDir = seederDataDir
550 seeder, err := NewClient(&cfg)
553 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
554 leecherDataDir, err := ioutil.TempDir("", "")
556 defer os.RemoveAll(leecherDataDir)
558 cfg.DataDir = leecherDataDir
559 leecher, err := NewClient(&cfg)
561 defer leecher.Close()
562 leecherTorrent, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
563 ret = TorrentSpecFromMetaInfo(mi)
567 leecherTorrent.AddPeers([]Peer{
569 IP: missinggo.AddrIP(seeder.ListenAddr()),
570 Port: missinggo.AddrPort(seeder.ListenAddr()),
573 reader := leecherTorrent.NewReader()
575 reader.SetReadahead(0)
576 reader.SetResponsive()
578 _, err = reader.Seek(3, os.SEEK_SET)
579 require.NoError(t, err)
580 _, err = io.ReadFull(reader, b)
582 assert.EqualValues(t, "lo", string(b))
583 _, err = reader.Seek(11, os.SEEK_SET)
584 require.NoError(t, err)
585 n, err := io.ReadFull(reader, b)
587 assert.EqualValues(t, 2, n)
588 assert.EqualValues(t, "d\n", string(b))
591 func TestTorrentDroppedDuringResponsiveRead(t *testing.T) {
592 seederDataDir, mi := testutil.GreetingTestTorrent()
593 defer os.RemoveAll(seederDataDir)
596 cfg.DataDir = seederDataDir
597 seeder, err := NewClient(&cfg)
600 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
601 leecherDataDir, err := ioutil.TempDir("", "")
603 defer os.RemoveAll(leecherDataDir)
605 cfg.DataDir = leecherDataDir
606 leecher, err := NewClient(&cfg)
608 defer leecher.Close()
609 leecherTorrent, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
610 ret = TorrentSpecFromMetaInfo(mi)
614 leecherTorrent.AddPeers([]Peer{
616 IP: missinggo.AddrIP(seeder.ListenAddr()),
617 Port: missinggo.AddrPort(seeder.ListenAddr()),
620 reader := leecherTorrent.NewReader()
622 reader.SetReadahead(0)
623 reader.SetResponsive()
625 _, err = reader.Seek(3, os.SEEK_SET)
626 require.NoError(t, err)
627 _, err = io.ReadFull(reader, b)
629 assert.EqualValues(t, "lo", string(b))
630 go leecherTorrent.Drop()
631 _, err = reader.Seek(11, os.SEEK_SET)
632 require.NoError(t, err)
633 n, err := reader.Read(b)
634 assert.EqualError(t, err, "torrent closed")
635 assert.EqualValues(t, 0, n)
638 func TestDHTInheritBlocklist(t *testing.T) {
639 ipl := iplist.New(nil)
640 require.NotNil(t, ipl)
642 cfg.IPBlocklist = ipl
644 cl, err := NewClient(&cfg)
645 require.NoError(t, err)
647 require.Equal(t, ipl, cl.DHT().IPBlocklist())
650 // Check that stuff is merged in subsequent AddTorrentSpec for the same
652 func TestAddTorrentSpecMerging(t *testing.T) {
653 cl, err := NewClient(&TestingConfig)
654 require.NoError(t, err)
656 dir, mi := testutil.GreetingTestTorrent()
657 defer os.RemoveAll(dir)
659 missinggo.CopyExact(&ts.InfoHash, mi.Info.Hash)
660 tt, new, err := cl.AddTorrentSpec(&ts)
661 require.NoError(t, err)
663 require.Nil(t, tt.Info())
664 _, new, err = cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
665 require.NoError(t, err)
666 require.False(t, new)
667 require.NotNil(t, tt.Info())
670 // Check that torrent Info is obtained from the metainfo file cache.
671 func TestAddTorrentMetainfoInCache(t *testing.T) {
673 cfg.DisableMetainfoCache = false
674 cfg.ConfigDir, _ = ioutil.TempDir(os.TempDir(), "")
675 defer os.RemoveAll(cfg.ConfigDir)
676 cl, err := NewClient(&cfg)
677 require.NoError(t, err)
679 dir, mi := testutil.GreetingTestTorrent()
680 defer os.RemoveAll(dir)
681 tt, new, err := cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
682 require.NoError(t, err)
684 require.NotNil(t, tt.Info())
685 _, err = os.Stat(filepath.Join(cfg.ConfigDir, "torrents", fmt.Sprintf("%x.torrent", mi.Info.Hash.Bytes())))
686 require.NoError(t, err)
687 // Contains only the infohash.
689 missinggo.CopyExact(&ts.InfoHash, mi.Info.Hash)
690 _, ok := cl.Torrent(ts.InfoHash)
693 _, ok = cl.Torrent(ts.InfoHash)
695 tt, new, err = cl.AddTorrentSpec(&ts)
696 require.NoError(t, err)
698 // Obtained from the metainfo cache.
699 require.NotNil(t, tt.Info())
702 func TestTorrentDroppedBeforeGotInfo(t *testing.T) {
703 dir, mi := testutil.GreetingTestTorrent()
705 cl, _ := NewClient(&TestingConfig)
708 missinggo.CopyExact(&ts.InfoHash, mi.Info.Hash)
709 tt, _, _ := cl.AddTorrentSpec(&ts)
711 assert.EqualValues(t, 0, len(cl.Torrents()))
719 func writeTorrentData(ts storage.Torrent, info *metainfo.InfoEx, b []byte) {
720 for i := range iter.N(info.NumPieces()) {
721 n, _ := ts.Piece(info.Piece(i)).WriteAt(b, 0)
726 func testAddTorrentPriorPieceCompletion(t *testing.T, alreadyCompleted bool) {
727 fileCacheDir, err := ioutil.TempDir("", "")
728 require.NoError(t, err)
729 defer os.RemoveAll(fileCacheDir)
730 fileCache, err := filecache.NewCache(fileCacheDir)
731 require.NoError(t, err)
732 greetingDataTempDir, greetingMetainfo := testutil.GreetingTestTorrent()
733 defer os.RemoveAll(greetingDataTempDir)
734 filePieceStore := storage.NewPieceFileStorage(fileCache.AsFileStore())
735 greetingData, err := filePieceStore.OpenTorrent(&greetingMetainfo.Info)
736 require.NoError(t, err)
737 writeTorrentData(greetingData, &greetingMetainfo.Info, []byte(testutil.GreetingFileContents))
738 // require.Equal(t, len(testutil.GreetingFileContents), written)
739 // require.NoError(t, err)
740 for i := 0; i < greetingMetainfo.Info.NumPieces(); i++ {
741 p := greetingMetainfo.Info.Piece(i)
742 if alreadyCompleted {
743 err := greetingData.Piece(p).MarkComplete()
744 assert.NoError(t, err)
748 // TODO: Disable network option?
749 cfg.DisableTCP = true
750 cfg.DisableUTP = true
751 cfg.DefaultStorage = filePieceStore
752 cl, err := NewClient(&cfg)
753 require.NoError(t, err)
755 tt, err := cl.AddTorrent(greetingMetainfo)
756 require.NoError(t, err)
757 psrs := tt.PieceStateRuns()
758 assert.Len(t, psrs, 1)
759 assert.EqualValues(t, 3, psrs[0].Length)
760 assert.Equal(t, alreadyCompleted, psrs[0].Complete)
761 if alreadyCompleted {
763 b, err := ioutil.ReadAll(r)
764 assert.NoError(t, err)
765 assert.EqualValues(t, testutil.GreetingFileContents, b)
769 func TestAddTorrentPiecesAlreadyCompleted(t *testing.T) {
770 testAddTorrentPriorPieceCompletion(t, true)
773 func TestAddTorrentPiecesNotAlreadyCompleted(t *testing.T) {
774 testAddTorrentPriorPieceCompletion(t, false)
777 func TestAddMetainfoWithNodes(t *testing.T) {
780 // For now, we want to just jam the nodes into the table, without
781 // verifying them first. Also the DHT code doesn't support mixing secure
782 // and insecure nodes if security is enabled (yet).
783 cfg.DHTConfig.NoSecurity = true
784 cl, err := NewClient(&cfg)
785 require.NoError(t, err)
787 assert.EqualValues(t, cl.DHT().NumNodes(), 0)
788 tt, err := cl.AddTorrentFromFile("metainfo/testdata/issue_65a.torrent")
789 require.NoError(t, err)
790 assert.Len(t, tt.trackers, 5)
791 assert.EqualValues(t, 6, cl.DHT().NumNodes())
794 type testDownloadCancelParams struct {
798 ExportClientStatus bool
799 SetLeecherStorageCapacity bool
800 LeecherStorageCapacity int64
804 func testDownloadCancel(t *testing.T, ps testDownloadCancelParams) {
805 greetingTempDir, mi := testutil.GreetingTestTorrent()
806 defer os.RemoveAll(greetingTempDir)
809 cfg.DataDir = greetingTempDir
810 seeder, err := NewClient(&cfg)
811 require.NoError(t, err)
813 if ps.ExportClientStatus {
814 testutil.ExportStatusWriter(seeder, "s")
816 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
817 leecherDataDir, err := ioutil.TempDir("", "")
818 require.NoError(t, err)
819 defer os.RemoveAll(leecherDataDir)
820 fc, err := filecache.NewCache(leecherDataDir)
821 require.NoError(t, err)
822 if ps.SetLeecherStorageCapacity {
823 fc.SetCapacity(ps.LeecherStorageCapacity)
825 cfg.DefaultStorage = storage.NewPieceFileStorage(fc.AsFileStore())
826 cfg.DataDir = leecherDataDir
827 leecher, _ := NewClient(&cfg)
828 defer leecher.Close()
829 if ps.ExportClientStatus {
830 testutil.ExportStatusWriter(leecher, "l")
832 leecherGreeting, new, err := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
833 ret = TorrentSpecFromMetaInfo(mi)
837 require.NoError(t, err)
839 psc := leecherGreeting.SubscribePieceStateChanges()
841 leecherGreeting.DownloadAll()
843 leecherGreeting.CancelPieces(0, leecherGreeting.NumPieces())
845 leecherGreeting.AddPeers([]Peer{
847 IP: missinggo.AddrIP(seeder.ListenAddr()),
848 Port: missinggo.AddrPort(seeder.ListenAddr()),
851 completes := make(map[int]bool, 3)
854 // started := time.Now()
856 case _v := <-psc.Values:
857 // log.Print(time.Since(started))
858 v := _v.(PieceStateChange)
859 completes[v.Index] = v.Complete
860 case <-time.After(100 * time.Millisecond):
865 assert.EqualValues(t, map[int]bool{0: false, 1: false, 2: false}, completes)
867 assert.EqualValues(t, map[int]bool{0: true, 1: true, 2: true}, completes)
872 func TestTorrentDownloadAll(t *testing.T) {
873 testDownloadCancel(t, testDownloadCancelParams{})
876 func TestTorrentDownloadAllThenCancel(t *testing.T) {
877 testDownloadCancel(t, testDownloadCancelParams{
882 // Ensure that it's an error for a peer to send an invalid have message.
883 func TestPeerInvalidHave(t *testing.T) {
884 cl, err := NewClient(&TestingConfig)
885 require.NoError(t, err)
887 tt, _new, err := cl.AddTorrentSpec(&TorrentSpec{
888 Info: &metainfo.InfoEx{
891 Pieces: make([]byte, 20),
892 Files: []metainfo.FileInfo{{Length: 1}},
896 require.NoError(t, err)
902 assert.NoError(t, cn.peerSentHave(0))
903 assert.Error(t, cn.peerSentHave(1))
906 func TestPieceCompletedInStorageButNotClient(t *testing.T) {
907 greetingTempDir, greetingMetainfo := testutil.GreetingTestTorrent()
908 defer os.RemoveAll(greetingTempDir)
910 cfg.DataDir = greetingTempDir
911 seeder, err := NewClient(&TestingConfig)
912 require.NoError(t, err)
913 seeder.AddTorrentSpec(&TorrentSpec{
914 Info: &greetingMetainfo.Info,