github.com/hanwen/go-fuse@v1.0.0/unionfs/unionfs_xattr_test.go (about) 1 // Copyright 2016 the Go-FUSE Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package unionfs 6 7 import ( 8 "os" 9 "sync/atomic" 10 "testing" 11 "time" 12 13 "github.com/hanwen/go-fuse/fuse" 14 "github.com/hanwen/go-fuse/fuse/nodefs" 15 "github.com/hanwen/go-fuse/fuse/pathfs" 16 "github.com/hanwen/go-fuse/internal/testutil" 17 ) 18 19 type TestFS struct { 20 pathfs.FileSystem 21 xattrRead int64 22 } 23 24 func (fs *TestFS) GetAttr(path string, context *fuse.Context) (*fuse.Attr, fuse.Status) { 25 switch path { 26 case "": 27 return &fuse.Attr{Mode: fuse.S_IFDIR | 0755}, fuse.OK 28 case "file": 29 return &fuse.Attr{Mode: fuse.S_IFREG | 0755}, fuse.OK 30 } 31 return nil, fuse.ENOENT 32 } 33 34 func (fs *TestFS) GetXAttr(path string, name string, context *fuse.Context) ([]byte, fuse.Status) { 35 if path == "file" && name == "user.attr" { 36 atomic.AddInt64(&fs.xattrRead, 1) 37 return []byte{42}, fuse.OK 38 } 39 return nil, fuse.ENOATTR 40 } 41 42 func TestXAttrCaching(t *testing.T) { 43 wd := testutil.TempDir() 44 defer os.RemoveAll(wd) 45 os.Mkdir(wd+"/mnt", 0700) 46 err := os.Mkdir(wd+"/rw", 0700) 47 if err != nil { 48 t.Fatalf("Mkdir failed: %v", err) 49 } 50 51 rwFS := pathfs.NewLoopbackFileSystem(wd + "/rw") 52 roFS := &TestFS{ 53 FileSystem: pathfs.NewDefaultFileSystem(), 54 } 55 56 ufs, err := NewUnionFs([]pathfs.FileSystem{rwFS, 57 NewCachingFileSystem(roFS, entryTTL)}, testOpts) 58 if err != nil { 59 t.Fatalf("NewUnionFs: %v", err) 60 } 61 62 opts := &nodefs.Options{ 63 EntryTimeout: entryTTL / 2, 64 AttrTimeout: entryTTL / 2, 65 NegativeTimeout: entryTTL / 2, 66 Debug: testutil.VerboseTest(), 67 LookupKnownChildren: true, 68 } 69 70 pathfs := pathfs.NewPathNodeFs(ufs, 71 &pathfs.PathNodeFsOptions{ClientInodes: true, 72 Debug: testutil.VerboseTest()}) 73 74 server, _, err := nodefs.MountRoot(wd+"/mnt", pathfs.Root(), opts) 75 if err != nil { 76 t.Fatalf("MountNodeFileSystem failed: %v", err) 77 } 78 defer server.Unmount() 79 go server.Serve() 80 server.WaitMount() 81 82 start := time.Now() 83 if fi, err := os.Lstat(wd + "/mnt"); err != nil || !fi.IsDir() { 84 t.Fatalf("root not readable: %v, %v", err, fi) 85 } 86 87 buf := make([]byte, 1024) 88 n, err := Getxattr(wd+"/mnt/file", "user.attr", buf) 89 if err != nil { 90 t.Fatalf("Getxattr: %v", err) 91 } 92 want := "\x2a" 93 got := string(buf[:n]) 94 if got != want { 95 t.Fatalf("Got %q want %q", got, err) 96 } 97 98 time.Sleep(entryTTL / 3) 99 100 n, err = Getxattr(wd+"/mnt/file", "user.attr", buf) 101 if err != nil { 102 t.Fatalf("Getxattr: %v", err) 103 } 104 got = string(buf[:n]) 105 if got != want { 106 t.Fatalf("Got %q want %q", got, err) 107 } 108 109 time.Sleep(entryTTL / 3) 110 111 // Make sure that an interceding Getxattr() to a filesystem that doesn't implement GetXAttr() doesn't affect future calls. 112 Getxattr(wd, "whatever", buf) 113 114 n, err = Getxattr(wd+"/mnt/file", "user.attr", buf) 115 if err != nil { 116 t.Fatalf("Getxattr: %v", err) 117 } 118 got = string(buf[:n]) 119 if got != want { 120 t.Fatalf("Got %q want %q", got, err) 121 } 122 123 if time.Now().Sub(start) >= entryTTL { 124 // If we run really slowly, this test will spuriously 125 // fail. 126 t.Skip("test took too long.") 127 } 128 129 actual := atomic.LoadInt64(&roFS.xattrRead) 130 if actual != 1 { 131 t.Errorf("got xattrRead=%d, want 1", actual) 132 } 133 }