15 _ "github.com/anacrolix/envpprof"
16 "github.com/anacrolix/utp"
17 "github.com/bradfitz/iter"
20 "github.com/anacrolix/torrent/bencode"
21 "github.com/anacrolix/torrent/data"
22 "github.com/anacrolix/torrent/data/blob"
23 "github.com/anacrolix/torrent/internal/testutil"
24 "github.com/anacrolix/torrent/metainfo"
25 "github.com/anacrolix/torrent/util"
29 log.SetFlags(log.LstdFlags | log.Lshortfile)
32 var TestingConfig = Config{
33 ListenAddr: "localhost:0",
35 DisableTrackers: true,
36 NoDefaultBlocklist: true,
37 DisableMetainfoCache: true,
38 DataDir: filepath.Join(os.TempDir(), "anacrolix"),
41 func TestClientDefault(t *testing.T) {
42 cl, err := NewClient(&TestingConfig)
49 func TestAddDropTorrent(t *testing.T) {
50 cl, err := NewClient(&TestingConfig)
55 dir, mi := testutil.GreetingTestTorrent()
56 defer os.RemoveAll(dir)
57 tt, new, err := cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
67 func TestAddTorrentNoSupportedTrackerSchemes(t *testing.T) {
71 func TestAddTorrentNoUsableURLs(t *testing.T) {
75 func TestAddPeersToUnknownTorrent(t *testing.T) {
79 func TestPieceHashSize(t *testing.T) {
80 if pieceHash.Size() != 20 {
85 func TestTorrentInitialState(t *testing.T) {
86 dir, mi := testutil.GreetingTestTorrent()
87 defer os.RemoveAll(dir)
88 tor, err := newTorrent(func() (ih InfoHash) {
89 util.CopyExact(ih[:], mi.Info.Hash)
95 err = tor.setMetadata(&mi.Info.Info, mi.Info.Bytes, nil)
99 if len(tor.Pieces) != 3 {
100 t.Fatal("wrong number of pieces")
103 tor.pendAllChunkSpecs(0)
104 if p.numPendingChunks() != 1 {
105 t.Fatalf("should only be 1 chunk: %v", p.PendingChunkSpecs)
107 // TODO: Set chunkSize to 2, to test odd/even silliness.
108 if chunkIndexSpec(0, tor.pieceLength(0)).Length != 5 {
109 t.Fatal("pending chunk spec is incorrect")
113 func TestUnmarshalPEXMsg(t *testing.T) {
114 var m peerExchangeMessage
115 if err := bencode.Unmarshal([]byte("d5:added12:\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0ce"), &m); err != nil {
118 if len(m.Added) != 2 {
121 if m.Added[0].Port != 0x506 {
126 func TestReducedDialTimeout(t *testing.T) {
127 for _, _case := range []struct {
131 ExpectedReduced time.Duration
133 {nominalDialTimeout, 40, 0, nominalDialTimeout},
134 {nominalDialTimeout, 40, 1, nominalDialTimeout},
135 {nominalDialTimeout, 40, 39, nominalDialTimeout},
136 {nominalDialTimeout, 40, 40, nominalDialTimeout / 2},
137 {nominalDialTimeout, 40, 80, nominalDialTimeout / 3},
138 {nominalDialTimeout, 40, 4000, nominalDialTimeout / 101},
140 reduced := reducedDialTimeout(_case.Max, _case.HalfOpenLimit, _case.PendingPeers)
141 expected := _case.ExpectedReduced
142 if expected < minDialTimeout {
143 expected = minDialTimeout
145 if reduced != expected {
146 t.Fatalf("expected %s, got %s", _case.ExpectedReduced, reduced)
151 func TestUTPRawConn(t *testing.T) {
152 l, err := utp.NewSocket("")
165 // Connect a UTP peer to see if the RawConn will still work.
166 utpPeer, err := func() *utp.Socket {
167 s, _ := utp.NewSocket("")
169 }().Dial(fmt.Sprintf("localhost:%d", util.AddrPort(l.Addr())))
171 t.Fatalf("error dialing utp listener: %s", err)
173 defer utpPeer.Close()
174 peer, err := net.ListenPacket("udp", ":0")
181 // How many messages to send. I've set this to double the channel buffer
182 // size in the raw packetConn.
184 readerStopped := make(chan struct{})
185 // The reader goroutine.
187 defer close(readerStopped)
188 b := make([]byte, 500)
189 for i := 0; i < N; i++ {
190 n, _, err := l.PacketConn().ReadFrom(b)
192 t.Fatalf("error reading from raw conn: %s", err)
196 fmt.Sscan(string(b[:n]), &d)
198 log.Printf("got wrong number: expected %d, got %d", i, d)
202 udpAddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", util.AddrPort(l.Addr())))
206 for i := 0; i < N; i++ {
207 _, err := peer.WriteTo([]byte(fmt.Sprintf("%d", i)), udpAddr)
211 time.Sleep(time.Microsecond)
214 case <-readerStopped:
215 case <-time.After(time.Second):
216 t.Fatal("reader timed out")
218 if msgsReceived != N {
219 t.Fatalf("messages received: %d", msgsReceived)
223 func TestTwoClientsArbitraryPorts(t *testing.T) {
224 for i := 0; i < 2; i++ {
225 cl, err := NewClient(&TestingConfig)
233 func TestAddDropManyTorrents(t *testing.T) {
234 cl, _ := NewClient(&TestingConfig)
236 for i := range iter.N(1000) {
238 binary.PutVarint(spec.InfoHash[:], int64(i))
239 tt, new, err := cl.AddTorrentSpec(&spec)
250 func TestClientTransfer(t *testing.T) {
251 greetingTempDir, mi := testutil.GreetingTestTorrent()
252 defer os.RemoveAll(greetingTempDir)
255 cfg.DataDir = greetingTempDir
256 seeder, err := NewClient(&cfg)
261 seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
262 leecherDataDir, err := ioutil.TempDir("", "")
266 defer os.RemoveAll(leecherDataDir)
267 // cfg.TorrentDataOpener = func(info *metainfo.Info) (data.Data, error) {
268 // return blob.TorrentData(info, leecherDataDir), nil
270 cfg.TorrentDataOpener = blob.NewStore(leecherDataDir).OpenTorrent
271 leecher, _ := NewClient(&cfg)
272 defer leecher.Close()
273 leecherGreeting, _, _ := leecher.AddTorrentSpec(TorrentSpecFromMetaInfo(mi))
274 leecherGreeting.AddPeers([]Peer{
276 IP: util.AddrIP(seeder.ListenAddr()),
277 Port: util.AddrPort(seeder.ListenAddr()),
280 r := leecherGreeting.NewReader()
282 _greeting, err := ioutil.ReadAll(r)
284 t.Fatalf("%q %s", string(_greeting), err)
286 greeting := string(_greeting)
287 if greeting != testutil.GreetingFileContents {
292 func TestReadaheadPieces(t *testing.T) {
293 for _, case_ := range []struct {
294 readaheadBytes, pieceLength int64
297 {5 * 1024 * 1024, 256 * 1024, 19},
298 {5 * 1024 * 1024, 5 * 1024 * 1024, 0},
299 {5*1024*1024 - 1, 5 * 1024 * 1024, 0},
300 {5 * 1024 * 1024, 5*1024*1024 - 1, 1},
301 {0, 5 * 1024 * 1024, -1},
302 {5 * 1024 * 1024, 1048576, 4},
304 if readaheadPieces(case_.readaheadBytes, case_.pieceLength) != case_.readaheadPieces {
305 t.Fatalf("case failed: %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 {