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 DisableMetainfoCache: true,
45 DHTConfig: dht.ServerConfig{
46 NoDefaultBootstrap: true,
50 func TestClientDefault(t *testing.T) {
51 cl, err := NewClient(&TestingConfig)
52 require.NoError(t, err)
56 func TestAddDropTorrent(t *testing.T) {
57 cl, err := NewClient(&TestingConfig)
58 require.NoError(t, err)
60 dir, mi := testutil.GreetingTestTorrent()
61 defer os.RemoveAll(dir)
62 tt, new, err := cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
63 require.NoError(t, err)
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 := newTorrent(func() (ih metainfo.Hash) {
90 missinggo.CopyExact(ih[:], mi.Info.Hash)
94 tor.storageOpener = storage.NewFile(dir)
95 // Needed to lock for asynchronous piece verification.
97 err := tor.setMetadata(&mi.Info.Info, mi.Info.Bytes)
98 require.NoError(t, err)
99 require.Len(t, tor.pieces, 3)
100 tor.pendAllChunkSpecs(0)
101 assert.EqualValues(t, 3, tor.pieceNumPendingChunks(0))
102 assert.EqualValues(t, chunkSpec{4, 1}, chunkIndexSpec(2, tor.pieceLength(0), tor.chunkSize))
105 func TestUnmarshalPEXMsg(t *testing.T) {
106 var m peerExchangeMessage
107 if err := bencode.Unmarshal([]byte("d5:added12:\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0ce"), &m); err != nil {
110 if len(m.Added) != 2 {
113 if m.Added[0].Port != 0x506 {
118 func TestReducedDialTimeout(t *testing.T) {
119 for _, _case := range []struct {
123 ExpectedReduced time.Duration
125 {nominalDialTimeout, 40, 0, nominalDialTimeout},
126 {nominalDialTimeout, 40, 1, nominalDialTimeout},
127 {nominalDialTimeout, 40, 39, nominalDialTimeout},
128 {nominalDialTimeout, 40, 40, nominalDialTimeout / 2},
129 {nominalDialTimeout, 40, 80, nominalDialTimeout / 3},
130 {nominalDialTimeout, 40, 4000, nominalDialTimeout / 101},
132 reduced := reducedDialTimeout(_case.Max, _case.HalfOpenLimit, _case.PendingPeers)
133 expected := _case.ExpectedReduced
134 if expected < minDialTimeout {
135 expected = minDialTimeout
137 if reduced != expected {
138 t.Fatalf("expected %s, got %s", _case.ExpectedReduced, reduced)
143 func TestUTPRawConn(t *testing.T) {
144 l, err := utp.NewSocket("udp", "")
157 // Connect a UTP peer to see if the RawConn will still work.
158 s, _ := utp.NewSocket("udp", "")
160 utpPeer, err := s.Dial(fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr())))
162 t.Fatalf("error dialing utp listener: %s", err)
164 defer utpPeer.Close()
165 peer, err := net.ListenPacket("udp", ":0")
172 // How many messages to send. I've set this to double the channel buffer
173 // size in the raw packetConn.
175 readerStopped := make(chan struct{})
176 // The reader goroutine.
178 defer close(readerStopped)
179 b := make([]byte, 500)
180 for i := 0; i < N; i++ {
181 n, _, err := l.ReadFrom(b)
183 t.Fatalf("error reading from raw conn: %s", err)
187 fmt.Sscan(string(b[:n]), &d)
189 log.Printf("got wrong number: expected %d, got %d", i, d)
193 udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", missinggo.AddrPort(l.Addr())))
197 for i := 0; i < N; i++ {
198 _, err := peer.WriteTo([]byte(fmt.Sprintf("%d", i)), udpAddr)
202 time.Sleep(time.Microsecond)
205 case <-readerStopped:
206 case <-time.After(time.Second):
207 t.Fatal("reader timed out")
209 if msgsReceived != N {
210 t.Fatalf("messages received: %d", msgsReceived)
214 func TestTwoClientsArbitraryPorts(t *testing.T) {
215 for i := 0; i < 2; i++ {
216 cl, err := NewClient(&TestingConfig)
224 func TestAddDropManyTorrents(t *testing.T) {
225 cl, err := NewClient(&TestingConfig)
226 require.NoError(t, err)
228 for i := range iter.N(1000) {
230 binary.PutVarint(spec.InfoHash[:], int64(i))
231 tt, new, err := cl.AddTorrentSpec(&spec)
232 assert.NoError(t, err)
238 func TestClientTransferDefault(t *testing.T) {
239 testClientTransfer(t, testClientTransferParams{
240 ExportClientStatus: true,
244 func TestClientTransferSmallCache(t *testing.T) {
245 testClientTransfer(t, testClientTransferParams{
246 SetLeecherStorageCapacity: true,
247 // Going below the piece length means it can't complete a piece so
248 // that it can be hashed.
249 LeecherStorageCapacity: 5,
251 // Can't readahead too far or the cache will thrash and drop data we
254 ExportClientStatus: true,
258 func TestClientTransferVarious(t *testing.T) {
259 for _, ss := range []func(string) storage.I{
263 for _, responsive := range []bool{false, true} {
264 testClientTransfer(t, testClientTransferParams{
265 Responsive: responsive,
268 for _, readahead := range []int64{-1, 0, 1, 2, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15, 20} {
269 testClientTransfer(t, testClientTransferParams{
271 Responsive: responsive,
273 Readahead: readahead,
280 type testClientTransferParams struct {
284 ExportClientStatus bool
285 SetLeecherStorageCapacity bool
286 LeecherStorageCapacity int64
287 SeederStorage func(string) storage.I
290 func testClientTransfer(t *testing.T, ps testClientTransferParams) {
291 greetingTempDir, mi := testutil.GreetingTestTorrent()
292 defer os.RemoveAll(greetingTempDir)
295 if ps.SeederStorage != nil {
296 cfg.DefaultStorage = ps.SeederStorage(greetingTempDir)
298 cfg.DataDir = greetingTempDir
300 seeder, err := NewClient(&cfg)
301 require.NoError(t, err)
303 if ps.ExportClientStatus {
304 testutil.ExportStatusWriter(seeder, "s")
306 _, new, err := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
307 require.NoError(t, err)
309 leecherDataDir, err := ioutil.TempDir("", "")
310 require.NoError(t, err)
311 defer os.RemoveAll(leecherDataDir)
312 fc, err := filecache.NewCache(leecherDataDir)
313 require.NoError(t, err)
314 if ps.SetLeecherStorageCapacity {
315 fc.SetCapacity(ps.LeecherStorageCapacity)
317 cfg.DefaultStorage = storage.NewPieceFileStorage(fc.AsFileStore())
318 leecher, err := NewClient(&cfg)
319 require.NoError(t, err)
320 defer leecher.Close()
321 if ps.ExportClientStatus {
322 testutil.ExportStatusWriter(leecher, "l")
324 leecherGreeting, new, err := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
325 ret = TorrentSpecFromMetaInfo(mi)
327 ret.Storage = storage.NewFile(leecherDataDir)
330 require.NoError(t, err)
332 leecherGreeting.AddPeers([]Peer{
334 IP: missinggo.AddrIP(seeder.ListenAddr()),
335 Port: missinggo.AddrPort(seeder.ListenAddr()),
338 r := leecherGreeting.NewReader()
344 r.SetReadahead(ps.Readahead)
346 for range iter.N(2) {
347 pos, err := r.Seek(0, os.SEEK_SET)
348 assert.NoError(t, err)
349 assert.EqualValues(t, 0, pos)
350 _greeting, err := ioutil.ReadAll(r)
351 assert.NoError(t, err)
352 assert.EqualValues(t, testutil.GreetingFileContents, _greeting)
356 // Check that after completing leeching, a leecher transitions to a seeding
357 // correctly. Connected in a chain like so: Seeder <-> Leecher <-> LeecherLeecher.
358 func TestSeedAfterDownloading(t *testing.T) {
359 greetingTempDir, mi := testutil.GreetingTestTorrent()
360 defer os.RemoveAll(greetingTempDir)
363 cfg.DataDir = greetingTempDir
364 seeder, err := NewClient(&cfg)
365 require.NoError(t, err)
367 testutil.ExportStatusWriter(seeder, "s")
368 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
369 cfg.DataDir, err = ioutil.TempDir("", "")
370 require.NoError(t, err)
371 defer os.RemoveAll(cfg.DataDir)
372 leecher, err := NewClient(&cfg)
373 require.NoError(t, err)
374 defer leecher.Close()
375 testutil.ExportStatusWriter(leecher, "l")
377 // cfg.TorrentDataOpener = nil
378 cfg.DataDir, err = ioutil.TempDir("", "")
379 require.NoError(t, err)
380 defer os.RemoveAll(cfg.DataDir)
381 leecherLeecher, _ := NewClient(&cfg)
382 defer leecherLeecher.Close()
383 testutil.ExportStatusWriter(leecherLeecher, "ll")
384 leecherGreeting, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
385 ret = TorrentSpecFromMetaInfo(mi)
389 llg, _, _ := leecherLeecher.AddTorrentSpec(func() (ret *TorrentSpec) {
390 ret = TorrentSpecFromMetaInfo(mi)
394 // Simultaneously DownloadAll in Leecher, and read the contents
395 // consecutively in LeecherLeecher. This non-deterministically triggered a
396 // case where the leecher wouldn't unchoke the LeecherLeecher.
397 var wg sync.WaitGroup
403 b, err := ioutil.ReadAll(r)
404 require.NoError(t, err)
405 assert.EqualValues(t, testutil.GreetingFileContents, b)
407 leecherGreeting.AddPeers([]Peer{
409 IP: missinggo.AddrIP(seeder.ListenAddr()),
410 Port: missinggo.AddrPort(seeder.ListenAddr()),
413 IP: missinggo.AddrIP(leecherLeecher.ListenAddr()),
414 Port: missinggo.AddrPort(leecherLeecher.ListenAddr()),
420 leecherGreeting.DownloadAll()
426 func TestMergingTrackersByAddingSpecs(t *testing.T) {
427 cl, err := NewClient(&TestingConfig)
428 require.NoError(t, err)
430 spec := TorrentSpec{}
431 T, new, _ := cl.AddTorrentSpec(&spec)
435 spec.Trackers = [][]string{{"http://a"}, {"udp://b"}}
436 _, new, _ = cl.AddTorrentSpec(&spec)
440 assert.EqualValues(t, T.trackers[0][0], "http://a")
441 assert.EqualValues(t, T.trackers[1][0], "udp://b")
444 type badStorage struct{}
446 func (me badStorage) OpenTorrent(*metainfo.InfoEx) (storage.Torrent, error) {
450 func (me badStorage) Close() error {
454 func (me badStorage) Piece(p metainfo.Piece) storage.Piece {
455 return badStoragePiece{p}
458 type badStoragePiece struct {
462 func (me badStoragePiece) WriteAt(b []byte, off int64) (int, error) {
466 func (me badStoragePiece) GetIsComplete() bool {
470 func (me badStoragePiece) MarkComplete() error {
471 return errors.New("psyyyyyyyche")
474 func (me badStoragePiece) randomlyTruncatedDataString() string {
475 return "hello, world\n"[:rand.Intn(14)]
478 func (me badStoragePiece) ReadAt(b []byte, off int64) (n int, err error) {
479 r := strings.NewReader(me.randomlyTruncatedDataString())
480 return r.ReadAt(b, off+me.p.Offset())
483 // We read from a piece which is marked completed, but is missing data.
484 func TestCompletedPieceWrongSize(t *testing.T) {
486 cfg.DefaultStorage = badStorage{}
487 cl, _ := NewClient(&cfg)
489 tt, new, err := cl.AddTorrentSpec(&TorrentSpec{
490 Info: &metainfo.InfoEx{
493 Pieces: make([]byte, 20),
494 Files: []metainfo.FileInfo{
495 metainfo.FileInfo{Path: []string{"greeting"}, Length: 13},
500 require.NoError(t, err)
505 b, err := ioutil.ReadAll(r)
507 assert.NoError(t, err)
510 func BenchmarkAddLargeTorrent(b *testing.B) {
512 cfg.DisableTCP = true
513 cfg.DisableUTP = true
514 cfg.ListenAddr = "redonk"
515 cl, _ := NewClient(&cfg)
517 for range iter.N(b.N) {
518 t, err := cl.AddTorrentFromFile("testdata/bootstrap.dat.torrent")
526 func TestResponsive(t *testing.T) {
527 seederDataDir, mi := testutil.GreetingTestTorrent()
528 defer os.RemoveAll(seederDataDir)
531 cfg.DataDir = seederDataDir
532 seeder, err := NewClient(&cfg)
535 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
536 leecherDataDir, err := ioutil.TempDir("", "")
538 defer os.RemoveAll(leecherDataDir)
540 cfg.DataDir = leecherDataDir
541 leecher, err := NewClient(&cfg)
543 defer leecher.Close()
544 leecherTorrent, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
545 ret = TorrentSpecFromMetaInfo(mi)
549 leecherTorrent.AddPeers([]Peer{
551 IP: missinggo.AddrIP(seeder.ListenAddr()),
552 Port: missinggo.AddrPort(seeder.ListenAddr()),
555 reader := leecherTorrent.NewReader()
557 reader.SetReadahead(0)
558 reader.SetResponsive()
560 _, err = reader.Seek(3, os.SEEK_SET)
561 require.NoError(t, err)
562 _, err = io.ReadFull(reader, b)
564 assert.EqualValues(t, "lo", string(b))
565 _, err = reader.Seek(11, os.SEEK_SET)
566 require.NoError(t, err)
567 n, err := io.ReadFull(reader, b)
569 assert.EqualValues(t, 2, n)
570 assert.EqualValues(t, "d\n", string(b))
573 func TestTorrentDroppedDuringResponsiveRead(t *testing.T) {
574 seederDataDir, mi := testutil.GreetingTestTorrent()
575 defer os.RemoveAll(seederDataDir)
578 cfg.DataDir = seederDataDir
579 seeder, err := NewClient(&cfg)
582 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
583 leecherDataDir, err := ioutil.TempDir("", "")
585 defer os.RemoveAll(leecherDataDir)
587 cfg.DataDir = leecherDataDir
588 leecher, err := NewClient(&cfg)
590 defer leecher.Close()
591 leecherTorrent, _, _ := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
592 ret = TorrentSpecFromMetaInfo(mi)
596 leecherTorrent.AddPeers([]Peer{
598 IP: missinggo.AddrIP(seeder.ListenAddr()),
599 Port: missinggo.AddrPort(seeder.ListenAddr()),
602 reader := leecherTorrent.NewReader()
604 reader.SetReadahead(0)
605 reader.SetResponsive()
607 _, err = reader.Seek(3, os.SEEK_SET)
608 require.NoError(t, err)
609 _, err = io.ReadFull(reader, b)
611 assert.EqualValues(t, "lo", string(b))
612 go leecherTorrent.Drop()
613 _, err = reader.Seek(11, os.SEEK_SET)
614 require.NoError(t, err)
615 n, err := reader.Read(b)
616 assert.EqualError(t, err, "torrent closed")
617 assert.EqualValues(t, 0, n)
620 func TestDHTInheritBlocklist(t *testing.T) {
621 ipl := iplist.New(nil)
622 require.NotNil(t, ipl)
624 cfg.IPBlocklist = ipl
626 cl, err := NewClient(&cfg)
627 require.NoError(t, err)
629 require.Equal(t, ipl, cl.DHT().IPBlocklist())
632 // Check that stuff is merged in subsequent AddTorrentSpec for the same
634 func TestAddTorrentSpecMerging(t *testing.T) {
635 cl, err := NewClient(&TestingConfig)
636 require.NoError(t, err)
638 dir, mi := testutil.GreetingTestTorrent()
639 defer os.RemoveAll(dir)
641 missinggo.CopyExact(&ts.InfoHash, mi.Info.Hash)
642 tt, new, err := cl.AddTorrentSpec(&ts)
643 require.NoError(t, err)
645 require.Nil(t, tt.Info())
646 _, new, err = cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
647 require.NoError(t, err)
648 require.False(t, new)
649 require.NotNil(t, tt.Info())
652 // Check that torrent Info is obtained from the metainfo file cache.
653 func TestAddTorrentMetainfoInCache(t *testing.T) {
655 cfg.DisableMetainfoCache = false
656 cfg.ConfigDir, _ = ioutil.TempDir(os.TempDir(), "")
657 defer os.RemoveAll(cfg.ConfigDir)
658 cl, err := NewClient(&cfg)
659 require.NoError(t, err)
661 dir, mi := testutil.GreetingTestTorrent()
662 defer os.RemoveAll(dir)
663 tt, new, err := cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
664 require.NoError(t, err)
666 require.NotNil(t, tt.Info())
667 _, err = os.Stat(filepath.Join(cfg.ConfigDir, "torrents", fmt.Sprintf("%x.torrent", mi.Info.Hash.Bytes())))
668 require.NoError(t, err)
669 // Contains only the infohash.
671 missinggo.CopyExact(&ts.InfoHash, mi.Info.Hash)
672 _, ok := cl.Torrent(ts.InfoHash)
675 _, ok = cl.Torrent(ts.InfoHash)
677 tt, new, err = cl.AddTorrentSpec(&ts)
678 require.NoError(t, err)
680 // Obtained from the metainfo cache.
681 require.NotNil(t, tt.Info())
684 func TestTorrentDroppedBeforeGotInfo(t *testing.T) {
685 dir, mi := testutil.GreetingTestTorrent()
687 cl, _ := NewClient(&TestingConfig)
690 missinggo.CopyExact(&ts.InfoHash, mi.Info.Hash)
691 tt, _, _ := cl.AddTorrentSpec(&ts)
693 assert.EqualValues(t, 0, len(cl.Torrents()))
701 func writeTorrentData(ts storage.Torrent, info *metainfo.InfoEx, b []byte) {
702 for i := range iter.N(info.NumPieces()) {
703 n, _ := ts.Piece(info.Piece(i)).WriteAt(b, 0)
708 func testAddTorrentPriorPieceCompletion(t *testing.T, alreadyCompleted bool) {
709 fileCacheDir, err := ioutil.TempDir("", "")
710 require.NoError(t, err)
711 defer os.RemoveAll(fileCacheDir)
712 fileCache, err := filecache.NewCache(fileCacheDir)
713 require.NoError(t, err)
714 greetingDataTempDir, greetingMetainfo := testutil.GreetingTestTorrent()
715 defer os.RemoveAll(greetingDataTempDir)
716 filePieceStore := storage.NewPieceFileStorage(fileCache.AsFileStore())
717 greetingData, err := filePieceStore.OpenTorrent(&greetingMetainfo.Info)
718 require.NoError(t, err)
719 writeTorrentData(greetingData, &greetingMetainfo.Info, []byte(testutil.GreetingFileContents))
720 // require.Equal(t, len(testutil.GreetingFileContents), written)
721 // require.NoError(t, err)
722 for i := 0; i < greetingMetainfo.Info.NumPieces(); i++ {
723 p := greetingMetainfo.Info.Piece(i)
724 if alreadyCompleted {
725 err := greetingData.Piece(p).MarkComplete()
726 assert.NoError(t, err)
730 // TODO: Disable network option?
731 cfg.DisableTCP = true
732 cfg.DisableUTP = true
733 cfg.DefaultStorage = filePieceStore
734 cl, err := NewClient(&cfg)
735 require.NoError(t, err)
737 tt, err := cl.AddTorrent(greetingMetainfo)
738 require.NoError(t, err)
739 psrs := tt.PieceStateRuns()
740 assert.Len(t, psrs, 1)
741 assert.EqualValues(t, 3, psrs[0].Length)
742 assert.Equal(t, alreadyCompleted, psrs[0].Complete)
743 if alreadyCompleted {
745 b, err := ioutil.ReadAll(r)
746 assert.NoError(t, err)
747 assert.EqualValues(t, testutil.GreetingFileContents, b)
751 func TestAddTorrentPiecesAlreadyCompleted(t *testing.T) {
752 testAddTorrentPriorPieceCompletion(t, true)
755 func TestAddTorrentPiecesNotAlreadyCompleted(t *testing.T) {
756 testAddTorrentPriorPieceCompletion(t, false)
759 func TestAddMetainfoWithNodes(t *testing.T) {
762 // For now, we want to just jam the nodes into the table, without
763 // verifying them first. Also the DHT code doesn't support mixing secure
764 // and insecure nodes if security is enabled (yet).
765 cfg.DHTConfig.NoSecurity = true
766 cl, err := NewClient(&cfg)
767 require.NoError(t, err)
769 assert.EqualValues(t, cl.DHT().NumNodes(), 0)
770 tt, err := cl.AddTorrentFromFile("metainfo/testdata/issue_65a.torrent")
771 require.NoError(t, err)
772 assert.Len(t, tt.trackers, 5)
773 assert.EqualValues(t, 6, cl.DHT().NumNodes())
776 type testDownloadCancelParams struct {
780 ExportClientStatus bool
781 SetLeecherStorageCapacity bool
782 LeecherStorageCapacity int64
786 func testDownloadCancel(t *testing.T, ps testDownloadCancelParams) {
787 greetingTempDir, mi := testutil.GreetingTestTorrent()
788 defer os.RemoveAll(greetingTempDir)
791 cfg.DataDir = greetingTempDir
792 seeder, err := NewClient(&cfg)
793 require.NoError(t, err)
795 if ps.ExportClientStatus {
796 testutil.ExportStatusWriter(seeder, "s")
798 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
799 leecherDataDir, err := ioutil.TempDir("", "")
800 require.NoError(t, err)
801 defer os.RemoveAll(leecherDataDir)
802 fc, err := filecache.NewCache(leecherDataDir)
803 require.NoError(t, err)
804 if ps.SetLeecherStorageCapacity {
805 fc.SetCapacity(ps.LeecherStorageCapacity)
807 cfg.DefaultStorage = storage.NewPieceFileStorage(fc.AsFileStore())
808 cfg.DataDir = leecherDataDir
809 leecher, _ := NewClient(&cfg)
810 defer leecher.Close()
811 if ps.ExportClientStatus {
812 testutil.ExportStatusWriter(leecher, "l")
814 leecherGreeting, new, err := leecher.AddTorrentSpec(func() (ret *TorrentSpec) {
815 ret = TorrentSpecFromMetaInfo(mi)
819 require.NoError(t, err)
821 psc := leecherGreeting.SubscribePieceStateChanges()
823 leecherGreeting.DownloadAll()
825 leecherGreeting.CancelPieces(0, leecherGreeting.NumPieces())
827 leecherGreeting.AddPeers([]Peer{
829 IP: missinggo.AddrIP(seeder.ListenAddr()),
830 Port: missinggo.AddrPort(seeder.ListenAddr()),
833 completes := make(map[int]bool, 3)
836 // started := time.Now()
838 case _v := <-psc.Values:
839 // log.Print(time.Since(started))
840 v := _v.(PieceStateChange)
841 completes[v.Index] = v.Complete
842 case <-time.After(100 * time.Millisecond):
847 assert.EqualValues(t, map[int]bool{0: false, 1: false, 2: false}, completes)
849 assert.EqualValues(t, map[int]bool{0: true, 1: true, 2: true}, completes)
854 func TestTorrentDownloadAll(t *testing.T) {
855 testDownloadCancel(t, testDownloadCancelParams{})
858 func TestTorrentDownloadAllThenCancel(t *testing.T) {
859 testDownloadCancel(t, testDownloadCancelParams{
864 // Ensure that it's an error for a peer to send an invalid have message.
865 func TestPeerInvalidHave(t *testing.T) {
866 cl, err := NewClient(&TestingConfig)
867 require.NoError(t, err)
869 tt, _new, err := cl.AddTorrentSpec(&TorrentSpec{
870 Info: &metainfo.InfoEx{
873 Pieces: make([]byte, 20),
874 Files: []metainfo.FileInfo{{Length: 1}},
878 require.NoError(t, err)
884 assert.NoError(t, cn.peerSentHave(0))
885 assert.Error(t, cn.peerSentHave(1))
888 func TestPieceCompletedInStorageButNotClient(t *testing.T) {
889 greetingTempDir, greetingMetainfo := testutil.GreetingTestTorrent()
890 defer os.RemoveAll(greetingTempDir)
892 cfg.DataDir = greetingTempDir
893 seeder, err := NewClient(&TestingConfig)
894 require.NoError(t, err)
895 seeder.AddTorrentSpec(&TorrentSpec{
896 Info: &greetingMetainfo.Info,