lib9p

Go 9P library.
Log | Files | Refs | LICENSE

commit 9828808d96a5af7b0890f40f47ba335b3e6ace39
parent 76560182459fdb808698ce07fb4fb4118a6ae3d9
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Tue,  2 Jan 2024 15:10:49 +0900

add TestSCreate

Diffstat:
Mfs_test.go | 40++++++++++++++++++++++++++++++++++++++++
Mserver.go | 4++++
Mserver_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 + } + } + } +}