TestUnmountWedged, fs.Destroy
This commit is contained in:
parent
1aa1063863
commit
8245f119ef
|
@ -3,6 +3,7 @@ package torrentfs
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"bazil.org/fuse"
|
"bazil.org/fuse"
|
||||||
fusefs "bazil.org/fuse/fs"
|
fusefs "bazil.org/fuse/fs"
|
||||||
|
@ -15,7 +16,9 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
type torrentFS struct {
|
type torrentFS struct {
|
||||||
Client *torrent.Client
|
Client *torrent.Client
|
||||||
|
destroyed chan struct{}
|
||||||
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ fusefs.NodeForgetter = rootNode{}
|
var _ fusefs.NodeForgetter = rootNode{}
|
||||||
|
@ -75,6 +78,8 @@ func (fn fileNode) Read(req *fuse.ReadRequest, resp *fuse.ReadResponse, intr fus
|
||||||
case torrent.ErrDataNotReady:
|
case torrent.ErrDataNotReady:
|
||||||
select {
|
select {
|
||||||
case <-dataWaiter:
|
case <-dataWaiter:
|
||||||
|
case <-fn.FS.destroyed:
|
||||||
|
return fuse.EIO
|
||||||
case <-intr:
|
case <-intr:
|
||||||
return fuse.EINTR
|
return fuse.EINTR
|
||||||
}
|
}
|
||||||
|
@ -217,16 +222,30 @@ func (rootNode) Attr() fuse.Attr {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(anacrolix): Why should rootNode implement this?
|
// 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) {
|
func (tfs *torrentFS) Root() (fusefs.Node, fuse.Error) {
|
||||||
return rootNode{tfs}, nil
|
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 {
|
func New(cl *torrent.Client) *torrentFS {
|
||||||
fs := &torrentFS{
|
fs := &torrentFS{
|
||||||
Client: cl,
|
Client: cl,
|
||||||
|
destroyed: make(chan struct{}),
|
||||||
}
|
}
|
||||||
return fs
|
return fs
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package torrentfs
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -39,25 +40,91 @@ func TestTCPAddrString(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDownloadOnDemand(t *testing.T) {
|
type testLayout struct {
|
||||||
dir, err := ioutil.TempDir("", "torrentfs")
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.RemoveAll(dir); err != nil {
|
err := layout.Destroy()
|
||||||
t.Error(err)
|
if err != nil {
|
||||||
|
t.Log(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
t.Logf("test directory: %s", dir)
|
client := torrent.Client{
|
||||||
finishedDir := filepath.Join(dir, "finished")
|
DataDir: filepath.Join(layout.BaseDir, "incomplete"),
|
||||||
os.Mkdir(finishedDir, 0777)
|
DisableTrackers: true,
|
||||||
name := testutil.CreateDummyTorrentData(finishedDir)
|
}
|
||||||
metaInfoBuf := &bytes.Buffer{}
|
client.Start()
|
||||||
testutil.CreateMetaInfo(name, metaInfoBuf)
|
client.AddTorrent(layout.Metainfo)
|
||||||
metaInfo, err := metainfo.Load(metaInfoBuf)
|
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{
|
seeder := torrent.Client{
|
||||||
DataDir: finishedDir,
|
DataDir: layout.Completed,
|
||||||
Listener: func() net.Listener {
|
Listener: func() net.Listener {
|
||||||
conn, err := net.Listen("tcp", ":0")
|
conn, err := net.Listen("tcp", ":0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -69,24 +136,23 @@ func TestDownloadOnDemand(t *testing.T) {
|
||||||
defer seeder.Listener.Close()
|
defer seeder.Listener.Close()
|
||||||
seeder.Start()
|
seeder.Start()
|
||||||
defer seeder.Stop()
|
defer seeder.Stop()
|
||||||
seeder.AddTorrent(metaInfo)
|
seeder.AddTorrent(layout.Metainfo)
|
||||||
leecher := torrent.Client{
|
leecher := torrent.Client{
|
||||||
DataDir: filepath.Join(dir, "download"),
|
DataDir: filepath.Join(layout.BaseDir, "download"),
|
||||||
}
|
}
|
||||||
leecher.Start()
|
leecher.Start()
|
||||||
defer leecher.Stop()
|
defer leecher.Stop()
|
||||||
leecher.AddTorrent(metaInfo)
|
leecher.AddTorrent(layout.Metainfo)
|
||||||
leecher.AddPeers(torrent.BytesInfoHash(metaInfo.InfoHash), []torrent.Peer{func() torrent.Peer {
|
leecher.AddPeers(torrent.BytesInfoHash(layout.Metainfo.InfoHash), []torrent.Peer{func() torrent.Peer {
|
||||||
tcpAddr := seeder.Listener.Addr().(*net.TCPAddr)
|
tcpAddr := seeder.Listener.Addr().(*net.TCPAddr)
|
||||||
return torrent.Peer{
|
return torrent.Peer{
|
||||||
IP: tcpAddr.IP,
|
IP: tcpAddr.IP,
|
||||||
Port: tcpAddr.Port,
|
Port: tcpAddr.Port,
|
||||||
}
|
}
|
||||||
}()})
|
}()})
|
||||||
mountDir := filepath.Join(dir, "mnt")
|
|
||||||
os.Mkdir(mountDir, 0777)
|
|
||||||
fs := New(&leecher)
|
fs := New(&leecher)
|
||||||
fuseConn, err := fuse.Mount(mountDir)
|
mountDir := layout.MountDir
|
||||||
|
fuseConn, err := fuse.Mount(layout.MountDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue