mirror of
https://github.com/ipfs/kubo.git
synced 2025-09-10 09:52:20 +08:00
introduce concept of filedescriptors to mfs, adjust fuse code to use them
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
This commit is contained in:
257
mfs/mfs_test.go
257
mfs/mfs_test.go
@ -9,7 +9,9 @@ import (
|
||||
"math/rand"
|
||||
"os"
|
||||
"sort"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
randbo "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/dustin/randbo"
|
||||
ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/ipfs/go-datastore"
|
||||
@ -38,6 +40,10 @@ func getDagserv(t *testing.T) dag.DAGService {
|
||||
|
||||
func getRandFile(t *testing.T, ds dag.DAGService, size int64) *dag.Node {
|
||||
r := io.LimitReader(u.NewTimeSeededRand(), size)
|
||||
return fileNodeFromReader(t, ds, r)
|
||||
}
|
||||
|
||||
func fileNodeFromReader(t *testing.T, ds dag.DAGService, r io.Reader) *dag.Node {
|
||||
nd, err := importer.BuildDagFromReader(ds, chunk.DefaultSplitter(r))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -143,7 +149,12 @@ func assertFileAtPath(ds dag.DAGService, root *Directory, exp *dag.Node, pth str
|
||||
return fmt.Errorf("%s was not a file!", pth)
|
||||
}
|
||||
|
||||
out, err := ioutil.ReadAll(file)
|
||||
rfd, err := file.Open(OpenReadOnly, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := ioutil.ReadAll(rfd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -374,6 +385,11 @@ func TestMfsFile(t *testing.T) {
|
||||
t.Fatal("some is seriously wrong here")
|
||||
}
|
||||
|
||||
wfd, err := fi.Open(OpenReadWrite, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// assert size is as expected
|
||||
size, err := fi.Size()
|
||||
if size != int64(fisize) {
|
||||
@ -382,7 +398,7 @@ func TestMfsFile(t *testing.T) {
|
||||
|
||||
// write to beginning of file
|
||||
b := []byte("THIS IS A TEST")
|
||||
n, err := fi.Write(b)
|
||||
n, err := wfd.Write(b)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -392,19 +408,19 @@ func TestMfsFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// sync file
|
||||
err = fi.Sync()
|
||||
err = wfd.Sync()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// make sure size hasnt changed
|
||||
size, err = fi.Size()
|
||||
size, err = wfd.Size()
|
||||
if size != int64(fisize) {
|
||||
t.Fatal("size isnt correct")
|
||||
}
|
||||
|
||||
// seek back to beginning
|
||||
ns, err := fi.Seek(0, os.SEEK_SET)
|
||||
ns, err := wfd.Seek(0, os.SEEK_SET)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -415,7 +431,7 @@ func TestMfsFile(t *testing.T) {
|
||||
|
||||
// read back bytes we wrote
|
||||
buf := make([]byte, len(b))
|
||||
n, err = fi.Read(buf)
|
||||
n, err = wfd.Read(buf)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -429,12 +445,12 @@ func TestMfsFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// truncate file to ten bytes
|
||||
err = fi.Truncate(10)
|
||||
err = wfd.Truncate(10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
size, err = fi.Size()
|
||||
size, err = wfd.Size()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -445,7 +461,7 @@ func TestMfsFile(t *testing.T) {
|
||||
|
||||
// 'writeAt' to extend it
|
||||
data := []byte("this is a test foo foo foo")
|
||||
nwa, err := fi.WriteAt(data, 5)
|
||||
nwa, err := wfd.WriteAt(data, 5)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -455,7 +471,7 @@ func TestMfsFile(t *testing.T) {
|
||||
}
|
||||
|
||||
// assert size once more
|
||||
size, err = fi.Size()
|
||||
size, err = wfd.Size()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -464,14 +480,14 @@ func TestMfsFile(t *testing.T) {
|
||||
t.Fatal("size was incorrect")
|
||||
}
|
||||
|
||||
// make sure we can get node. TODO: verify it later
|
||||
_, err = fi.GetNode()
|
||||
// close it out!
|
||||
err = wfd.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// close it out!
|
||||
err = fi.Close()
|
||||
// make sure we can get node. TODO: verify it later
|
||||
_, err = fi.GetNode()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -529,13 +545,18 @@ func actorMakeFile(d *Directory) error {
|
||||
return err
|
||||
}
|
||||
|
||||
r := io.LimitReader(randbo.New(), int64(77*rand.Intn(123)))
|
||||
_, err = io.Copy(f, r)
|
||||
wfd, err := f.Open(OpenWriteOnly, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = f.Close()
|
||||
r := io.LimitReader(randbo.New(), int64(77*rand.Intn(123)))
|
||||
_, err = io.Copy(wfd, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = wfd.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -630,9 +651,14 @@ func actorWriteFile(d *Directory) error {
|
||||
return err
|
||||
}
|
||||
|
||||
wfd, err := fi.Open(OpenWriteOnly, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
offset := rand.Int63n(s)
|
||||
|
||||
n, err := fi.WriteAt(buf, offset)
|
||||
n, err := wfd.WriteAt(buf, offset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -640,7 +666,7 @@ func actorWriteFile(d *Directory) error {
|
||||
return fmt.Errorf("didnt write enough")
|
||||
}
|
||||
|
||||
return fi.Close()
|
||||
return wfd.Close()
|
||||
}
|
||||
|
||||
func actorReadFile(d *Directory) error {
|
||||
@ -657,12 +683,17 @@ func actorReadFile(d *Directory) error {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = ioutil.ReadAll(fi)
|
||||
rfd, err := fi.Open(OpenReadOnly, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return fi.Close()
|
||||
_, err = ioutil.ReadAll(rfd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return rfd.Close()
|
||||
}
|
||||
|
||||
func testActor(rt *Root, iterations int, errs chan error) {
|
||||
@ -780,3 +811,187 @@ func TestFlushing(t *testing.T) {
|
||||
t.Fatalf("dag looks wrong, expected %s, but got %s", exp, rnk.B58String())
|
||||
}
|
||||
}
|
||||
|
||||
func readFile(rt *Root, path string, offset int64, buf []byte) error {
|
||||
n, err := Lookup(rt, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fi, ok := n.(*File)
|
||||
if !ok {
|
||||
return fmt.Errorf("%s was not a file", path)
|
||||
}
|
||||
|
||||
fd, err := fi.Open(OpenReadOnly, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = fd.Seek(offset, os.SEEK_SET)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nread, err := fd.Read(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if nread != len(buf) {
|
||||
return fmt.Errorf("didnt read enough!")
|
||||
}
|
||||
|
||||
return fd.Close()
|
||||
}
|
||||
|
||||
func TestConcurrentReads(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
ds, rt := setupRoot(ctx, t)
|
||||
|
||||
rootdir := rt.GetValue().(*Directory)
|
||||
|
||||
path := "a/b/c"
|
||||
d := mkdirP(t, rootdir, path)
|
||||
|
||||
buf := make([]byte, 2048)
|
||||
randbo.New().Read(buf)
|
||||
|
||||
fi := fileNodeFromReader(t, ds, bytes.NewReader(buf))
|
||||
err := d.AddChild("afile", fi)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
nloops := 100
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func(me int) {
|
||||
defer wg.Done()
|
||||
mybuf := make([]byte, len(buf))
|
||||
for j := 0; j < nloops; j++ {
|
||||
offset := rand.Intn(len(buf))
|
||||
length := rand.Intn(len(buf) - offset)
|
||||
|
||||
err := readFile(rt, "/a/b/c/afile", int64(offset), mybuf[:length])
|
||||
if err != nil {
|
||||
t.Error("readfile failed: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(mybuf[:length], buf[offset:offset+length]) {
|
||||
t.Error("incorrect read!")
|
||||
}
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestFileDescriptors(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
ds, rt := setupRoot(ctx, t)
|
||||
dir := rt.GetValue().(*Directory)
|
||||
|
||||
nd := &dag.Node{Data: ft.FilePBData(nil, 0)}
|
||||
fi, err := NewFile("test", nd, dir, ds)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// test read only
|
||||
rfd1, err := fi.Open(OpenReadOnly, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = rfd1.Truncate(0)
|
||||
if err == nil {
|
||||
t.Fatal("shouldnt be able to truncate readonly fd")
|
||||
}
|
||||
|
||||
_, err = rfd1.Write([]byte{})
|
||||
if err == nil {
|
||||
t.Fatal("shouldnt be able to write to readonly fd")
|
||||
}
|
||||
|
||||
_, err = rfd1.Read([]byte{})
|
||||
if err != nil {
|
||||
t.Fatalf("expected to be able to read from file: %s", err)
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
// can open second readonly file descriptor
|
||||
rfd2, err := fi.Open(OpenReadOnly, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
rfd2.Close()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("open second file descriptor failed")
|
||||
case <-done:
|
||||
}
|
||||
|
||||
if t.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
// test not being able to open for write until reader are closed
|
||||
done = make(chan struct{})
|
||||
go func() {
|
||||
defer close(done)
|
||||
wfd1, err := fi.Open(OpenWriteOnly, true)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
wfd1.Close()
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(time.Millisecond * 200):
|
||||
case <-done:
|
||||
if t.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
t.Fatal("shouldnt have been able to open file for writing")
|
||||
}
|
||||
|
||||
err = rfd1.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("should have been able to open write fd after closing read fd")
|
||||
case <-done:
|
||||
}
|
||||
|
||||
wfd, err := fi.Open(OpenWriteOnly, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
_, err = wfd.Read([]byte{})
|
||||
if err == nil {
|
||||
t.Fatal("shouldnt have been able to read from write only filedescriptor")
|
||||
}
|
||||
|
||||
_, err = wfd.Write([]byte{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user