From 7b80153387e0f447c833e47510d14a7c2e9b94f6 Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Wed, 3 Dec 2014 12:53:10 -0600 Subject: [PATCH] fs: Improve tests --- fs/torrentfs.go | 17 ++++++++++++--- fs/torrentfs_test.go | 49 +++++++++++++++++++++++++++++++------------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/fs/torrentfs.go b/fs/torrentfs.go index 6fd721b7..fd9cb059 100644 --- a/fs/torrentfs.go +++ b/fs/torrentfs.go @@ -25,9 +25,11 @@ var ( ) type TorrentFS struct { - Client *torrent.Client - destroyed chan struct{} - mu sync.Mutex + Client *torrent.Client + destroyed chan struct{} + mu sync.Mutex + blockedReads int + event sync.Cond } var ( @@ -73,6 +75,10 @@ func (n *node) fsPath() string { } func blockingRead(fs *TorrentFS, t torrent.Torrent, off int64, p []byte, intr fusefs.Intr) (n int, err fuse.Error) { + fs.mu.Lock() + fs.blockedReads++ + fs.event.Broadcast() + fs.mu.Unlock() var ( _n int _err fuse.Error @@ -91,6 +97,10 @@ func blockingRead(fs *TorrentFS, t torrent.Torrent, off int64, p []byte, intr fu case <-intr: err = fuse.EINTR } + fs.mu.Lock() + fs.blockedReads-- + fs.event.Broadcast() + fs.mu.Unlock() return } @@ -296,5 +306,6 @@ func New(cl *torrent.Client) *TorrentFS { Client: cl, destroyed: make(chan struct{}), } + fs.event.L = &fs.mu return fs } diff --git a/fs/torrentfs_test.go b/fs/torrentfs_test.go index 2f9c79fb..52591aed 100644 --- a/fs/torrentfs_test.go +++ b/fs/torrentfs_test.go @@ -77,6 +77,8 @@ func newGreetingLayout() (tl testLayout, err error) { 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() if err != nil { @@ -96,7 +98,7 @@ func TestUnmountWedged(t *testing.T) { NoDefaultBlocklist: true, }) defer client.Stop() - log.Printf("%+v", *layout.Metainfo) + t.Logf("%+v", *layout.Metainfo) client.AddTorrent(layout.Metainfo) fs := New(client) fuseConn, err := fuse.Mount(layout.MountDir) @@ -106,32 +108,50 @@ func TestUnmountWedged(t *testing.T) { } t.Fatal(err) } + <-fuseConn.Ready + if err := fuseConn.MountError; err != nil { + t.Fatal(err) + } go func() { server := fusefs.Server{ FS: fs, Debug: func(msg interface{}) { - log.Print(msg) + t.Log(msg) }, } server.Serve(fuseConn) }() - <-fuseConn.Ready - if err := fuseConn.MountError; err != nil { - log.Fatal(err) - } + // 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() { - ioutil.ReadFile(filepath.Join(layout.MountDir, layout.Metainfo.Info.Name)) + _, err := ioutil.ReadFile(filepath.Join(layout.MountDir, layout.Metainfo.Info.Name)) + if err == nil { + t.Fatal("expected error reading greeting") + } }() - // time.Sleep(time.Second) - fs.Destroy() - // time.Sleep(time.Second) - err = fuse.Unmount(layout.MountDir) - if err != nil { - log.Print(err) + + // Wait until the read has blocked inside the filesystem code. + fs.mu.Lock() + for fs.blockedReads != 1 { + fs.event.Wait() } + fs.mu.Unlock() + + fs.Destroy() + + for { + err = fuse.Unmount(layout.MountDir) + if err != nil { + t.Logf("error unmounting: %s", err) + } else { + break + } + } + err = fuseConn.Close() if err != nil { - t.Log(err) + t.Fatalf("error closing fuse conn: %s", err) } } @@ -140,6 +160,7 @@ func TestDownloadOnDemand(t *testing.T) { if err != nil { t.Fatal(err) } + defer layout.Destroy() seeder, err := torrent.NewClient(&torrent.Config{ DataDir: layout.Completed, DisableTrackers: true,