github.com/SmartMeshFoundation/Spectrum@v0.0.0-20220621030607-452a266fee1e/swarm/fuse/swarmfs_test.go (about) 1 // Copyright 2017 The Spectrum Authors 2 // This file is part of the Spectrum library. 3 // 4 // The Spectrum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The Spectrum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the Spectrum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // +build linux darwin freebsd 18 19 package fuse 20 21 import ( 22 "bytes" 23 "crypto/rand" 24 "io" 25 "io/ioutil" 26 "os" 27 "path/filepath" 28 "testing" 29 30 "github.com/SmartMeshFoundation/Spectrum/swarm/api" 31 "github.com/SmartMeshFoundation/Spectrum/swarm/storage" 32 ) 33 34 type fileInfo struct { 35 perm uint64 36 uid int 37 gid int 38 contents []byte 39 } 40 41 func createTestFilesAndUploadToSwarm(t *testing.T, api *api.Api, files map[string]fileInfo, uploadDir string) string { 42 os.RemoveAll(uploadDir) 43 44 for fname, finfo := range files { 45 actualPath := filepath.Join(uploadDir, fname) 46 filePath := filepath.Dir(actualPath) 47 48 err := os.MkdirAll(filePath, 0777) 49 if err != nil { 50 t.Fatalf("Error creating directory '%v' : %v", filePath, err) 51 } 52 53 fd, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(finfo.perm)) 54 if err1 != nil { 55 t.Fatalf("Error creating file %v: %v", actualPath, err1) 56 } 57 58 fd.Write(finfo.contents) 59 fd.Chown(finfo.uid, finfo.gid) 60 fd.Chmod(os.FileMode(finfo.perm)) 61 fd.Sync() 62 fd.Close() 63 } 64 65 bzzhash, err := api.Upload(uploadDir, "") 66 if err != nil { 67 t.Fatalf("Error uploading directory %v: %v", uploadDir, err) 68 } 69 70 return bzzhash 71 } 72 73 func mountDir(t *testing.T, api *api.Api, files map[string]fileInfo, bzzHash string, mountDir string) *SwarmFS { 74 os.RemoveAll(mountDir) 75 os.MkdirAll(mountDir, 0777) 76 swarmfs := NewSwarmFS(api) 77 _, err := swarmfs.Mount(bzzHash, mountDir) 78 if isFUSEUnsupportedError(err) { 79 t.Skip("FUSE not supported:", err) 80 } else if err != nil { 81 t.Fatalf("Error mounting hash %v: %v", bzzHash, err) 82 } 83 84 found := false 85 mi := swarmfs.Listmounts() 86 for _, minfo := range mi { 87 if minfo.MountPoint == mountDir { 88 if minfo.StartManifest != bzzHash || 89 minfo.LatestManifest != bzzHash || 90 minfo.fuseConnection == nil { 91 t.Fatalf("Error mounting: exp(%s): act(%s)", bzzHash, minfo.StartManifest) 92 } 93 found = true 94 } 95 } 96 97 // Test listMounts 98 if !found { 99 t.Fatalf("Error getting mounts information for %v: %v", mountDir, err) 100 } 101 102 // Check if file and their attributes are as expected 103 compareGeneratedFileWithFileInMount(t, files, mountDir) 104 105 return swarmfs 106 } 107 108 func compareGeneratedFileWithFileInMount(t *testing.T, files map[string]fileInfo, mountDir string) { 109 err := filepath.Walk(mountDir, func(path string, f os.FileInfo, err error) error { 110 if f.IsDir() { 111 return nil 112 } 113 fname := path[len(mountDir)+1:] 114 if _, ok := files[fname]; !ok { 115 t.Fatalf(" file %v present in mount dir and is not expected", fname) 116 } 117 return nil 118 }) 119 if err != nil { 120 t.Fatalf("Error walking dir %v", mountDir) 121 } 122 123 for fname, finfo := range files { 124 destinationFile := filepath.Join(mountDir, fname) 125 126 dfinfo, err := os.Stat(destinationFile) 127 if err != nil { 128 t.Fatalf("Destination file %v missing in mount: %v", fname, err) 129 } 130 131 if int64(len(finfo.contents)) != dfinfo.Size() { 132 t.Fatalf("file %v Size mismatch source (%v) vs destination(%v)", fname, int64(len(finfo.contents)), dfinfo.Size()) 133 } 134 135 if dfinfo.Mode().Perm().String() != "-rwx------" { 136 t.Fatalf("file %v Permission mismatch source (-rwx------) vs destination(%v)", fname, dfinfo.Mode().Perm()) 137 } 138 139 fileContents, err := ioutil.ReadFile(filepath.Join(mountDir, fname)) 140 if err != nil { 141 t.Fatalf("Could not readfile %v : %v", fname, err) 142 } 143 if !bytes.Equal(fileContents, finfo.contents) { 144 t.Fatalf("File %v contents mismatch: %v , %v", fname, fileContents, finfo.contents) 145 146 } 147 // TODO: check uid and gid 148 } 149 } 150 151 func checkFile(t *testing.T, testMountDir, fname string, contents []byte) { 152 destinationFile := filepath.Join(testMountDir, fname) 153 dfinfo, err1 := os.Stat(destinationFile) 154 if err1 != nil { 155 t.Fatalf("Could not stat file %v", destinationFile) 156 } 157 if dfinfo.Size() != int64(len(contents)) { 158 t.Fatalf("Mismatch in size actual(%v) vs expected(%v)", dfinfo.Size(), int64(len(contents))) 159 } 160 161 fd, err2 := os.OpenFile(destinationFile, os.O_RDONLY, os.FileMode(0665)) 162 if err2 != nil { 163 t.Fatalf("Could not open file %v", destinationFile) 164 } 165 newcontent := make([]byte, len(contents)) 166 fd.Read(newcontent) 167 fd.Close() 168 169 if !bytes.Equal(contents, newcontent) { 170 t.Fatalf("File content mismatch expected (%v): received (%v) ", contents, newcontent) 171 } 172 } 173 174 func getRandomBtes(size int) []byte { 175 contents := make([]byte, size) 176 rand.Read(contents) 177 return contents 178 } 179 180 func isDirEmpty(name string) bool { 181 f, err := os.Open(name) 182 if err != nil { 183 return false 184 } 185 defer f.Close() 186 187 _, err = f.Readdirnames(1) 188 189 return err == io.EOF 190 } 191 192 type testAPI struct { 193 api *api.Api 194 } 195 196 func (ta *testAPI) mountListAndUnmount(t *testing.T) { 197 files := make(map[string]fileInfo) 198 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "fuse-source") 199 testMountDir, _ := ioutil.TempDir(os.TempDir(), "fuse-dest") 200 201 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 202 files["2.txt"] = fileInfo{0711, 333, 444, getRandomBtes(10)} 203 files["3.txt"] = fileInfo{0622, 333, 444, getRandomBtes(100)} 204 files["4.txt"] = fileInfo{0533, 333, 444, getRandomBtes(1024)} 205 files["5.txt"] = fileInfo{0544, 333, 444, getRandomBtes(10)} 206 files["6.txt"] = fileInfo{0555, 333, 444, getRandomBtes(10)} 207 files["7.txt"] = fileInfo{0666, 333, 444, getRandomBtes(10)} 208 files["8.txt"] = fileInfo{0777, 333, 333, getRandomBtes(10)} 209 files["11.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)} 210 files["111.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)} 211 files["two/2.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)} 212 files["two/2/2.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10)} 213 files["two/2./2.txt"] = fileInfo{0777, 444, 444, getRandomBtes(10)} 214 files["twice/2.txt"] = fileInfo{0777, 444, 333, getRandomBtes(200)} 215 files["one/two/three/four/five/six/seven/eight/nine/10.txt"] = fileInfo{0777, 333, 444, getRandomBtes(10240)} 216 files["one/two/three/four/five/six/six"] = fileInfo{0777, 333, 444, getRandomBtes(10)} 217 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 218 219 swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir) 220 defer swarmfs.Stop() 221 222 // Check unmount 223 _, err := swarmfs.Unmount(testMountDir) 224 if err != nil { 225 t.Fatalf("could not unmount %v", bzzHash) 226 } 227 if !isDirEmpty(testMountDir) { 228 t.Fatalf("unmount didnt work for %v", testMountDir) 229 } 230 231 } 232 233 func (ta *testAPI) maxMounts(t *testing.T) { 234 files := make(map[string]fileInfo) 235 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 236 uploadDir1, _ := ioutil.TempDir(os.TempDir(), "max-upload1") 237 bzzHash1 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir1) 238 mount1, _ := ioutil.TempDir(os.TempDir(), "max-mount1") 239 swarmfs1 := mountDir(t, ta.api, files, bzzHash1, mount1) 240 defer swarmfs1.Stop() 241 242 files["2.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 243 uploadDir2, _ := ioutil.TempDir(os.TempDir(), "max-upload2") 244 bzzHash2 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir2) 245 mount2, _ := ioutil.TempDir(os.TempDir(), "max-mount2") 246 swarmfs2 := mountDir(t, ta.api, files, bzzHash2, mount2) 247 defer swarmfs2.Stop() 248 249 files["3.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 250 uploadDir3, _ := ioutil.TempDir(os.TempDir(), "max-upload3") 251 bzzHash3 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir3) 252 mount3, _ := ioutil.TempDir(os.TempDir(), "max-mount3") 253 swarmfs3 := mountDir(t, ta.api, files, bzzHash3, mount3) 254 defer swarmfs3.Stop() 255 256 files["4.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 257 uploadDir4, _ := ioutil.TempDir(os.TempDir(), "max-upload4") 258 bzzHash4 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir4) 259 mount4, _ := ioutil.TempDir(os.TempDir(), "max-mount4") 260 swarmfs4 := mountDir(t, ta.api, files, bzzHash4, mount4) 261 defer swarmfs4.Stop() 262 263 files["5.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 264 uploadDir5, _ := ioutil.TempDir(os.TempDir(), "max-upload5") 265 bzzHash5 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir5) 266 mount5, _ := ioutil.TempDir(os.TempDir(), "max-mount5") 267 swarmfs5 := mountDir(t, ta.api, files, bzzHash5, mount5) 268 defer swarmfs5.Stop() 269 270 files["6.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 271 uploadDir6, _ := ioutil.TempDir(os.TempDir(), "max-upload6") 272 bzzHash6 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir6) 273 mount6, _ := ioutil.TempDir(os.TempDir(), "max-mount6") 274 275 os.RemoveAll(mount6) 276 os.MkdirAll(mount6, 0777) 277 _, err := swarmfs.Mount(bzzHash6, mount6) 278 if err == nil { 279 t.Fatalf("Error: Going beyond max mounts %v", bzzHash6) 280 } 281 282 } 283 284 func (ta *testAPI) remount(t *testing.T) { 285 files := make(map[string]fileInfo) 286 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 287 uploadDir1, _ := ioutil.TempDir(os.TempDir(), "re-upload1") 288 bzzHash1 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir1) 289 testMountDir1, _ := ioutil.TempDir(os.TempDir(), "re-mount1") 290 swarmfs := mountDir(t, ta.api, files, bzzHash1, testMountDir1) 291 defer swarmfs.Stop() 292 293 uploadDir2, _ := ioutil.TempDir(os.TempDir(), "re-upload2") 294 bzzHash2 := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir2) 295 testMountDir2, _ := ioutil.TempDir(os.TempDir(), "re-mount2") 296 297 // try mounting the same hash second time 298 os.RemoveAll(testMountDir2) 299 os.MkdirAll(testMountDir2, 0777) 300 _, err := swarmfs.Mount(bzzHash1, testMountDir2) 301 if err != nil { 302 t.Fatalf("Error mounting hash %v", bzzHash1) 303 } 304 305 // mount a different hash in already mounted point 306 _, err = swarmfs.Mount(bzzHash2, testMountDir1) 307 if err == nil { 308 t.Fatalf("Error mounting hash %v", bzzHash2) 309 } 310 311 // mount nonexistent hash 312 _, err = swarmfs.Mount("0xfea11223344", testMountDir1) 313 if err == nil { 314 t.Fatalf("Error mounting hash %v", bzzHash2) 315 } 316 } 317 318 func (ta *testAPI) unmount(t *testing.T) { 319 files := make(map[string]fileInfo) 320 uploadDir, _ := ioutil.TempDir(os.TempDir(), "ex-upload") 321 testMountDir, _ := ioutil.TempDir(os.TempDir(), "ex-mount") 322 323 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 324 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, uploadDir) 325 326 swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir) 327 defer swarmfs.Stop() 328 329 swarmfs.Unmount(testMountDir) 330 331 mi := swarmfs.Listmounts() 332 for _, minfo := range mi { 333 if minfo.MountPoint == testMountDir { 334 t.Fatalf("mount state not cleaned up in unmount case %v", testMountDir) 335 } 336 } 337 } 338 339 func (ta *testAPI) unmountWhenResourceBusy(t *testing.T) { 340 files := make(map[string]fileInfo) 341 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "ex-upload") 342 testMountDir, _ := ioutil.TempDir(os.TempDir(), "ex-mount") 343 344 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 345 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 346 347 swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir) 348 defer swarmfs.Stop() 349 350 actualPath := filepath.Join(testMountDir, "2.txt") 351 d, err := os.OpenFile(actualPath, os.O_RDWR, os.FileMode(0700)) 352 d.Write(getRandomBtes(10)) 353 354 _, err = swarmfs.Unmount(testMountDir) 355 if err != nil { 356 t.Fatalf("could not unmount %v", bzzHash) 357 } 358 d.Close() 359 360 mi := swarmfs.Listmounts() 361 for _, minfo := range mi { 362 if minfo.MountPoint == testMountDir { 363 t.Fatalf("mount state not cleaned up in unmount case %v", testMountDir) 364 } 365 } 366 } 367 368 func (ta *testAPI) seekInMultiChunkFile(t *testing.T) { 369 files := make(map[string]fileInfo) 370 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "seek-upload") 371 testMountDir, _ := ioutil.TempDir(os.TempDir(), "seek-mount") 372 373 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10240)} 374 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 375 376 swarmfs := mountDir(t, ta.api, files, bzzHash, testMountDir) 377 defer swarmfs.Stop() 378 379 // Create a new file seek the second chunk 380 actualPath := filepath.Join(testMountDir, "1.txt") 381 d, _ := os.OpenFile(actualPath, os.O_RDONLY, os.FileMode(0700)) 382 383 d.Seek(5000, 0) 384 385 contents := make([]byte, 1024) 386 d.Read(contents) 387 finfo := files["1.txt"] 388 389 if !bytes.Equal(finfo.contents[:6024][5000:], contents) { 390 t.Fatalf("File seek contents mismatch") 391 } 392 d.Close() 393 } 394 395 func (ta *testAPI) createNewFile(t *testing.T) { 396 files := make(map[string]fileInfo) 397 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "create-upload") 398 testMountDir, _ := ioutil.TempDir(os.TempDir(), "create-mount") 399 400 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 401 files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 402 files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 403 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 404 405 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 406 defer swarmfs1.Stop() 407 408 // Create a new file in the root dir and check 409 actualPath := filepath.Join(testMountDir, "2.txt") 410 d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) 411 if err1 != nil { 412 t.Fatalf("Could not create file %s : %v", actualPath, err1) 413 } 414 contents := make([]byte, 11) 415 rand.Read(contents) 416 d.Write(contents) 417 d.Close() 418 419 mi, err2 := swarmfs1.Unmount(testMountDir) 420 if err2 != nil { 421 t.Fatalf("Could not unmount %v", err2) 422 } 423 424 // mount again and see if things are okay 425 files["2.txt"] = fileInfo{0700, 333, 444, contents} 426 swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) 427 defer swarmfs2.Stop() 428 429 checkFile(t, testMountDir, "2.txt", contents) 430 } 431 432 func (ta *testAPI) createNewFileInsideDirectory(t *testing.T) { 433 files := make(map[string]fileInfo) 434 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "createinsidedir-upload") 435 testMountDir, _ := ioutil.TempDir(os.TempDir(), "createinsidedir-mount") 436 437 files["one/1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 438 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 439 440 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 441 defer swarmfs1.Stop() 442 443 // Create a new file inside a existing dir and check 444 dirToCreate := filepath.Join(testMountDir, "one") 445 actualPath := filepath.Join(dirToCreate, "2.txt") 446 d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) 447 if err1 != nil { 448 t.Fatalf("Could not create file %s : %v", actualPath, err1) 449 } 450 contents := make([]byte, 11) 451 rand.Read(contents) 452 d.Write(contents) 453 d.Close() 454 455 mi, err2 := swarmfs1.Unmount(testMountDir) 456 if err2 != nil { 457 t.Fatalf("Could not unmount %v", err2) 458 } 459 460 // mount again and see if things are okay 461 files["one/2.txt"] = fileInfo{0700, 333, 444, contents} 462 swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) 463 defer swarmfs2.Stop() 464 465 checkFile(t, testMountDir, "one/2.txt", contents) 466 } 467 468 func (ta *testAPI) createNewFileInsideNewDirectory(t *testing.T) { 469 files := make(map[string]fileInfo) 470 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "createinsidenewdir-upload") 471 testMountDir, _ := ioutil.TempDir(os.TempDir(), "createinsidenewdir-mount") 472 473 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 474 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 475 476 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 477 defer swarmfs1.Stop() 478 479 // Create a new file inside a existing dir and check 480 dirToCreate := filepath.Join(testMountDir, "one") 481 os.MkdirAll(dirToCreate, 0777) 482 actualPath := filepath.Join(dirToCreate, "2.txt") 483 d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) 484 if err1 != nil { 485 t.Fatalf("Could not create file %s : %v", actualPath, err1) 486 } 487 contents := make([]byte, 11) 488 rand.Read(contents) 489 d.Write(contents) 490 d.Close() 491 492 mi, err2 := swarmfs1.Unmount(testMountDir) 493 if err2 != nil { 494 t.Fatalf("Could not unmount %v", err2) 495 } 496 497 // mount again and see if things are okay 498 files["one/2.txt"] = fileInfo{0700, 333, 444, contents} 499 swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) 500 defer swarmfs2.Stop() 501 502 checkFile(t, testMountDir, "one/2.txt", contents) 503 } 504 505 func (ta *testAPI) removeExistingFile(t *testing.T) { 506 files := make(map[string]fileInfo) 507 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "remove-upload") 508 testMountDir, _ := ioutil.TempDir(os.TempDir(), "remove-mount") 509 510 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 511 files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 512 files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 513 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 514 515 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 516 defer swarmfs1.Stop() 517 518 // Remove a file in the root dir and check 519 actualPath := filepath.Join(testMountDir, "five.txt") 520 os.Remove(actualPath) 521 522 mi, err2 := swarmfs1.Unmount(testMountDir) 523 if err2 != nil { 524 t.Fatalf("Could not unmount %v", err2) 525 } 526 527 // mount again and see if things are okay 528 delete(files, "five.txt") 529 swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) 530 defer swarmfs2.Stop() 531 } 532 533 func (ta *testAPI) removeExistingFileInsideDir(t *testing.T) { 534 files := make(map[string]fileInfo) 535 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "remove-upload") 536 testMountDir, _ := ioutil.TempDir(os.TempDir(), "remove-mount") 537 538 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 539 files["one/five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 540 files["one/six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 541 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 542 543 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 544 defer swarmfs1.Stop() 545 546 // Remove a file in the root dir and check 547 actualPath := filepath.Join(testMountDir, "one/five.txt") 548 os.Remove(actualPath) 549 550 mi, err2 := swarmfs1.Unmount(testMountDir) 551 if err2 != nil { 552 t.Fatalf("Could not unmount %v", err2) 553 } 554 555 // mount again and see if things are okay 556 delete(files, "one/five.txt") 557 swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) 558 defer swarmfs2.Stop() 559 } 560 561 func (ta *testAPI) removeNewlyAddedFile(t *testing.T) { 562 563 files := make(map[string]fileInfo) 564 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "removenew-upload") 565 testMountDir, _ := ioutil.TempDir(os.TempDir(), "removenew-mount") 566 567 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 568 files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 569 files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 570 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 571 572 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 573 defer swarmfs1.Stop() 574 575 // Adda a new file and remove it 576 dirToCreate := filepath.Join(testMountDir, "one") 577 os.MkdirAll(dirToCreate, os.FileMode(0665)) 578 actualPath := filepath.Join(dirToCreate, "2.txt") 579 d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) 580 if err1 != nil { 581 t.Fatalf("Could not create file %s : %v", actualPath, err1) 582 } 583 contents := make([]byte, 11) 584 rand.Read(contents) 585 d.Write(contents) 586 d.Close() 587 588 checkFile(t, testMountDir, "one/2.txt", contents) 589 590 os.Remove(actualPath) 591 592 mi, err2 := swarmfs1.Unmount(testMountDir) 593 if err2 != nil { 594 t.Fatalf("Could not unmount %v", err2) 595 } 596 597 // mount again and see if things are okay 598 swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) 599 defer swarmfs2.Stop() 600 601 if bzzHash != mi.LatestManifest { 602 t.Fatalf("same contents different hash orig(%v): new(%v)", bzzHash, mi.LatestManifest) 603 } 604 } 605 606 func (ta *testAPI) addNewFileAndModifyContents(t *testing.T) { 607 files := make(map[string]fileInfo) 608 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "modifyfile-upload") 609 testMountDir, _ := ioutil.TempDir(os.TempDir(), "modifyfile-mount") 610 611 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 612 files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 613 files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 614 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 615 616 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 617 defer swarmfs1.Stop() 618 619 // Create a new file in the root dir and check 620 actualPath := filepath.Join(testMountDir, "2.txt") 621 d, err1 := os.OpenFile(actualPath, os.O_RDWR|os.O_CREATE, os.FileMode(0665)) 622 if err1 != nil { 623 t.Fatalf("Could not create file %s : %v", actualPath, err1) 624 } 625 line1 := []byte("Line 1") 626 rand.Read(line1) 627 d.Write(line1) 628 d.Close() 629 630 mi1, err2 := swarmfs1.Unmount(testMountDir) 631 if err2 != nil { 632 t.Fatalf("Could not unmount %v", err2) 633 } 634 635 // mount again and see if things are okay 636 files["2.txt"] = fileInfo{0700, 333, 444, line1} 637 swarmfs2 := mountDir(t, ta.api, files, mi1.LatestManifest, testMountDir) 638 defer swarmfs2.Stop() 639 640 checkFile(t, testMountDir, "2.txt", line1) 641 642 mi2, err3 := swarmfs2.Unmount(testMountDir) 643 if err3 != nil { 644 t.Fatalf("Could not unmount %v", err3) 645 } 646 647 // mount again and modify 648 swarmfs3 := mountDir(t, ta.api, files, mi2.LatestManifest, testMountDir) 649 defer swarmfs3.Stop() 650 651 fd, err4 := os.OpenFile(actualPath, os.O_RDWR|os.O_APPEND, os.FileMode(0665)) 652 if err4 != nil { 653 t.Fatalf("Could not create file %s : %v", actualPath, err4) 654 } 655 line2 := []byte("Line 2") 656 rand.Read(line2) 657 fd.Seek(int64(len(line1)), 0) 658 fd.Write(line2) 659 fd.Close() 660 661 mi3, err5 := swarmfs3.Unmount(testMountDir) 662 if err5 != nil { 663 t.Fatalf("Could not unmount %v", err5) 664 } 665 666 // mount again and see if things are okay 667 b := [][]byte{line1, line2} 668 line1and2 := bytes.Join(b, []byte("")) 669 files["2.txt"] = fileInfo{0700, 333, 444, line1and2} 670 swarmfs4 := mountDir(t, ta.api, files, mi3.LatestManifest, testMountDir) 671 defer swarmfs4.Stop() 672 673 checkFile(t, testMountDir, "2.txt", line1and2) 674 } 675 676 func (ta *testAPI) removeEmptyDir(t *testing.T) { 677 files := make(map[string]fileInfo) 678 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-upload") 679 testMountDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-mount") 680 681 files["1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 682 files["five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 683 files["six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 684 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 685 686 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 687 defer swarmfs1.Stop() 688 689 os.MkdirAll(filepath.Join(testMountDir, "newdir"), 0777) 690 691 mi, err3 := swarmfs1.Unmount(testMountDir) 692 if err3 != nil { 693 t.Fatalf("Could not unmount %v", err3) 694 } 695 if bzzHash != mi.LatestManifest { 696 t.Fatalf("same contents different hash orig(%v): new(%v)", bzzHash, mi.LatestManifest) 697 } 698 } 699 700 func (ta *testAPI) removeDirWhichHasFiles(t *testing.T) { 701 files := make(map[string]fileInfo) 702 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-upload") 703 testMountDir, _ := ioutil.TempDir(os.TempDir(), "rmdir-mount") 704 705 files["one/1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 706 files["two/five.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 707 files["two/six.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 708 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 709 710 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 711 defer swarmfs1.Stop() 712 713 dirPath := filepath.Join(testMountDir, "two") 714 os.RemoveAll(dirPath) 715 716 mi, err2 := swarmfs1.Unmount(testMountDir) 717 if err2 != nil { 718 t.Fatalf("Could not unmount %v ", err2) 719 } 720 721 // mount again and see if things are okay 722 delete(files, "two/five.txt") 723 delete(files, "two/six.txt") 724 725 swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) 726 defer swarmfs2.Stop() 727 } 728 729 func (ta *testAPI) removeDirWhichHasSubDirs(t *testing.T) { 730 files := make(map[string]fileInfo) 731 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "rmsubdir-upload") 732 testMountDir, _ := ioutil.TempDir(os.TempDir(), "rmsubdir-mount") 733 734 files["one/1.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 735 files["two/three/2.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 736 files["two/three/3.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 737 files["two/four/5.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 738 files["two/four/6.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 739 files["two/four/six/7.txt"] = fileInfo{0700, 333, 444, getRandomBtes(10)} 740 741 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 742 743 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 744 defer swarmfs1.Stop() 745 746 dirPath := filepath.Join(testMountDir, "two") 747 os.RemoveAll(dirPath) 748 749 mi, err2 := swarmfs1.Unmount(testMountDir) 750 if err2 != nil { 751 t.Fatalf("Could not unmount %v ", err2) 752 } 753 754 // mount again and see if things are okay 755 delete(files, "two/three/2.txt") 756 delete(files, "two/three/3.txt") 757 delete(files, "two/four/5.txt") 758 delete(files, "two/four/6.txt") 759 delete(files, "two/four/six/7.txt") 760 761 swarmfs2 := mountDir(t, ta.api, files, mi.LatestManifest, testMountDir) 762 defer swarmfs2.Stop() 763 } 764 765 func (ta *testAPI) appendFileContentsToEnd(t *testing.T) { 766 files := make(map[string]fileInfo) 767 testUploadDir, _ := ioutil.TempDir(os.TempDir(), "appendlargefile-upload") 768 testMountDir, _ := ioutil.TempDir(os.TempDir(), "appendlargefile-mount") 769 770 line1 := make([]byte, 10) 771 rand.Read(line1) 772 files["1.txt"] = fileInfo{0700, 333, 444, line1} 773 bzzHash := createTestFilesAndUploadToSwarm(t, ta.api, files, testUploadDir) 774 775 swarmfs1 := mountDir(t, ta.api, files, bzzHash, testMountDir) 776 defer swarmfs1.Stop() 777 778 actualPath := filepath.Join(testMountDir, "1.txt") 779 fd, err4 := os.OpenFile(actualPath, os.O_RDWR|os.O_APPEND, os.FileMode(0665)) 780 if err4 != nil { 781 t.Fatalf("Could not create file %s : %v", actualPath, err4) 782 } 783 line2 := make([]byte, 5) 784 rand.Read(line2) 785 fd.Seek(int64(len(line1)), 0) 786 fd.Write(line2) 787 fd.Close() 788 789 mi1, err5 := swarmfs1.Unmount(testMountDir) 790 if err5 != nil { 791 t.Fatalf("Could not unmount %v ", err5) 792 } 793 794 // mount again and see if things are okay 795 b := [][]byte{line1, line2} 796 line1and2 := bytes.Join(b, []byte("")) 797 files["1.txt"] = fileInfo{0700, 333, 444, line1and2} 798 swarmfs2 := mountDir(t, ta.api, files, mi1.LatestManifest, testMountDir) 799 defer swarmfs2.Stop() 800 801 checkFile(t, testMountDir, "1.txt", line1and2) 802 } 803 804 func TestFUSE(t *testing.T) { 805 datadir, err := ioutil.TempDir("", "fuse") 806 if err != nil { 807 t.Fatalf("unable to create temp dir: %v", err) 808 } 809 os.RemoveAll(datadir) 810 811 dpa, err := storage.NewLocalDPA(datadir) 812 if err != nil { 813 t.Fatal(err) 814 } 815 ta := &testAPI{api: api.NewApi(dpa, nil)} 816 dpa.Start() 817 defer dpa.Stop() 818 819 t.Run("mountListAndUmount", ta.mountListAndUnmount) 820 t.Run("maxMounts", ta.maxMounts) 821 t.Run("remount", ta.remount) 822 t.Run("unmount", ta.unmount) 823 t.Run("unmountWhenResourceBusy", ta.unmountWhenResourceBusy) 824 t.Run("seekInMultiChunkFile", ta.seekInMultiChunkFile) 825 t.Run("createNewFile", ta.createNewFile) 826 t.Run("createNewFileInsideDirectory", ta.createNewFileInsideDirectory) 827 t.Run("createNewFileInsideNewDirectory", ta.createNewFileInsideNewDirectory) 828 t.Run("removeExistingFile", ta.removeExistingFile) 829 t.Run("removeExistingFileInsideDir", ta.removeExistingFileInsideDir) 830 t.Run("removeNewlyAddedFile", ta.removeNewlyAddedFile) 831 t.Run("addNewFileAndModifyContents", ta.addNewFileAndModifyContents) 832 t.Run("removeEmptyDir", ta.removeEmptyDir) 833 t.Run("removeDirWhichHasFiles", ta.removeDirWhichHasFiles) 834 t.Run("removeDirWhichHasSubDirs", ta.removeDirWhichHasSubDirs) 835 t.Run("appendFileContentsToEnd", ta.appendFileContentsToEnd) 836 }