tractor.dev/toolkit-go@v0.0.0-20241010005851-214d91207d07/engine/fs/mountablefs/mountablefs_test.go (about) 1 package mountablefs 2 3 import ( 4 "io/fs" 5 "testing" 6 7 "tractor.dev/toolkit-go/engine/fs/fstest" 8 "tractor.dev/toolkit-go/engine/fs/memfs" 9 ) 10 11 func TestMountUnmount(t *testing.T) { 12 host := memfs.New() 13 mnt := memfs.New() 14 15 fstest.WriteFS(t, host, map[string]string{ 16 "all": "host", 17 "mount/host-data": "host", 18 }) 19 20 fstest.WriteFS(t, mnt, map[string]string{ 21 "all2": "mounted", 22 "rickroll.mpv": "mounted", 23 }) 24 25 fsys := New(host) 26 if err := fsys.Mount(mnt, "mount"); err != nil { 27 t.Fatal(err) 28 } 29 30 fstest.CheckFS(t, fsys, map[string]string{ 31 "all": "host", 32 "mount/all2": "mounted", 33 "mount/rickroll.mpv": "mounted", 34 }) 35 36 if _, err := fsys.Open("mount/host-data"); err == nil { 37 t.Fatalf("Open: expected file %s to be masked by mount: got nil, expected %v", "mount/host-data", fs.ErrNotExist) 38 } 39 40 if err := fsys.Unmount("all"); err == nil { 41 t.Fatal("Unmount: expected error when attempting to Unmount a non-mountpoint, got nil") 42 } 43 44 if err := fsys.Unmount("mount"); err != nil { 45 t.Fatal(err) 46 } 47 48 fstest.CheckFS(t, fsys, map[string]string{ 49 "all": "host", 50 "mount/host-data": "host", 51 }) 52 53 if _, err := fsys.Open("mount/rickroll.mpv"); err == nil { 54 t.Fatalf("Open: unexpected file %s: expected error %v", "mount/rickroll.mpv", fs.ErrNotExist) 55 } 56 } 57 58 func TestRemove(t *testing.T) { 59 host := memfs.New() 60 mnt := memfs.New() 61 62 fstest.WriteFS(t, host, map[string]string{ 63 "A/B": "host", 64 "C/D/blah": "host", 65 }) 66 67 fstest.WriteFS(t, mnt, map[string]string{ 68 "E/F": "mounted", 69 "G/H": "mounted", 70 }) 71 72 fsys := New(host) 73 if err := fsys.Mount(mnt, "C/D"); err != nil { 74 t.Fatal(err) 75 } 76 77 fstest.CheckFS(t, fsys, map[string]string{ 78 "A/B": "host", 79 "C/D/E/F": "mounted", 80 "C/D/G/H": "mounted", 81 }) 82 83 if err := fsys.Remove("A/B"); err != nil { 84 t.Fatal(err) 85 } 86 87 if err := fsys.Remove("C/D/E/F"); err != nil { 88 t.Fatal(err) 89 } 90 91 if err := fsys.RemoveAll("C/D/G"); err != nil { 92 t.Fatal(err) 93 } 94 95 fstest.CheckFS(t, fsys, map[string]string{ 96 // dirs are empty strings 97 "A/": "", 98 "C/D/E/": "", 99 }) 100 101 if err := fsys.Remove("A/B"); err == nil { 102 t.Fatalf("Remove: expected attempt to Remove a non-existant file to fail") 103 } 104 105 if err := fsys.Remove("C/D/G"); err == nil { 106 t.Fatalf("Remove: expected attempt to Remove a non-existant file to fail") 107 } 108 109 if err := fsys.Remove("C/D"); err == nil { 110 t.Fatalf("Remove: expected attempt to Remove a mount-point file to fail") 111 } 112 113 if err := fsys.RemoveAll("C/D"); err == nil { 114 t.Fatalf("RemoveAll: expected attempt to RemoveAll a mount-point file to fail") 115 } 116 117 if err := fsys.RemoveAll("/"); err == nil { 118 t.Fatalf("RemoveAll: expected attempt to RemoveAll a path containing a mount-point file to fail") 119 } 120 121 fstest.CheckFS(t, fsys, map[string]string{ 122 // dirs are empty strings 123 "C/D/E/": "", 124 }) 125 126 if err := fsys.Unmount("C/D"); err != nil { 127 t.Fatal(err) 128 } 129 } 130 131 func TestRename(t *testing.T) { 132 host := memfs.New() 133 mnt := memfs.New() 134 135 fstest.WriteFS(t, host, map[string]string{ 136 "all": "host", 137 "mount/host-data": "host", 138 }) 139 140 fstest.WriteFS(t, mnt, map[string]string{ 141 "all2": "mounted", 142 "rickroll.mpv": "mounted", 143 }) 144 145 fsys := New(host) 146 if err := fsys.Mount(mnt, "mount"); err != nil { 147 t.Fatal(err) 148 } 149 150 if err := fsys.Rename("all", "none"); err != nil { 151 t.Fatal(err) 152 } 153 154 if err := fsys.Rename("mount/all2", "mount/none2"); err != nil { 155 t.Fatal(err) 156 } 157 158 if err := fsys.Rename("mount/rickroll.mpv", "rickroll.mpv"); err == nil { 159 t.Fatalf("Rename: expected error when attempting to rename across filesystems") 160 } 161 162 if err := fsys.Rename("mount", "not-a-mount"); err == nil { 163 t.Fatalf("Rename: expected error when attempting to rename a mountpoint") 164 } 165 166 fstest.CheckFS(t, fsys, map[string]string{ 167 "none": "host", 168 "mount/none2": "mounted", 169 "mount/rickroll.mpv": "mounted", 170 }) 171 172 if err := fsys.Unmount("mount"); err != nil { 173 t.Fatal(err) 174 } 175 } 176 177 func TestMkdir(t *testing.T) { 178 host := memfs.New() 179 mnt := memfs.New() 180 181 fstest.WriteFS(t, host, map[string]string{ 182 "all": "host", 183 "mount/host-data": "host", 184 }) 185 186 fstest.WriteFS(t, mnt, map[string]string{ 187 "all2": "mounted", 188 "rickroll.mpv": "mounted", 189 }) 190 191 fsys := New(host) 192 if err := fsys.Mount(mnt, "mount"); err != nil { 193 t.Fatal(err) 194 } 195 196 if err := fsys.Mkdir("all/new-host-dir", 0755); err != nil { 197 t.Fatal(err) 198 } 199 200 if err := fsys.Mkdir("mount/secret_tunnel", 0755); err != nil { 201 t.Fatal(err) 202 } 203 204 // TODO: memfs has incorrect behavior for creating and checking parents, so until 205 // it's fixed I'm leaving these commented. They're really testing the underlying 206 // filesystem implementation anyway. 207 // if err := fsys.Mkdir("mount/rickroll.mpv/nope", 0755); err == nil { 208 // t.Fatalf("Mkdir: expected error when attempting to make a directory under a file") 209 // } 210 211 // if err := fsys.Mkdir("mount/hello/goodbye", 0755); err == nil { 212 // t.Fatalf("Mkdir: expected error when attempting to make a directory with missing parents") 213 // } 214 215 if err := fsys.MkdirAll("mount/secret_tunnel/super_secret/deadend", 0755); err != nil { 216 t.Fatal(err) 217 } 218 219 fstest.CheckFS(t, fsys, map[string]string{ 220 // dirs are empty strings 221 "all/new-host-dir/": "", 222 "mount/all2": "mounted", 223 "mount/rickroll.mpv": "mounted", 224 "mount/secret_tunnel/super_secret/deadend/": "", 225 }) 226 227 if err := fsys.Unmount("mount"); err != nil { 228 t.Fatal(err) 229 } 230 }