commit 9828808d96a5af7b0890f40f47ba335b3e6ace39
parent 76560182459fdb808698ce07fb4fb4118a6ae3d9
Author: Matsuda Kenji <info@mtkn.jp>
Date: Tue, 2 Jan 2024 15:10:49 +0900
add TestSCreate
Diffstat:
M | fs_test.go | | | 40 | ++++++++++++++++++++++++++++++++++++++++ |
M | server.go | | | 4 | ++++ |
M | server_test.go | | | 97 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ |
3 files changed, 134 insertions(+), 7 deletions(-)
diff --git a/fs_test.go b/fs_test.go
@@ -7,6 +7,7 @@ import (
"path"
"strings"
"testing"
+ "time"
)
type testFile struct {
@@ -91,6 +92,7 @@ type testFS struct {
// If slow is true, each function on files of this testFS waits for
// something arrives on waitc.
slow bool
+ nextQid uint64
// waitc is used to wait some timing to emulate slow response.
waitc chan struct{}
// groups holds the information of groups and it leader and members.
@@ -128,6 +130,43 @@ func (fs *testFS) IsGroupMember(gid, uid string) bool {
return g.members[uid]
}
+// Permission check is intentionally skipped.
+func (fs *testFS) Create(name string, uid string, mode OpenMode, perm FileMode) (File, error) {
+ dirname, filename := path.Split(name)
+ if dirname == "" && (filename == "." || filename == "" ) {
+ return nil, fmt.Errorf("cant create root")
+ }
+ dir, err := fs.walkPath(path.Dir(dirname))
+ if err != nil {
+ return nil, fmt.Errorf("not found")
+ }
+ for _, c := range dir.children {
+ if c.stat.Name == filename {
+ return nil, fmt.Errorf("file already exists")
+ }
+ }
+ f := &testFile{
+ fsys: fs,
+ parent: dir,
+ stat: Stat{
+ Qid: Qid{
+ Type: FSModeToQidType(perm),
+ Path: fs.nextQid,
+ },
+ Mode: perm,
+ Atime: uint32(time.Now().Unix()),
+ Mtime: uint32(time.Now().Unix()),
+ Name: filename,
+ Uid: uid,
+ Gid: dir.stat.Gid,
+ Muid: uid,
+ },
+ }
+ fs.nextQid++
+ dir.children = append(dir.children, f)
+ return f, nil
+}
+
func (fs *testFS) walk(wnames []string) (*testFile, error) {
if len(wnames) == 1 && (wnames[0] == "." || wnames[0] == "") {
return fs.root, nil
@@ -198,6 +237,7 @@ func init() {
Muid: f.muid,
}
ff.fsys = testfs
+ testfs.nextQid++
}
testfs.waitc = make(chan struct{})
testfs.groups = map[string]group{
diff --git a/server.go b/server.go
@@ -622,6 +622,10 @@ func sCreate(ctx context.Context, c *conn, rc <-chan *request) {
r.err = ErrUnknownFid
goto resp
}
+ if r.fid.omode != -1 {
+ r.err = ErrBotch
+ goto resp
+ }
dirstat, err = fs.Stat(ExportFS{c.s.fs}, r.fid.path)
if err != nil {
r.err = fmt.Errorf("stat: %v", err)
diff --git a/server_test.go b/server_test.go
@@ -6,6 +6,7 @@ import (
"errors"
"io"
"os"
+ "path"
"reflect"
"sync"
"testing"
@@ -140,11 +141,11 @@ func setupConn(fs FS) (c *conn, tc, rc chan *request) {
tc = make(chan *request)
rc = make(chan *request)
c = &conn{
- s: NewServer(fs),
- msize: 1024,
+ s: NewServer(fs),
+ msize: 1024,
mSizeLock: new(sync.Mutex),
- fPool: newFidPool(),
- respChan: rc,
+ fPool: newFidPool(),
+ respChan: rc,
}
return
}
@@ -417,14 +418,13 @@ func TestSOpen(t *testing.T) {
fid.omode = -1
fid.path = test.filePath
fid.uid = test.uid
- f, err := testfs.WalkPath(test.filePath)
+ f, err := testfs.walkPath(test.filePath)
if err != nil {
t.Error(i, err)
continue
}
fid.file = f
- req := &Req{ifcall:test.input}
- tc <- req
+ tc <- &request{ifcall: test.input}
ofcall := (<-rc).ofcall
switch test.wantMsg.(type) {
case *ROpen:
@@ -440,3 +440,86 @@ func TestSOpen(t *testing.T) {
}
}
}
+
+func TestSCreate(t *testing.T) {
+ tests := []struct {
+ dir string // pathname in which a file is to be created.
+ uid string
+ ifcall *TCreate
+ want Msg
+ }{
+ {".", "glenda",
+ &TCreate{Name: "test", Perm: 0777, Mode: OREAD},
+ &RCreate{}},
+ {"dir", "glenda",
+ &TCreate{Name: "test", Perm: 0777, Mode: OREAD},
+ &RError{Ename: ErrPerm}},
+ {"dir", "rob",
+ &TCreate{Name: "test", Perm: 0777, Mode: OREAD},
+ &RCreate{}},
+ }
+ c, tc, rc := setupConn(testfs)
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ go sCreate(ctx, c, tc)
+ for i, test := range tests {
+ c.fPool.delete(0)
+ fid, err := c.fPool.add(0)
+ if err != nil {
+ t.Error(i, err)
+ continue
+ }
+ f, err := testfs.walkPath(test.dir)
+ if err != nil {
+ t.Error(i, err)
+ continue
+ }
+ fid.file = f
+ fid.omode = -1
+ fid.path = test.dir
+ fid.uid = test.uid
+ tc <- &request{ifcall: test.ifcall}
+ ofcall := (<-rc).ofcall
+ var qid Qid
+ switch test.want.(type) {
+ case *RCreate:
+ got, ok := ofcall.(*RCreate)
+ if !ok {
+ t.Errorf("%d:\n\twant: %v\n\tgot: %v", i, test.want, ofcall)
+ continue
+ }
+ qid = got.Qid
+ case *RError:
+ if _, ok := ofcall.(*RError); !ok {
+ t.Errorf("%d:\n\twant: %v\n\tgot: %v", i, test.want, ofcall)
+ continue
+ }
+ continue
+ default:
+ t.Errorf("%d: unexpected message: %v", i, test.want)
+ continue
+ }
+ fname := path.Join(test.dir, test.ifcall.Name)
+ ff, err := testfs.walkPath(fname)
+ if err != nil {
+ t.Error(i, err)
+ goto remove
+ }
+ if !reflect.DeepEqual(ff.stat.Qid, qid) {
+ t.Errorf("%d: qid mismatch: want: %v, got: %v", i, ff.stat.Qid, qid)
+ goto remove
+ }
+remove:
+ dd, err := testfs.walkPath(test.dir)
+ if err != nil {
+ t.Fatal(i, err)
+ continue
+ }
+ for i, c := range dd.children {
+ if c.stat.Name == test.ifcall.Name {
+ dd.children = append(dd.children[:i], dd.children[i+1:]...)
+ break
+ }
+ }
+ }
+}