]> Sergey Matveev's repositories - btrtrc.git/blobdiff - fs/torrentfs_test.go
Drop support for go 1.20
[btrtrc.git] / fs / torrentfs_test.go
index cca219925184a38e60c53bde93ab2e2f95c6df8b..097f1bb2377449d1c4300e4d8496a1f90806ad11 100644 (file)
@@ -1,7 +1,7 @@
 package torrentfs
 
 import (
-       "bytes"
+       "context"
        "fmt"
        "io/ioutil"
        "log"
@@ -9,17 +9,15 @@ import (
        _ "net/http/pprof"
        "os"
        "path/filepath"
-       "strings"
        "testing"
        "time"
 
-       "bazil.org/fuse"
-       fusefs "bazil.org/fuse/fs"
        _ "github.com/anacrolix/envpprof"
-       "github.com/anacrolix/missinggo"
+       "github.com/anacrolix/fuse"
+       fusefs "github.com/anacrolix/fuse/fs"
+       "github.com/anacrolix/missinggo/v2"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
-       netContext "golang.org/x/net/context"
 
        "github.com/anacrolix/torrent"
        "github.com/anacrolix/torrent/internal/testutil"
@@ -60,30 +58,25 @@ type testLayout struct {
        Metainfo  *metainfo.MetaInfo
 }
 
-func (me *testLayout) Destroy() error {
-       return os.RemoveAll(me.BaseDir)
+func (tl *testLayout) Destroy() error {
+       return os.RemoveAll(tl.BaseDir)
 }
 
-func newGreetingLayout() (tl testLayout, err error) {
-       tl.BaseDir, err = ioutil.TempDir("", "torrentfs")
-       if err != nil {
-               return
-       }
+func newGreetingLayout(t *testing.T) (tl testLayout, err error) {
+       tl.BaseDir = t.TempDir()
        tl.Completed = filepath.Join(tl.BaseDir, "completed")
-       os.Mkdir(tl.Completed, 0777)
+       os.Mkdir(tl.Completed, 0o777)
        tl.MountDir = filepath.Join(tl.BaseDir, "mnt")
-       os.Mkdir(tl.MountDir, 0777)
-       name := testutil.CreateDummyTorrentData(tl.Completed)
-       metaInfoBuf := &bytes.Buffer{}
-       testutil.CreateMetaInfo(name, metaInfoBuf)
-       tl.Metainfo, err = metainfo.Load(metaInfoBuf)
+       os.Mkdir(tl.MountDir, 0o777)
+       testutil.CreateDummyTorrentData(tl.Completed)
+       tl.Metainfo = testutil.GreetingMetaInfo()
        return
 }
 
 // Unmount without first killing the FUSE connection while there are FUSE
 // operations blocked inside the filesystem code.
 func TestUnmountWedged(t *testing.T) {
-       layout, err := newGreetingLayout()
+       layout, err := newGreetingLayout(t)
        require.NoError(t, err)
        defer func() {
                err := layout.Destroy()
@@ -91,28 +84,27 @@ func TestUnmountWedged(t *testing.T) {
                        t.Log(err)
                }
        }()
-       client, err := torrent.NewClient(&torrent.Config{
-               DataDir:         filepath.Join(layout.BaseDir, "incomplete"),
-               DisableTrackers: true,
-               NoDHT:           true,
-               ListenAddr:      "redonk",
-               DisableTCP:      true,
-               DisableUTP:      true,
-
-               NoDefaultBlocklist: true,
-       })
+       cfg := torrent.NewDefaultClientConfig()
+       cfg.DataDir = filepath.Join(layout.BaseDir, "incomplete")
+       cfg.DisableTrackers = true
+       cfg.NoDHT = true
+       cfg.DisableTCP = true
+       cfg.DisableUTP = true
+       client, err := torrent.NewClient(cfg)
        require.NoError(t, err)
        defer client.Close()
-       _, err = client.AddTorrent(layout.Metainfo)
+       tt, err := client.AddTorrent(layout.Metainfo)
        require.NoError(t, err)
        fs := New(client)
        fuseConn, err := fuse.Mount(layout.MountDir)
        if err != nil {
-               msg := fmt.Sprintf("error mounting: %s", err)
-               if strings.Contains(err.Error(), "fuse") || err.Error() == "exit status 71" {
-                       t.Skip(msg)
+               switch err.Error() {
+               case "cannot locate OSXFUSE":
+                       fallthrough
+               case "fusermount: exit status 1":
+                       t.Skip(err)
                }
-               t.Fatal(msg)
+               t.Fatal(err)
        }
        go func() {
                server := fusefs.New(fuseConn, &fusefs.Config{
@@ -126,19 +118,25 @@ func TestUnmountWedged(t *testing.T) {
        if err := fuseConn.MountError; err != nil {
                t.Fatalf("mount error: %s", err)
        }
+       ctx, cancel := context.WithCancel(context.Background())
        // Read the greeting file, though it will never be available. This should
        // "wedge" FUSE, requiring the fs object to be forcibly destroyed. The
        // read call will return with a FS error.
        go func() {
-               _, err := ioutil.ReadFile(filepath.Join(layout.MountDir, layout.Metainfo.Info.Name))
-               if err == nil {
-                       t.Fatal("expected error reading greeting")
-               }
+               <-ctx.Done()
+               fs.mu.Lock()
+               fs.event.Broadcast()
+               fs.mu.Unlock()
+       }()
+       go func() {
+               defer cancel()
+               _, err := ioutil.ReadFile(filepath.Join(layout.MountDir, tt.Info().Name))
+               require.Error(t, err)
        }()
 
        // Wait until the read has blocked inside the filesystem code.
        fs.mu.Lock()
-       for fs.blockedReads != 1 {
+       for fs.blockedReads != 1 && ctx.Err() == nil {
                fs.event.Wait()
        }
        fs.mu.Unlock()
@@ -156,72 +154,72 @@ func TestUnmountWedged(t *testing.T) {
        }
 
        err = fuseConn.Close()
-       if err != nil {
-               t.Fatalf("error closing fuse conn: %s", err)
-       }
+       assert.NoError(t, err)
 }
 
 func TestDownloadOnDemand(t *testing.T) {
-       layout, err := newGreetingLayout()
+       layout, err := newGreetingLayout(t)
        require.NoError(t, err)
        defer layout.Destroy()
-       seeder, err := torrent.NewClient(&torrent.Config{
-               DataDir:         layout.Completed,
-               DisableTrackers: true,
-               NoDHT:           true,
-               ListenAddr:      "localhost:0",
-               Seed:            true,
-
-               NoDefaultBlocklist: true,
-               // Ensure that the metainfo is obtained over the wire, since we added
-               // the torrent to the seeder by magnet.
-               DisableMetainfoCache: true,
-       })
-       seeder.SetIPBlockList(nil)
+       cfg := torrent.NewDefaultClientConfig()
+       cfg.DataDir = layout.Completed
+       cfg.DisableTrackers = true
+       cfg.NoDHT = true
+       cfg.Seed = true
+       cfg.ListenPort = 0
+       cfg.ListenHost = torrent.LoopbackListenHost
+       seeder, err := torrent.NewClient(cfg)
        require.NoError(t, err)
        defer seeder.Close()
-       testutil.ExportStatusWriter(seeder, "s")
-       _, err = seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%s", layout.Metainfo.Info.Hash.HexString()))
+       defer testutil.ExportStatusWriter(seeder, "s", t)()
+       // Just to mix things up, the seeder starts with the data, but the leecher
+       // starts with the metainfo.
+       seederTorrent, err := seeder.AddMagnet(fmt.Sprintf("magnet:?xt=urn:btih:%s", layout.Metainfo.HashInfoBytes().HexString()))
        require.NoError(t, err)
-       leecher, err := torrent.NewClient(&torrent.Config{
-               DisableTrackers: true,
-               NoDHT:           true,
-               ListenAddr:      "localhost:0",
-               DisableTCP:      true,
-
-               NoDefaultBlocklist: true,
-
-               DefaultStorage: storage.NewMMap(filepath.Join(layout.BaseDir, "download")),
-
-               // This can be used to check if clients can connect to other clients
-               // with the same ID.
-
-               // PeerID: seeder.PeerID(),
-       })
-       leecher.SetIPBlockList(nil)
-       testutil.ExportStatusWriter(leecher, "l")
+       go func() {
+               // Wait until we get the metainfo, then check for the data.
+               <-seederTorrent.GotInfo()
+               seederTorrent.VerifyData()
+       }()
+       cfg = torrent.NewDefaultClientConfig()
+       cfg.DisableTrackers = true
+       cfg.NoDHT = true
+       cfg.DisableTCP = true
+       cfg.DefaultStorage = storage.NewMMap(filepath.Join(layout.BaseDir, "download"))
+       cfg.ListenHost = torrent.LoopbackListenHost
+       cfg.ListenPort = 0
+       leecher, err := torrent.NewClient(cfg)
+       require.NoError(t, err)
+       testutil.ExportStatusWriter(leecher, "l", t)()
        defer leecher.Close()
-       leecherTorrent, _ := leecher.AddTorrent(layout.Metainfo)
-       leecherTorrent.AddPeers([]torrent.Peer{
-               torrent.Peer{
-                       IP:   missinggo.AddrIP(seeder.ListenAddr()),
-                       Port: missinggo.AddrPort(seeder.ListenAddr()),
-               },
-       })
+       leecherTorrent, err := leecher.AddTorrent(layout.Metainfo)
+       require.NoError(t, err)
+       leecherTorrent.AddClientPeer(seeder)
        fs := New(leecher)
        defer fs.Destroy()
        root, _ := fs.Root()
-       node, _ := root.(fusefs.NodeStringLookuper).Lookup(netContext.Background(), "greeting")
+       node, _ := root.(fusefs.NodeStringLookuper).Lookup(context.Background(), "greeting")
        var attr fuse.Attr
-       node.Attr(netContext.Background(), &attr)
+       node.Attr(context.Background(), &attr)
        size := attr.Size
-       resp := &fuse.ReadResponse{
-               Data: make([]byte, size),
+       data := make([]byte, size)
+       h, err := node.(fusefs.NodeOpener).Open(context.TODO(), nil, nil)
+       require.NoError(t, err)
+
+       // torrent.Reader.Read no longer tries to fill the entire read buffer, so this is a ReadFull for
+       // fusefs.
+       var n int
+       for n < len(data) {
+               resp := fuse.ReadResponse{Data: data[n:]}
+               err := h.(fusefs.HandleReader).Read(context.Background(), &fuse.ReadRequest{
+                       Size:   int(size) - n,
+                       Offset: int64(n),
+               }, &resp)
+               assert.NoError(t, err)
+               n += len(resp.Data)
        }
-       node.(fusefs.HandleReader).Read(netContext.Background(), &fuse.ReadRequest{
-               Size: int(size),
-       }, resp)
-       assert.EqualValues(t, testutil.GreetingFileContents, resp.Data)
+
+       assert.EqualValues(t, testutil.GreetingFileContents, data)
 }
 
 func TestIsSubPath(t *testing.T) {
@@ -231,6 +229,7 @@ func TestIsSubPath(t *testing.T) {
        }{
                {"", "", false},
                {"", "/", true},
+               {"", "a", true},
                {"a/b", "a/bc", false},
                {"a/b", "a/b", false},
                {"a/b", "a/b/c", true},