|
@@ -0,0 +1,380 @@
|
|
|
+package mountree_test
|
|
|
+
|
|
|
+import (
|
|
|
+ "git.swzry.com/ProjectNagae/FsUtils/mountree"
|
|
|
+ "testing"
|
|
|
+)
|
|
|
+
|
|
|
+type Mount struct {
|
|
|
+ FileSystemName string
|
|
|
+ MountPoint string
|
|
|
+}
|
|
|
+
|
|
|
+type TestCase struct {
|
|
|
+ Path string
|
|
|
+ FileSystemName string
|
|
|
+ RemainPath string
|
|
|
+}
|
|
|
+
|
|
|
+type Payload struct {
|
|
|
+ FsName string
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Payload) Name() string {
|
|
|
+ return p.FsName
|
|
|
+}
|
|
|
+
|
|
|
+func (p *Payload) Description() string {
|
|
|
+ return p.FsName
|
|
|
+}
|
|
|
+
|
|
|
+var _ mountree.PayloadType = (*Payload)(nil)
|
|
|
+
|
|
|
+var FS *mountree.SimpleUnixLikePathTree[*Payload]
|
|
|
+
|
|
|
+func TestAll(t *testing.T) {
|
|
|
+ t.Log("==== Phase1 ====")
|
|
|
+ mounts1 := []Mount{
|
|
|
+ {"fs1", "/"},
|
|
|
+ {"fs2", "/foo"},
|
|
|
+ {"fs3", "/foo/bar"},
|
|
|
+ {"fs4", "/foo/baz"},
|
|
|
+ {"fs5", "/foo/baz/qux/tac/mud"},
|
|
|
+ {"fs6", "/foo/baz/qux/fox"},
|
|
|
+ }
|
|
|
+ for _, mount := range mounts1 {
|
|
|
+ err := FS.Mount(mount.MountPoint, &Payload{FsName: mount.FileSystemName}, false)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("failed to mount %v: %v", mount.MountPoint, err)
|
|
|
+ } else {
|
|
|
+ t.Logf("mounted %s at %s.", mount.FileSystemName, mount.MountPoint)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ t.Log("-- Mount Test OK --")
|
|
|
+ t.Log("Mount Table:")
|
|
|
+ FS.ListAllMount(func(path string, payload *Payload) {
|
|
|
+ t.Logf("\t%s\t\t%s", payload.Name(), path)
|
|
|
+ })
|
|
|
+ t.Log("-- List Mount Table OK --")
|
|
|
+ tc1 := []TestCase{
|
|
|
+ {"/", "fs1", ""},
|
|
|
+ {"///", "fs1", ""},
|
|
|
+ {"", "fs1", ""},
|
|
|
+ {"/foobar", "fs1", "foobar"},
|
|
|
+ {"/reimu", "fs1", "reimu"},
|
|
|
+ {"/foobar/satori", "fs1", "foobar/satori"},
|
|
|
+ {"/reimu/cirno", "fs1", "reimu/cirno"},
|
|
|
+ {"/foo", "fs2", ""},
|
|
|
+ {"/foo/cirno", "fs2", "cirno"},
|
|
|
+ {"/foo/cirno/satori", "fs2", "cirno/satori"},
|
|
|
+ {"/foo/cirno/satori_komeiji", "fs2", "cirno/satori_komeiji"},
|
|
|
+ {"/foo/bar", "fs3", ""},
|
|
|
+ {"/foo/bar/////", "fs3", ""},
|
|
|
+ {"/foo/bar/", "fs3", ""},
|
|
|
+ {"/foo/bar/koishi", "fs3", "koishi"},
|
|
|
+ {"/foo/baz", "fs4", ""},
|
|
|
+ {"/foo/baz/qux114514", "fs4", "qux114514"},
|
|
|
+ {"/foo/baz/qux114514.fox", "fs4", "qux114514.fox"},
|
|
|
+ {"/foo/baz/qux/tac/mud", "fs5", ""},
|
|
|
+ {"/foo/baz/qux/tac/mud/can", "fs5", "can"},
|
|
|
+ {"/foo/baz/qux/fox", "fs6", ""},
|
|
|
+ {"/foo/baz/qux/fox/can/tell/you", "fs6", "can/tell/you"},
|
|
|
+ }
|
|
|
+ for _, tc := range tc1 {
|
|
|
+ payload, remain, err := FS.GetPayload(tc.Path)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("failed to get payload for %s: %v", tc, err)
|
|
|
+ }
|
|
|
+ if (*payload).Name() != tc.FileSystemName {
|
|
|
+ t.Fatalf("at '%s': payload mismatch: want %#v, got %#v", tc.Path, tc.FileSystemName, *payload)
|
|
|
+ }
|
|
|
+ if remain != tc.RemainPath {
|
|
|
+ t.Fatalf("at '%s': remain path mismatch: want %#v, got %#v", tc.Path, tc.RemainPath, remain)
|
|
|
+ }
|
|
|
+ t.Logf("at '%s': payload: %s, remain: %s", tc.Path, *payload, remain)
|
|
|
+ }
|
|
|
+ t.Log("-- GetPayload Test OK --")
|
|
|
+ t.Log("==== Phase2 ====")
|
|
|
+ umounts1 := []string{
|
|
|
+ "/foo/baz/qux/fox",
|
|
|
+ "/foo/bar",
|
|
|
+ }
|
|
|
+ for _, mount := range umounts1 {
|
|
|
+ err := FS.Umount(mount)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("failed to umount %v: %v", mount, err)
|
|
|
+ } else {
|
|
|
+ t.Logf("umounted %s.", mount)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ t.Log("-- Umount Test OK --")
|
|
|
+ t.Log("Mount Table:")
|
|
|
+ FS.ListAllMount(func(path string, payload *Payload) {
|
|
|
+ t.Logf("\t%s\t\t%s", payload.Name(), path)
|
|
|
+ })
|
|
|
+ t.Log("-- List Mount Table OK --")
|
|
|
+ tc2 := []TestCase{
|
|
|
+ {"/", "fs1", ""},
|
|
|
+ {"///", "fs1", ""},
|
|
|
+ {"", "fs1", ""},
|
|
|
+ {"/foobar", "fs1", "foobar"},
|
|
|
+ {"/reimu", "fs1", "reimu"},
|
|
|
+ {"/foobar/satori", "fs1", "foobar/satori"},
|
|
|
+ {"/reimu/cirno", "fs1", "reimu/cirno"},
|
|
|
+ {"/foo", "fs2", ""},
|
|
|
+ {"/foo/cirno", "fs2", "cirno"},
|
|
|
+ {"/foo/cirno/satori", "fs2", "cirno/satori"},
|
|
|
+ {"/foo/cirno/satori_komeiji", "fs2", "cirno/satori_komeiji"},
|
|
|
+ {"/foo/bar", "fs2", "bar"},
|
|
|
+ {"/foo/bar/////", "fs2", "bar"},
|
|
|
+ {"/foo/bar/", "fs2", "bar"},
|
|
|
+ {"/foo/bar/koishi", "fs2", "bar/koishi"},
|
|
|
+ {"/foo/baz", "fs4", ""},
|
|
|
+ {"/foo/baz/qux114514", "fs4", "qux114514"},
|
|
|
+ {"/foo/baz/qux114514.fox", "fs4", "qux114514.fox"},
|
|
|
+ {"/foo/baz/qux/tac/mud", "fs5", ""},
|
|
|
+ {"/foo/baz/qux/tac/mud/can", "fs5", "can"},
|
|
|
+ {"/foo/baz/qux/fox", "fs4", "qux/fox"},
|
|
|
+ {"/foo/baz/qux/fox/can/tell/you", "fs4", "qux/fox/can/tell/you"},
|
|
|
+ }
|
|
|
+ for _, tc := range tc2 {
|
|
|
+ payload, remain, err := FS.GetPayload(tc.Path)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("failed to get payload for %s: %v", tc.Path, err.Error())
|
|
|
+ }
|
|
|
+ if (*payload).Name() != tc.FileSystemName {
|
|
|
+ t.Fatalf("at '%s': payload mismatch: want %#v, got %#v", tc.Path, tc.FileSystemName, *payload)
|
|
|
+ }
|
|
|
+ if remain != tc.RemainPath {
|
|
|
+ t.Fatalf("at '%s': remain path mismatch: want %#v, got %#v", tc.Path, tc.RemainPath, remain)
|
|
|
+ }
|
|
|
+ t.Logf("at '%s': payload: %s, remain: %s", tc.Path, (*payload).Name(), remain)
|
|
|
+ }
|
|
|
+ t.Log("-- GetPayload Test OK --")
|
|
|
+ t.Log("==== Phase3 ====")
|
|
|
+ t.Log("mount an already mounted path '/' without force")
|
|
|
+ err := FS.Mount("/", &Payload{FsName: "errfs1"}, false)
|
|
|
+ if err != nil {
|
|
|
+ if mountree.CheckErrorType(err, mountree.ErrMountPointAlreadyExists) {
|
|
|
+ t.Log("Ok")
|
|
|
+ } else {
|
|
|
+ t.Fatalf(
|
|
|
+ "unexpected error type: want '%s', got '%s'",
|
|
|
+ mountree.ErrMountPointAlreadyExists.Error(),
|
|
|
+ err.Error(),
|
|
|
+ )
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ t.Fatal("test failed: this action should cause error")
|
|
|
+ }
|
|
|
+ t.Log("mount an already mounted path '/foo' without force")
|
|
|
+ err = FS.Mount("/", &Payload{FsName: "errfs2"}, false)
|
|
|
+ if err != nil {
|
|
|
+ if mountree.CheckErrorType(err, mountree.ErrMountPointAlreadyExists) {
|
|
|
+ t.Log("Ok")
|
|
|
+ } else {
|
|
|
+ t.Fatalf(
|
|
|
+ "unexpected error type: want '%s', got '%s'",
|
|
|
+ mountree.ErrMountPointAlreadyExists.Error(),
|
|
|
+ err.Error(),
|
|
|
+ )
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ t.Fatal("test failed: this action should cause error")
|
|
|
+ }
|
|
|
+ t.Log("mount an already mounted path '/' with force")
|
|
|
+ err = FS.Mount("/", &Payload{FsName: "fs7"}, true)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal("force remount '/' failed: ", err.Error())
|
|
|
+ } else {
|
|
|
+ t.Log("Ok")
|
|
|
+ }
|
|
|
+ t.Log("Mount Table:")
|
|
|
+ FS.ListAllMount(func(path string, payload *Payload) {
|
|
|
+ t.Logf("\t%s\t\t%s", payload.Name(), path)
|
|
|
+ })
|
|
|
+ t.Log("-- List Mount Table OK --")
|
|
|
+ tc3 := []TestCase{
|
|
|
+ {"/", "fs7", ""},
|
|
|
+ {"///", "fs7", ""},
|
|
|
+ {"", "fs7", ""},
|
|
|
+ {"/foobar", "fs7", "foobar"},
|
|
|
+ {"/foo/baz/qux/tac/mud", "fs5", ""},
|
|
|
+ {"/foo/baz/qux/tac/mud/can", "fs5", "can"},
|
|
|
+ }
|
|
|
+ for _, tc := range tc3 {
|
|
|
+ payload, remain, err := FS.GetPayload(tc.Path)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("failed to get payload for %s: %v", tc.Path, err.Error())
|
|
|
+ }
|
|
|
+ if (*payload).Name() != tc.FileSystemName {
|
|
|
+ t.Fatalf("at '%s': payload mismatch: want %#v, got %#v", tc.Path, tc.FileSystemName, *payload)
|
|
|
+ }
|
|
|
+ if remain != tc.RemainPath {
|
|
|
+ t.Fatalf("at '%s': remain path mismatch: want %#v, got %#v", tc.Path, tc.RemainPath, remain)
|
|
|
+ }
|
|
|
+ t.Logf("at '%s': payload: %s, remain: %s", tc.Path, (*payload).Name(), remain)
|
|
|
+ }
|
|
|
+ t.Log("-- GetPayload Test OK --")
|
|
|
+ t.Log("==== Phase4 ====")
|
|
|
+ t.Log("umount mount point that not exists: '/foo/cirno'")
|
|
|
+ err = FS.Umount("/foo/cirno")
|
|
|
+ if err != nil {
|
|
|
+ if mountree.CheckErrorType(err, mountree.ErrMountPointNotExists) {
|
|
|
+ t.Log("Ok")
|
|
|
+ } else {
|
|
|
+ t.Fatalf(
|
|
|
+ "unexpected error type: want '%s', got '%s'",
|
|
|
+ mountree.ErrMountPointNotExists.Error(),
|
|
|
+ err.Error(),
|
|
|
+ )
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ t.Fatal("test failed: this action should cause error")
|
|
|
+ }
|
|
|
+ t.Log("umount '/'")
|
|
|
+ err = FS.Umount("/")
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal("umount '/' failed: ", err.Error())
|
|
|
+ } else {
|
|
|
+ t.Log("Ok")
|
|
|
+ }
|
|
|
+ t.Log("Mount Table:")
|
|
|
+ FS.ListAllMount(func(path string, payload *Payload) {
|
|
|
+ t.Logf("\t%s\t\t%s", payload.Name(), path)
|
|
|
+ })
|
|
|
+ t.Log("-- List Mount Table OK --")
|
|
|
+ t.Log("test for '/'")
|
|
|
+ _, _, err = FS.GetPayload("/")
|
|
|
+ if err != nil {
|
|
|
+ if mountree.CheckErrorType(err, mountree.ErrNoAvailableMountPointForThisPath) {
|
|
|
+ t.Log("Ok")
|
|
|
+ } else {
|
|
|
+ t.Fatalf(
|
|
|
+ "unexpected error type: want '%s', got '%s'",
|
|
|
+ mountree.ErrNoAvailableMountPointForThisPath.Error(),
|
|
|
+ err.Error(),
|
|
|
+ )
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ t.Fatal("test failed: this action should cause error")
|
|
|
+ }
|
|
|
+ t.Log("test for '/cirno/koishi'")
|
|
|
+ _, _, err = FS.GetPayload("/cirno/koishi")
|
|
|
+ if err != nil {
|
|
|
+ if mountree.CheckErrorType(err, mountree.ErrNoAvailableMountPointForThisPath) {
|
|
|
+ t.Log("Ok")
|
|
|
+ } else {
|
|
|
+ t.Fatalf(
|
|
|
+ "unexpected error type: want '%s', got '%s'",
|
|
|
+ mountree.ErrNoAvailableMountPointForThisPath.Error(),
|
|
|
+ err.Error(),
|
|
|
+ )
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ t.Fatal("test failed: this action should cause error")
|
|
|
+ }
|
|
|
+ t.Log("==== Phase5 ====")
|
|
|
+ mounts2 := []Mount{
|
|
|
+ {"fs8", "/"},
|
|
|
+ {"fs9", "/foo/bar"},
|
|
|
+ {"fs10", "/foo/baz/qux/fox"},
|
|
|
+ {"fs11", "/foo/baz/lut"},
|
|
|
+ {"fs12", "/foo/baz/cuk"},
|
|
|
+ {"fs13", "/foo/baz/zek"},
|
|
|
+ {"fs14", "/foo/baz/zek/cirno"},
|
|
|
+ }
|
|
|
+ for _, mount := range mounts2 {
|
|
|
+ err := FS.Mount(mount.MountPoint, &Payload{FsName: mount.FileSystemName}, false)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("failed to mount %v: %v", mount.MountPoint, err)
|
|
|
+ } else {
|
|
|
+ t.Logf("mounted %s at %s.", mount.FileSystemName, mount.MountPoint)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ t.Log("-- Mount Test OK --")
|
|
|
+ t.Log("Mount Table:")
|
|
|
+ FS.ListAllMount(func(path string, payload *Payload) {
|
|
|
+ t.Logf("\t%s\t\t%s", payload.Name(), path)
|
|
|
+ })
|
|
|
+ t.Log("-- List Mount Table OK --")
|
|
|
+ tc4 := []TestCase{
|
|
|
+ {"/", "fs8", ""},
|
|
|
+ {"///", "fs8", ""},
|
|
|
+ {"", "fs8", ""},
|
|
|
+ {"/foo/bar/810", "fs9", "810"},
|
|
|
+ {"/foo/baz/qux/tac/mud", "fs5", ""},
|
|
|
+ {"/foo/baz/qux/tac/mud/can", "fs5", "can"},
|
|
|
+ {"/foo/baz/qux/fox/cat/dog", "fs10", "cat/dog"},
|
|
|
+ {"/foo/baz/lut/fox/cat/dog", "fs11", "fox/cat/dog"},
|
|
|
+ {"/foo/baz/cuk/cat/dog/fox", "fs12", "cat/dog/fox"},
|
|
|
+ {"/foo/baz/zek", "fs13", ""},
|
|
|
+ {"/foo/baz/zek/cirno", "fs14", ""},
|
|
|
+ {"/foo/baz/zek/cirno/satori", "fs14", "satori"},
|
|
|
+ {"/foo/baz", "fs4", ""},
|
|
|
+ {"/foo/baz/zun", "fs4", "zun"},
|
|
|
+ }
|
|
|
+ for _, tc := range tc4 {
|
|
|
+ payload, remain, err := FS.GetPayload(tc.Path)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("failed to get payload for %s: %v", tc.Path, err.Error())
|
|
|
+ }
|
|
|
+ if (*payload).Name() != tc.FileSystemName {
|
|
|
+ t.Fatalf("at '%s': payload mismatch: want %#v, got %#v", tc.Path, tc.FileSystemName, *payload)
|
|
|
+ }
|
|
|
+ if remain != tc.RemainPath {
|
|
|
+ t.Fatalf("at '%s': remain path mismatch: want %#v, got %#v", tc.Path, tc.RemainPath, remain)
|
|
|
+ }
|
|
|
+ t.Logf("at '%s': payload: %s, remain: %s", tc.Path, (*payload).Name(), remain)
|
|
|
+ }
|
|
|
+ t.Log("-- GetPayload Test OK --")
|
|
|
+ t.Log("==== Phase5 ====")
|
|
|
+
|
|
|
+ t.Log("umount '/foo/baz'")
|
|
|
+ err = FS.Umount("/foo/baz")
|
|
|
+ if err != nil {
|
|
|
+ t.Fatal("umount '/' failed: ", err.Error())
|
|
|
+ } else {
|
|
|
+ t.Log("Ok")
|
|
|
+ }
|
|
|
+ t.Log("Mount Table:")
|
|
|
+ FS.ListAllMount(func(path string, payload *Payload) {
|
|
|
+ t.Logf("\t%s\t\t%s", payload.Name(), path)
|
|
|
+ })
|
|
|
+ t.Log("-- List Mount Table OK --")
|
|
|
+ tc5 := []TestCase{
|
|
|
+ {"/", "fs8", ""},
|
|
|
+ {"///", "fs8", ""},
|
|
|
+ {"", "fs8", ""},
|
|
|
+ {"/foo/bar/810", "fs9", "810"},
|
|
|
+ {"/foo/baz/qux/tac/mud", "fs5", ""},
|
|
|
+ {"/foo/baz/qux/tac/mud/can", "fs5", "can"},
|
|
|
+ {"/foo/baz/qux/fox/cat/dog", "fs10", "cat/dog"},
|
|
|
+ {"/foo/baz/lut/fox/cat/dog", "fs11", "fox/cat/dog"},
|
|
|
+ {"/foo/baz/cuk/cat/dog/fox", "fs12", "cat/dog/fox"},
|
|
|
+ {"/foo/baz/zek", "fs13", ""},
|
|
|
+ {"/foo/baz/zek/cirno", "fs14", ""},
|
|
|
+ {"/foo/baz/zek/cirno/satori", "fs14", "satori"},
|
|
|
+ {"/foo/baz", "fs2", "baz"},
|
|
|
+ {"/foo/baz/zun", "fs2", "baz/zun"},
|
|
|
+ }
|
|
|
+ for _, tc := range tc5 {
|
|
|
+ payload, remain, err := FS.GetPayload(tc.Path)
|
|
|
+ if err != nil {
|
|
|
+ t.Fatalf("failed to get payload for %s: %v", tc.Path, err.Error())
|
|
|
+ }
|
|
|
+ if (*payload).Name() != tc.FileSystemName {
|
|
|
+ t.Fatalf("at '%s': payload mismatch: want %#v, got %#v", tc.Path, tc.FileSystemName, *payload)
|
|
|
+ }
|
|
|
+ if remain != tc.RemainPath {
|
|
|
+ t.Fatalf("at '%s': remain path mismatch: want %#v, got %#v", tc.Path, tc.RemainPath, remain)
|
|
|
+ }
|
|
|
+ t.Logf("at '%s': payload: %s, remain: %s", tc.Path, (*payload).Name(), remain)
|
|
|
+ }
|
|
|
+ t.Log("-- GetPayload Test OK --")
|
|
|
+}
|
|
|
+
|
|
|
+func TestMain(m *testing.M) {
|
|
|
+ FS = mountree.NewSimpleUnixLikePathTree[*Payload]()
|
|
|
+ m.Run()
|
|
|
+}
|