From: Matt Joiner Date: Thu, 17 Apr 2014 06:37:54 +0000 (+1000) Subject: TestUnmountWedged, fs.Destroy X-Git-Tag: v1.0.0~1752 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=8245f119eff3c01e2ad5393290101816a965f46e;p=btrtrc.git TestUnmountWedged, fs.Destroy --- diff --git a/fs/torrentfs.go b/fs/torrentfs.go index 914c2697..02c2e306 100644 --- a/fs/torrentfs.go +++ b/fs/torrentfs.go @@ -3,6 +3,7 @@ package torrentfs import ( "log" "os" + "sync" "bazil.org/fuse" fusefs "bazil.org/fuse/fs" @@ -15,7 +16,9 @@ const ( ) type torrentFS struct { - Client *torrent.Client + Client *torrent.Client + destroyed chan struct{} + mu sync.Mutex } var _ fusefs.NodeForgetter = rootNode{} @@ -75,6 +78,8 @@ func (fn fileNode) Read(req *fuse.ReadRequest, resp *fuse.ReadResponse, intr fus case torrent.ErrDataNotReady: select { case <-dataWaiter: + case <-fn.FS.destroyed: + return fuse.EIO case <-intr: return fuse.EINTR } @@ -217,16 +222,30 @@ func (rootNode) Attr() fuse.Attr { } // TODO(anacrolix): Why should rootNode implement this? -func (rootNode) Forget() { +func (me rootNode) Forget() { + me.fs.Destroy() } func (tfs *torrentFS) Root() (fusefs.Node, fuse.Error) { return rootNode{tfs}, nil } +func (me *torrentFS) Destroy() { + me.mu.Lock() + select { + case <-me.destroyed: + default: + close(me.destroyed) + } + me.mu.Unlock() +} + +var _ fusefs.FSDestroyer = &torrentFS{} + func New(cl *torrent.Client) *torrentFS { fs := &torrentFS{ - Client: cl, + Client: cl, + destroyed: make(chan struct{}), } return fs } diff --git a/fs/torrentfs_test.go b/fs/torrentfs_test.go index f43b913d..a1ae3f82 100644 --- a/fs/torrentfs_test.go +++ b/fs/torrentfs_test.go @@ -3,6 +3,7 @@ package torrentfs import ( "bytes" "io/ioutil" + "log" "net" "os" "path/filepath" @@ -39,25 +40,91 @@ func TestTCPAddrString(t *testing.T) { } } -func TestDownloadOnDemand(t *testing.T) { - dir, err := ioutil.TempDir("", "torrentfs") +type testLayout struct { + BaseDir string + MountDir string + Completed string + Metainfo *metainfo.MetaInfo +} + +func (me *testLayout) Destroy() error { + return os.RemoveAll(me.BaseDir) +} + +func newGreetingLayout() (tl testLayout, err error) { + tl.BaseDir, err = ioutil.TempDir("", "torrentfs") + if err != nil { + return + } + tl.Completed = filepath.Join(tl.BaseDir, "completed") + os.Mkdir(tl.Completed, 0777) + 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) + return +} + +func TestUnmountWedged(t *testing.T) { + layout, err := newGreetingLayout() if err != nil { t.Fatal(err) } defer func() { - if err := os.RemoveAll(dir); err != nil { - t.Error(err) + err := layout.Destroy() + if err != nil { + t.Log(err) } }() - t.Logf("test directory: %s", dir) - finishedDir := filepath.Join(dir, "finished") - os.Mkdir(finishedDir, 0777) - name := testutil.CreateDummyTorrentData(finishedDir) - metaInfoBuf := &bytes.Buffer{} - testutil.CreateMetaInfo(name, metaInfoBuf) - metaInfo, err := metainfo.Load(metaInfoBuf) + client := torrent.Client{ + DataDir: filepath.Join(layout.BaseDir, "incomplete"), + DisableTrackers: true, + } + client.Start() + client.AddTorrent(layout.Metainfo) + fs := New(&client) + fuseConn, err := fuse.Mount(layout.MountDir) + if err != nil { + t.Fatal(err) + } + go func() { + server := fusefs.Server{ + FS: fs, + Debug: func(msg interface{}) { + log.Print(msg) + }, + } + server.Serve(fuseConn) + }() + <-fuseConn.Ready + if err := fuseConn.MountError; err != nil { + log.Fatal(err) + } + go func() { + ioutil.ReadFile(filepath.Join(layout.MountDir, layout.Metainfo.Name)) + }() + time.Sleep(time.Second) + fs.Destroy() + time.Sleep(time.Second) + err = fuse.Unmount(layout.MountDir) + if err != nil { + log.Print(err) + } + err = fuseConn.Close() + if err != nil { + t.Log(err) + } +} + +func TestDownloadOnDemand(t *testing.T) { + layout, err := newGreetingLayout() + if err != nil { + t.Fatal(err) + } seeder := torrent.Client{ - DataDir: finishedDir, + DataDir: layout.Completed, Listener: func() net.Listener { conn, err := net.Listen("tcp", ":0") if err != nil { @@ -69,24 +136,23 @@ func TestDownloadOnDemand(t *testing.T) { defer seeder.Listener.Close() seeder.Start() defer seeder.Stop() - seeder.AddTorrent(metaInfo) + seeder.AddTorrent(layout.Metainfo) leecher := torrent.Client{ - DataDir: filepath.Join(dir, "download"), + DataDir: filepath.Join(layout.BaseDir, "download"), } leecher.Start() defer leecher.Stop() - leecher.AddTorrent(metaInfo) - leecher.AddPeers(torrent.BytesInfoHash(metaInfo.InfoHash), []torrent.Peer{func() torrent.Peer { + leecher.AddTorrent(layout.Metainfo) + leecher.AddPeers(torrent.BytesInfoHash(layout.Metainfo.InfoHash), []torrent.Peer{func() torrent.Peer { tcpAddr := seeder.Listener.Addr().(*net.TCPAddr) return torrent.Peer{ IP: tcpAddr.IP, Port: tcpAddr.Port, } }()}) - mountDir := filepath.Join(dir, "mnt") - os.Mkdir(mountDir, 0777) fs := New(&leecher) - fuseConn, err := fuse.Mount(mountDir) + mountDir := layout.MountDir + fuseConn, err := fuse.Mount(layout.MountDir) if err != nil { t.Fatal(err) }