| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- package main
- import (
- "testing"
- "golang.org/x/sys/unix"
- )
- const sampleMountinfo = `22 1 252:0 / / rw,relatime shared:1 - ext4 /dev/mapper/vg-root rw
- 30 22 0:5 / /dev rw,nosuid shared:2 - devtmpfs udev rw
- 95 22 8:1 / /media/u/Data rw,relatime shared:50 - ext4 /dev/sda1 rw
- 96 22 8:1 /photos /mnt/photos\040bind rw,relatime shared:50 - ext4 /dev/sda1 rw
- `
- func TestParseMountinfo(t *testing.T) {
- es := parseMountinfo(sampleMountinfo)
- if len(es) != 4 {
- t.Fatalf("应解析出 4 条:%d", len(es))
- }
- if e := es[3]; e.Point != "/mnt/photos bind" || e.Root != "/photos" || e.Major != 8 || e.Minor != 1 || e.FSType != "ext4" || e.Source != "/dev/sda1" {
- t.Errorf("解析不正确:%+v", e)
- }
- }
- // fakeSystem 模拟挂载表、UUID 与设备号
- type fakeSystem struct {
- info string
- uuid map[uint64]string
- devs map[string]uint64 // 路径前缀 → 设备号(最长匹配)
- stats []string
- }
- func (f *fakeSystem) mountinfo() []mountEntry { return parseMountinfo(f.info) }
- func (f *fakeSystem) uuids() map[uint64]string { return f.uuid }
- func (f *fakeSystem) devOf(p string) (uint64, error) {
- f.stats = append(f.stats, p)
- best, dev := "", uint64(0)
- for prefix, d := range f.devs {
- if within(p, prefix) && len(prefix) >= len(best) {
- best, dev = prefix, d
- }
- }
- if best == "" {
- return 0, unix.ENOENT
- }
- return dev, nil
- }
- func TestIdentifyAndLocate(t *testing.T) {
- sda := unix.Mkdev(8, 1)
- root := unix.Mkdev(252, 0)
- sys := &fakeSystem{
- info: sampleMountinfo,
- uuid: map[uint64]string{sda: "aaaa-1111", root: "rootuuid"},
- devs: map[string]uint64{"/": root, "/media/u/Data": sda, "/mnt/photos bind": sda},
- }
- // 系统盘:只记路径
- if id := identify(sys, "/home/u/docs"); !id.SystemDisk || id.UUID != "" {
- t.Errorf("系统盘上的目录:%+v", id)
- }
- // 外接盘:UUID + 设备内路径
- id := identify(sys, "/media/u/Data/资料/合同")
- if id.UUID != "aaaa-1111" || id.RelPath != "/资料/合同" || id.SystemDisk || id.MountPoint != "/media/u/Data" {
- t.Fatalf("外接盘上的目录:%+v", id)
- }
- src := localSource{Path: id.Path, UUID: id.UUID, RelPath: id.RelPath}
- if p, err := locate(sys, src); err != nil || p != "/media/u/Data/资料/合同" {
- t.Errorf("设备在原位置:%q %v", p, err)
- }
- // bind mount 的子目录
- if p, err := locate(sys, localSource{Path: "/mnt/photos bind/2024", UUID: "aaaa-1111", RelPath: "/photos/2024"}); err != nil || p != "/mnt/photos bind/2024" {
- t.Errorf("bind mount:%q %v", p, err)
- }
- // 设备拔出:UUID 不在了
- sys.uuid = map[uint64]string{root: "rootuuid"}
- if _, err := locate(sys, src); err == nil || err.State != "device_missing" {
- t.Errorf("设备拔出应为 device_missing:%v", err)
- }
- // 设备插回,但挂到了别的位置(sdb)
- sdb := unix.Mkdev(8, 17)
- sys.uuid = map[uint64]string{sdb: "aaaa-1111", root: "rootuuid"}
- sys.info = "22 1 252:0 / / rw - ext4 /dev/mapper/vg-root rw\n97 22 8:17 / /media/u/Data1 rw - ext4 /dev/sdb1 rw\n"
- if p, err := locate(sys, src); err != nil || p != "/media/u/Data1/资料/合同" {
- t.Errorf("挂载位置变化后应能找到:%q %v", p, err)
- }
- // 另一块盘挂在原路径上:UUID 不同,不会被误认
- sys.uuid = map[uint64]string{sdb: "bbbb-2222", root: "rootuuid"}
- sys.info = "22 1 252:0 / / rw - ext4 /dev/mapper/vg-root rw\n97 22 8:17 / /media/u/Data rw - ext4 /dev/sdb1 rw\n"
- if _, err := locate(sys, src); err == nil || err.State != "device_missing" {
- t.Errorf("换了一块盘应为 device_missing:%v", err)
- }
- // 设备已连接但没有挂载(例如自动挂载):会访问原路径触发挂载
- sys.uuid = map[uint64]string{sda: "aaaa-1111", root: "rootuuid"}
- sys.info = "22 1 252:0 / / rw - ext4 /dev/mapper/vg-root rw\n"
- sys.stats = nil
- if _, err := locate(sys, src); err == nil || err.State != "device_missing" || !contains(err.Message, "没有挂载") {
- t.Errorf("已连接未挂载:%v", err)
- }
- if len(sys.stats) == 0 || sys.stats[0] != src.Path {
- t.Errorf("应访问原路径以触发自动挂载:%v", sys.stats)
- }
- // 只记路径的目录
- if p, err := locate(sys, localSource{Path: "/home/u/docs"}); err != nil || p != "/home/u/docs" {
- t.Errorf("系统盘:%q %v", p, err)
- }
- }
|