@@ -3,11 +3,15 @@ package nfs_test
3
3
import (
4
4
"bytes"
5
5
"fmt"
6
+ "math/rand"
6
7
"net"
8
+ "os"
7
9
"reflect"
8
10
"sort"
11
+ "sync"
9
12
"testing"
10
13
14
+ "github.com/go-git/go-billy/v5"
11
15
nfs "github.com/willscott/go-nfs"
12
16
"github.com/willscott/go-nfs/helpers"
13
17
"github.com/willscott/go-nfs/helpers/memfs"
@@ -18,6 +22,75 @@ import (
18
22
"github.com/willscott/go-nfs-client/nfs/xdr"
19
23
)
20
24
25
+ type OpenArgs struct {
26
+ File string
27
+ Flag int
28
+ Perm os.FileMode
29
+ }
30
+
31
+ func (o * OpenArgs ) String () string {
32
+ return fmt .Sprintf ("\" %s\" ; %05xd %s" , o .File , o .Flag , o .Perm )
33
+ }
34
+
35
+ // NewTrackingFS wraps fs to detect file handle leaks.
36
+ func NewTrackingFS (fs billy.Filesystem ) * trackingFS {
37
+ return & trackingFS {Filesystem : fs , open : make (map [int64 ]OpenArgs )}
38
+ }
39
+
40
+ // trackingFS wraps a Filesystem to detect file handle leaks.
41
+ type trackingFS struct {
42
+ billy.Filesystem
43
+ mu sync.Mutex
44
+ open map [int64 ]OpenArgs
45
+ }
46
+
47
+ func (t * trackingFS ) ListOpened () []OpenArgs {
48
+ t .mu .Lock ()
49
+ defer t .mu .Unlock ()
50
+ ret := make ([]OpenArgs , 0 , len (t .open ))
51
+ for _ , o := range t .open {
52
+ ret = append (ret , o )
53
+ }
54
+ return ret
55
+ }
56
+
57
+ func (t * trackingFS ) Create (filename string ) (billy.File , error ) {
58
+ return t .OpenFile (filename , os .O_RDWR | os .O_CREATE | os .O_TRUNC , 0666 )
59
+ }
60
+
61
+ func (t * trackingFS ) Open (filename string ) (billy.File , error ) {
62
+ return t .OpenFile (filename , os .O_RDONLY , 0 )
63
+ }
64
+
65
+ func (t * trackingFS ) OpenFile (filename string , flag int , perm os.FileMode ) (billy.File , error ) {
66
+ open , err := t .Filesystem .OpenFile (filename , flag , perm )
67
+ if err != nil {
68
+ return nil , err
69
+ }
70
+ t .mu .Lock ()
71
+ defer t .mu .Unlock ()
72
+ id := rand .Int63 ()
73
+ t .open [id ] = OpenArgs {filename , flag , perm }
74
+ closer := func () {
75
+ delete (t .open , id )
76
+ }
77
+ open = & trackingFile {
78
+ File : open ,
79
+ onClose : closer ,
80
+ }
81
+ return open , err
82
+ }
83
+
84
+ type trackingFile struct {
85
+ billy.File
86
+ onClose func ()
87
+ }
88
+
89
+ func (f * trackingFile ) Close () error {
90
+ f .onClose ()
91
+ return f .File .Close ()
92
+ }
93
+
21
94
func TestNFS (t * testing.T ) {
22
95
if testing .Verbose () {
23
96
util .DefaultLogger .SetDebug (true )
@@ -29,9 +102,17 @@ func TestNFS(t *testing.T) {
29
102
t .Fatal (err )
30
103
}
31
104
32
- mem := memfs .New ()
105
+ mem := NewTrackingFS (memfs .New ())
106
+
107
+ defer func () {
108
+ if opened := mem .ListOpened (); len (opened ) > 0 {
109
+ t .Errorf ("Unclosed files: %v" , opened )
110
+ }
111
+ }()
112
+
33
113
// File needs to exist in the root for memfs to acknowledge the root exists.
34
- _ , _ = mem .Create ("/test" )
114
+ r , _ := mem .Create ("/test" )
115
+ r .Close ()
35
116
36
117
handler := helpers .NewNullAuthHandler (mem )
37
118
cacheHelper := helpers .NewCachingHandler (handler , 1024 )
@@ -78,12 +159,18 @@ func TestNFS(t *testing.T) {
78
159
if err != nil {
79
160
t .Fatal (err )
80
161
}
162
+ defer f .Close ()
81
163
b := []byte ("hello world" )
82
164
_ , err = f .Write (b )
83
165
if err != nil {
84
166
t .Fatal (err )
85
167
}
86
- mf , _ := mem .Open ("/helloworld.txt" )
168
+
169
+ mf , err := target .Open ("/helloworld.txt" )
170
+ if err != nil {
171
+ t .Fatal (err )
172
+ }
173
+ defer mf .Close ()
87
174
buf := make ([]byte , len (b ))
88
175
if _ , err = mf .Read (buf [:]); err != nil {
89
176
t .Fatal (err )
0 commit comments