go-ceph/cephfs/directory_test.go
John Mulligan 807eafb9d5 cephfs: add ReadDirPlus function and associated types
Add the ReadDirPlus function call, wrapping ceph_readdirplus_r. Add
DirEntryPlus which is a DirEntry plus a getter for the statx field.
Add a test similar to the ReadDir test and (since it is possible to
induce an error with ceph_readdirplus_r) a test for the error handling
path to improve code coverage.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
2020-05-19 16:35:58 -04:00

249 lines
6.2 KiB
Go

package cephfs
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestOpenCloseDir(t *testing.T) {
mount := fsConnect(t)
defer fsDisconnect(t, mount)
dir1 := "/base"
err := mount.MakeDir(dir1, 0755)
assert.NoError(t, err)
defer func() { assert.NoError(t, mount.RemoveDir(dir1)) }()
dir2 := dir1 + "/a"
err = mount.MakeDir(dir2, 0755)
assert.NoError(t, err)
defer func() { assert.NoError(t, mount.RemoveDir(dir2)) }()
dir, err := mount.OpenDir(dir1)
assert.NoError(t, err)
assert.NotNil(t, dir)
err = dir.Close()
assert.NoError(t, err)
dir, err = mount.OpenDir(dir2)
assert.NoError(t, err)
assert.NotNil(t, dir)
err = dir.Close()
assert.NoError(t, err)
dir, err = mount.OpenDir("/no.such.dir")
assert.Error(t, err)
assert.Nil(t, dir)
}
func TestReadDir(t *testing.T) {
mount := fsConnect(t)
defer fsDisconnect(t, mount)
dir1 := "/base"
err := mount.MakeDir(dir1, 0755)
assert.NoError(t, err)
defer func() { assert.NoError(t, mount.RemoveDir(dir1)) }()
subdirs := []string{"a", "bb", "ccc", "dddd"}
for _, s := range subdirs {
spath := dir1 + "/" + s
err = mount.MakeDir(spath, 0755)
assert.NoError(t, err)
defer func(d string) {
assert.NoError(t, mount.RemoveDir(d))
}(spath)
}
t.Run("root", func(t *testing.T) {
dir, err := mount.OpenDir("/")
assert.NoError(t, err)
assert.NotNil(t, dir)
defer func() { assert.NoError(t, dir.Close()) }()
found := []string{}
for {
entry, err := dir.ReadDir()
assert.NoError(t, err)
if entry == nil {
break
}
assert.NotEqual(t, Inode(0), entry.Inode())
assert.NotEqual(t, "", entry.Name())
found = append(found, entry.Name())
}
assert.Contains(t, found, "base")
})
t.Run("dir1", func(t *testing.T) {
dir, err := mount.OpenDir(dir1)
assert.NoError(t, err)
assert.NotNil(t, dir)
defer func() { assert.NoError(t, dir.Close()) }()
found := []string{}
for {
entry, err := dir.ReadDir()
assert.NoError(t, err)
if entry == nil {
break
}
assert.NotEqual(t, Inode(0), entry.Inode())
assert.NotEqual(t, "", entry.Name())
// we have created all the contents of this dir and they are all
// empty dirs.
assert.Equal(t, DTypeDir, entry.DType())
found = append(found, entry.Name())
}
assert.Subset(t, found, subdirs)
})
}
func TestDirectoryList(t *testing.T) {
mount := fsConnect(t)
defer fsDisconnect(t, mount)
dir1 := "/base"
err := mount.MakeDir(dir1, 0755)
assert.NoError(t, err)
defer func() { assert.NoError(t, mount.RemoveDir(dir1)) }()
subdirs := []string{"a", "bb", "ccc", "dddd"}
for _, s := range subdirs {
spath := dir1 + "/" + s
err = mount.MakeDir(spath, 0755)
assert.NoError(t, err)
defer func(d string) {
assert.NoError(t, mount.RemoveDir(d))
}(spath)
}
t.Run("root", func(t *testing.T) {
dir, err := mount.OpenDir("/")
assert.NoError(t, err)
assert.NotNil(t, dir)
defer func() { assert.NoError(t, dir.Close()) }()
entries, err := dir.list()
assert.NoError(t, err)
assert.Greater(t, len(entries), 1)
found := entries.names()
assert.Contains(t, found, "base")
})
t.Run("dir1", func(t *testing.T) {
dir, err := mount.OpenDir(dir1)
assert.NoError(t, err)
assert.NotNil(t, dir)
defer func() { assert.NoError(t, dir.Close()) }()
entries, err := dir.list()
assert.NoError(t, err)
assert.Greater(t, len(entries), 1)
found := entries.names()
assert.Subset(t, found, subdirs)
})
t.Run("dir1Twice", func(t *testing.T) {
dir, err := mount.OpenDir(dir1)
assert.NoError(t, err)
assert.NotNil(t, dir)
defer func() { assert.NoError(t, dir.Close()) }()
entries, err := dir.list()
assert.NoError(t, err)
assert.Greater(t, len(entries), 1)
found := entries.names()
assert.Subset(t, found, subdirs)
// verify that calling list gives a complete list
// even after being used for the same directory already
entries, err = dir.list()
assert.NoError(t, err)
assert.Greater(t, len(entries), 1)
found = entries.names()
assert.Subset(t, found, subdirs)
})
}
func TestReadDirPlus(t *testing.T) {
mount := fsConnect(t)
defer fsDisconnect(t, mount)
dir1 := "/base"
err := mount.MakeDir(dir1, 0755)
assert.NoError(t, err)
defer func() { assert.NoError(t, mount.RemoveDir(dir1)) }()
subdirs := []string{"a", "bb", "ccc", "dddd"}
for _, s := range subdirs {
spath := dir1 + "/" + s
err = mount.MakeDir(spath, 0755)
assert.NoError(t, err)
defer func(d string) {
assert.NoError(t, mount.RemoveDir(d))
}(spath)
}
t.Run("root", func(t *testing.T) {
dir, err := mount.OpenDir("/")
assert.NoError(t, err)
assert.NotNil(t, dir)
defer func() { assert.NoError(t, dir.Close()) }()
found := []string{}
for {
entry, err := dir.ReadDirPlus(StatxBasicStats, AtSymlinkNofollow)
assert.NoError(t, err)
if entry == nil {
break
}
assert.NotEqual(t, Inode(0), entry.Inode())
assert.NotEqual(t, "", entry.Name())
found = append(found, entry.Name())
}
assert.Contains(t, found, "base")
})
t.Run("dir1", func(t *testing.T) {
dir, err := mount.OpenDir(dir1)
assert.NoError(t, err)
assert.NotNil(t, dir)
defer func() { assert.NoError(t, dir.Close()) }()
found := []string{}
for {
entry, err := dir.ReadDirPlus(StatxBasicStats, AtSymlinkNofollow)
assert.NoError(t, err)
if entry == nil {
break
}
assert.NotEqual(t, Inode(0), entry.Inode())
assert.NotEqual(t, "", entry.Name())
// we have created all the contents of this dir and they are all
// empty dirs.
assert.Equal(t, DTypeDir, entry.DType())
// get statx data from the entry, and check it
st := entry.Statx()
assert.Equal(t, StatxBasicStats, st.Mask&StatxBasicStats)
assert.Equal(t, uint16(0755), st.Mode&0777)
found = append(found, entry.Name())
}
assert.Subset(t, found, subdirs)
})
}
func TestReadDirPlusInvalid(t *testing.T) {
mount := fsConnect(t)
defer fsDisconnect(t, mount)
dir, err := mount.OpenDir("/")
assert.NoError(t, err)
assert.NotNil(t, dir)
defer func() { assert.NoError(t, dir.Close()) }()
// Feed it an invalid flag to trigger in EINVAL in libcephfs. This could
// break in the future if it ever becomes a valid flag but it works well
// enough for now, and the error suddenly changing to no error will be
// kinda obvious.
_, err = dir.ReadDirPlus(StatxBasicStats, AtFlags(1<<13))
assert.Error(t, err)
}