commit 1ddfb8c5a9a4b934f88201f52f6eb780ee09c12c
parent 6f8cf9d673e4b93ef41d83deaef0bcd5b884edb9
Author: Matsuda Kenji <info@mtkn.jp>
Date: Wed, 3 Jan 2024 09:24:56 +0900
add TestSRemove, TestSStat
Diffstat:
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