lib9p

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

commit 1ddfb8c5a9a4b934f88201f52f6eb780ee09c12c
parent 6f8cf9d673e4b93ef41d83deaef0bcd5b884edb9
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Wed,  3 Jan 2024 09:24:56 +0900

add TestSRemove, TestSStat

Diffstat:
Mfs_test.go | 20++++++++++++++++++++
Mserver.go | 2++
Mserver_test.go | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 133 insertions(+), 0 deletions(-)

diff --git a/fs_test.go b/fs_test.go @@ -167,6 +167,26 @@ func (fs *testFS) Create(name string, uid string, mode OpenMode, perm FileMode) return f, nil } +func (fs *testFS) Remove(name string) error { + ds, filename := path.Split(name) + dirname := path.Dir(ds) + dir, err := fs.walkPath(dirname) + if err != nil { + return fmt.Errorf("not found") + } + for i, c := range dir.children { + if c.stat.Name == filename { + if len(c.children) != 0 { + return fmt.Errorf("directory not empty") + } + dir.children = append(dir.children[:i], dir.children[i+1:]...) + // TODO: should close the file? + return nil + } + } + return fmt.Errorf("not found") +} + func (fs *testFS) walk(wnames []string) (*testFile, error) { if len(wnames) == 1 && (wnames[0] == "." || wnames[0] == "") { return fs.root, nil diff --git a/server.go b/server.go @@ -951,6 +951,8 @@ func sRemove(ctx context.Context, c *conn, rc <-chan *request) { r.err = ErrOperation goto resp } + // TODO: this assumes the file can be identified by its path. + // I think the argument of RemoverFS.Remove should be Qid.Path. if err = rfs.Remove(r.fid.path); err != nil { r.err = fmt.Errorf("remove: %v", err) goto resp diff --git a/server_test.go b/server_test.go @@ -669,4 +669,115 @@ func TestSClunk(t *testing.T) { } }() } +} + +func TestSRemove(t *testing.T) { + tests := []struct{ + fid uint32 + pathname string + fuid string // uid of the file to be removed. + mode OpenMode + perm FileMode + ruid string // uid of the user who evoke remove. + ifcall *TRemove + want Msg + }{ + // ok. + {0, "unko", "glenda", OREAD, 0777, "glenda", &TRemove{Fid: 0}, &RRemove{}}, + // unknown fid. + {0, "unko", "glenda", OREAD, 0777, "glenda", &TRemove{Fid: 1}, &RError{}}, + // permission denied. + {0, "unko", "glenda", OREAD, 0777, "kenji", &TRemove{Fid: 0}, &RError{}}, + // ok. + {0, "dir/unko", "glenda", OREAD, 0000, "rob", &TRemove{Fid: 0}, &RRemove{}}, + // permission denied. + {0, "dir/unko", "glenda", OREAD, 0777, "glenda", &TRemove{Fid: 0}, &RError{}}, + } + c, tc, rc := setupConn(testfs) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go sRemove(ctx, c, tc) + for i, test := range tests { + func() { + fid, err := c.fPool.add(test.fid) + if err != nil { + t.Error(err) + return + } + defer c.fPool.delete(test.fid) + fid.omode = -1 + fid.path = test.pathname + f, err := testfs.Create(test.pathname, test.fuid, test.mode, test.perm) + if err != nil { + t.Fatal(i, err) + } + defer f.Close() + fid.file = f + fid.uid = test.ruid + tc <- &request{ifcall: test.ifcall} + ofcall := (<-rc).ofcall + switch ofcall := ofcall.(type) { + case *RRemove: + if _, ok := test.want.(*RRemove); !ok { + t.Errorf("%d: unexpected message:\n\twant: %v\n\tgot: %v", + i, test.want, ofcall) + return + } + if _, err := testfs.OpenFile(test.pathname, OREAD); err == nil { + t.Errorf("%d: file not removed", i) + testfs.Remove(test.pathname) + return + } + case *RError: + defer testfs.Remove(test.pathname) + if _, ok := test.want.(*RError); !ok { + t.Errorf("%d: unexpected message:\n\twant: %v\n\tgot: %v", + i, test.want, ofcall) + return + } + default: + t.Fatalf("%d: unexpected message: %v", i, ofcall) + } + }() + } +} + +func TestSStat(t *testing.T) { + c, tc, rc := setupConn(testfs) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + go sStat(ctx, c, tc) + testSStat(t, ".", c, tc, rc) +} + +func testSStat(t *testing.T, pathname string, c *conn, tc, rc chan *request) { + f, err := testfs.walkPath(pathname) + if err != nil { + t.Fatal(err) + } + st := f.stat + fid, err := c.fPool.add(0) + if err != nil { + t.Fatal(err) + } + fid.omode = -1 + fid.path = pathname + fid.file = f + tc <- &request{ifcall: &TStat{Fid: 0}} + ofcall := (<-rc).ofcall + c.fPool.delete(0) + switch ofcall := ofcall.(type) { + case *RStat: + if !reflect.DeepEqual(st, *ofcall.Stat) { + t.Errorf("stat doesn't match:\n\twant: %v\n\tgot: %v", st, ofcall.Stat) + } + case *RError: + t.Errorf("unexpected message: %v", ofcall) + default: + t.Fatalf("unexpected message: %v", ofcall) + } + for _, child := range f.children { + cpath := path.Join(pathname, child.stat.Name) + testSStat(t, cpath, c, tc, rc) + } } \ No newline at end of file