X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=client_test.go;h=d2a88e9e7a769abcd1871092c006e37b33573a51;hb=HEAD;hp=84a99f469fb8beb361abd6d827719f08f5a397af;hpb=ebd19af7951b9a2f409f08e03e7edb3bf9c8ac14;p=btrtrc.git diff --git a/client_test.go b/client_test.go index 84a99f46..d2a88e9e 100644 --- a/client_test.go +++ b/client_test.go @@ -4,7 +4,8 @@ import ( "encoding/binary" "fmt" "io" - "io/ioutil" + "net" + "net/netip" "os" "path/filepath" "reflect" @@ -12,15 +13,15 @@ import ( "testing/iotest" "time" - "github.com/bradfitz/iter" + "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/dht/v2" - "github.com/anacrolix/missinggo" - "github.com/anacrolix/missinggo/v2/filecache" - "github.com/anacrolix/torrent/bencode" "github.com/anacrolix/torrent/internal/testutil" "github.com/anacrolix/torrent/iplist" @@ -31,29 +32,17 @@ import ( 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() -} - -func TestBoltPieceCompletionClosedWhenClientClosed(t *testing.T) { - cfg := TestingConfig(t) - pc, err := storage.NewBoltPieceCompletion(cfg.DataDir) - require.NoError(t, err) - ci := storage.NewFileWithCompletion(cfg.DataDir, pc) - defer ci.Close() - cfg.DefaultStorage = ci - cl, err := NewClient(cfg) - require.NoError(t, err) - cl.Close() - // And again, https://github.com/anacrolix/torrent/issues/158 - cl, err = NewClient(cfg) - require.NoError(t, err) - cl.Close() + require.Empty(t, cl.Close()) } func TestAddDropTorrent(t *testing.T) { @@ -92,9 +81,8 @@ func TestPieceHashSize(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(), @@ -102,7 +90,7 @@ func TestTorrentInitialState(t *testing.T) { ) 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) @@ -143,7 +131,7 @@ func TestAddDropManyTorrents(t *testing.T) { 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) @@ -215,7 +203,7 @@ func BenchmarkAddLargeTorrent(b *testing.B) { 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) @@ -235,9 +223,51 @@ func TestResponsive(t *testing.T) { 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 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 os.RemoveAll(leecherDataDir) + defer seeder.Close() + seederTorrent, _, _ := seeder.AddTorrentSpec(TorrentSpecFromMetaInfo(mi)) + seederTorrent.VerifyData() + leecherDataDir := t.TempDir() cfg = TestingConfig(t) cfg.DataDir = leecherDataDir leecher, err := NewClient(cfg) @@ -278,9 +308,7 @@ func TestTorrentDroppedDuringResponsiveRead(t *testing.T) { 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) @@ -302,9 +330,9 @@ func TestTorrentDroppedDuringResponsiveRead(t *testing.T) { _, 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) @@ -366,16 +394,14 @@ func TestTorrentDroppedBeforeGotInfo(t *testing.T) { } 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() @@ -470,9 +496,7 @@ func testDownloadCancel(t *testing.T, ps testDownloadCancelParams) { 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 { @@ -497,7 +521,7 @@ func testDownloadCancel(t *testing.T, ps testDownloadCancelParams) { 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{}) @@ -512,8 +536,7 @@ func testDownloadCancel(t *testing.T, ps testDownloadCancelParams) { } }() for !reflect.DeepEqual(completes, expected) { - _v := <-psc.Values - v := _v.(PieceStateChange) + v := <-psc.Values completes[v.Index] = v.Complete } } @@ -551,8 +574,10 @@ func TestPeerInvalidHave(t *testing.T) { 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() @@ -567,6 +592,7 @@ func TestPieceCompletedInStorageButNotClient(t *testing.T) { cfg.DataDir = greetingTempDir seeder, err := NewClient(TestingConfig(t)) require.NoError(t, err) + defer seeder.Close() seeder.AddTorrentSpec(&TorrentSpec{ InfoBytes: greetingMetainfo.InfoBytes, }) @@ -621,7 +647,7 @@ func TestSetMaxEstablishedConn(t *testing.T) { 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() @@ -661,8 +687,8 @@ func TestSetMaxEstablishedConn(t *testing.T) { // 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)) @@ -698,11 +724,11 @@ func TestMultipleTorrentsWithEncryption(t *testing.T) { // 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) @@ -762,12 +788,16 @@ func TestObfuscatedHeaderFallbackSeederRequiresLeecherPrefersNot(t *testing.T) { } 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) } @@ -782,31 +812,6 @@ func TestClientHasDhtServersWhenUtpDisabled(t *testing.T) { assert.NotEmpty(t, cl.DhtServers()) } -func TestIssue335(t *testing.T) { - dir, mi := testutil.GreetingTestTorrent() - defer os.RemoveAll(dir) - cfg := TestingConfig(t) - cfg.Seed = false - cfg.Debug = true - cfg.DataDir = dir - comp, err := storage.NewBoltPieceCompletion(dir) - require.NoError(t, err) - defer comp.Close() - cfg.DefaultStorage = storage.NewMMapWithCompletion(dir, comp) - cl, err := NewClient(cfg) - require.NoError(t, err) - defer cl.Close() - tor, new, err := cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi)) - require.NoError(t, err) - assert.True(t, new) - require.True(t, cl.WaitAll()) - tor.Drop() - _, new, err = cl.AddTorrentSpec(TorrentSpecFromMetaInfo(mi)) - require.NoError(t, err) - assert.True(t, new) - require.True(t, cl.WaitAll()) -} - func TestClientDisabledImplicitNetworksButDhtEnabled(t *testing.T) { cfg := TestingConfig(t) cfg.DisableTCP = true @@ -818,3 +823,87 @@ func TestClientDisabledImplicitNetworksButDhtEnabled(t *testing.T) { 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) +}