gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/renter/files_test.go (about) 1 package renter 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "gitlab.com/NebulousLabs/errors" 13 "gitlab.com/NebulousLabs/fastrand" 14 15 "gitlab.com/SkynetLabs/skyd/skymodules" 16 "gitlab.com/SkynetLabs/skyd/skymodules/renter/filesystem" 17 "go.sia.tech/siad/crypto" 18 "go.sia.tech/siad/persist" 19 ) 20 21 // createRenterTestFile creates a test file when the test has a renter so that the 22 // file is properly added to the renter. It returns the SiaFileSetEntry that the 23 // SiaFile is stored in 24 func (r *Renter) createRenterTestFile(siaPath skymodules.SiaPath) (*filesystem.FileNode, error) { 25 // Generate erasure coder 26 _, rsc := testingFileParams() 27 return r.createRenterTestFileWithParams(siaPath, rsc, crypto.RandomCipherType()) 28 } 29 30 // createRenterTestFileWithParams creates a test file when the test has a renter 31 // so that the file is properly added to the renter. 32 func (r *Renter) createRenterTestFileWithParams(siaPath skymodules.SiaPath, rsc skymodules.ErasureCoder, ct crypto.CipherType) (*filesystem.FileNode, error) { 33 return r.createRenterTestFileWithParamsAndSize(siaPath, rsc, ct, 1000) 34 } 35 36 // createRenterTestFileWithParamsAndSize creates a test file when the test has 37 // a renter so that the file is properly added to the renter. 38 func (r *Renter) createRenterTestFileWithParamsAndSize(siaPath skymodules.SiaPath, rsc skymodules.ErasureCoder, ct crypto.CipherType, size uint64) (*filesystem.FileNode, error) { 39 // create the renter/files dir if it doesn't exist 40 siaFilePath := r.staticFileSystem.FilePath(siaPath) 41 dir, _ := filepath.Split(siaFilePath) 42 if err := os.MkdirAll(dir, 0700); err != nil { 43 return nil, err 44 } 45 // Create File 46 up := skymodules.FileUploadParams{ 47 Source: "", 48 SiaPath: siaPath, 49 ErasureCode: rsc, 50 } 51 err := r.staticFileSystem.NewSiaFile(up.SiaPath, up.Source, up.ErasureCode, crypto.GenerateSiaKey(ct), size, persist.DefaultDiskPermissionsTest) 52 if err != nil { 53 return nil, err 54 } 55 return r.staticFileSystem.OpenSiaFile(up.SiaPath) 56 } 57 58 // newRenterTestFile creates a test file when the test has a renter so that the 59 // file is properly added to the renter. It returns the SiaFileSetEntry that the 60 // SiaFile is stored in 61 func (r *Renter) newRenterTestFile() (*filesystem.FileNode, error) { 62 // Generate name and erasure coding 63 siaPath, rsc := testingFileParams() 64 f, err := r.createRenterTestFileWithParams(siaPath, rsc, crypto.RandomCipherType()) 65 if err != nil { 66 return nil, err 67 } 68 // Mark as finished for compatibility in testing 69 return f, f.SetFinished(0) 70 } 71 72 // TestRenterFileListLocalPath verifies that FileList() returns the correct 73 // local path information for an uploaded file. 74 func TestRenterFileListLocalPath(t *testing.T) { 75 if testing.Short() { 76 t.SkipNow() 77 } 78 rt, err := newRenterTester(t.Name()) 79 if err != nil { 80 t.Fatal(err) 81 } 82 defer func() { 83 if err := rt.Close(); err != nil { 84 t.Fatal(err) 85 } 86 }() 87 id := rt.renter.mu.Lock() 88 entry, _ := rt.renter.newRenterTestFile() 89 if err := entry.SetLocalPath("TestPath"); err != nil { 90 t.Fatal(err) 91 } 92 rt.renter.mu.Unlock(id) 93 files, err := rt.renter.FileListCollect(skymodules.RootSiaPath(), true, false) 94 if err != nil { 95 t.Fatal(err) 96 } 97 if len(files) != 1 { 98 t.Fatal("wrong number of files, got", len(files), "wanted one") 99 } 100 if files[0].LocalPath != "TestPath" { 101 t.Fatal("file had wrong LocalPath: got", files[0].LocalPath, "wanted TestPath") 102 } 103 } 104 105 // TestRenterDeleteFile probes the DeleteFile method of the renter type. 106 func TestRenterDeleteFile(t *testing.T) { 107 if testing.Short() { 108 t.SkipNow() 109 } 110 rt, err := newRenterTester(t.Name()) 111 if err != nil { 112 t.Fatal(err) 113 } 114 defer func() { 115 if err := rt.Close(); err != nil { 116 t.Fatal(err) 117 } 118 }() 119 120 // Delete a file from an empty renter. 121 siaPath, err := skymodules.NewSiaPath("dne") 122 if err != nil { 123 t.Fatal(err) 124 } 125 err = rt.renter.DeleteFile(siaPath) 126 // NOTE: using strings.Contains because errors.Contains does not recognize 127 // errors when errors.Extend is used 128 if !strings.Contains(err.Error(), filesystem.ErrNotExist.Error()) { 129 t.Errorf("Expected error to contain %v but got '%v'", filesystem.ErrNotExist, err) 130 } 131 132 // Put a file in the renter. 133 entry, err := rt.renter.newRenterTestFile() 134 if err != nil { 135 t.Fatal(err) 136 } 137 // Delete a different file. 138 siaPathOne, err := skymodules.NewSiaPath("one") 139 if err != nil { 140 t.Fatal(err) 141 } 142 err = rt.renter.DeleteFile(siaPathOne) 143 // NOTE: using strings.Contains because errors.Contains does not recognize 144 // errors when errors.Extend is used 145 if !strings.Contains(err.Error(), filesystem.ErrNotExist.Error()) { 146 t.Errorf("Expected error to contain %v but got '%v'", filesystem.ErrNotExist, err) 147 } 148 // Delete the file. 149 siapath := rt.renter.staticFileSystem.FileSiaPath(entry) 150 151 if err := entry.Close(); err != nil { 152 t.Fatal(err) 153 } 154 err = rt.renter.DeleteFile(siapath) 155 if err != nil { 156 t.Fatal(err) 157 } 158 files, err := rt.renter.FileListCollect(skymodules.RootSiaPath(), true, false) 159 if err != nil { 160 t.Fatal(err) 161 } 162 if len(files) != 0 { 163 t.Error("file was deleted, but is still reported in FileList") 164 } 165 // Confirm that file was removed from SiaFileSet 166 _, err = rt.renter.staticFileSystem.OpenSiaFile(siapath) 167 if err == nil { 168 t.Fatal("Deleted file still found in staticFileSet") 169 } 170 171 // Put a file in the renter, then rename it. 172 entry2, err := rt.renter.newRenterTestFile() 173 if err != nil { 174 t.Fatal(err) 175 } 176 siaPath1, err := skymodules.NewSiaPath("1") 177 if err != nil { 178 t.Fatal(err) 179 } 180 err = rt.renter.RenameFile(rt.renter.staticFileSystem.FileSiaPath(entry2), siaPath1) // set name to "1" 181 if err != nil { 182 t.Fatal(err) 183 } 184 siapath2 := rt.renter.staticFileSystem.FileSiaPath(entry2) 185 entry2.Close() 186 siapath2 = rt.renter.staticFileSystem.FileSiaPath(entry2) 187 err = rt.renter.RenameFile(siapath2, siaPathOne) 188 if err != nil { 189 t.Fatal(err) 190 } 191 // Call delete on the previous name. 192 err = rt.renter.DeleteFile(siaPath1) 193 // NOTE: using strings.Contains because errors.Contains does not recognize 194 // errors when errors.Extend is used 195 if !strings.Contains(err.Error(), filesystem.ErrNotExist.Error()) { 196 t.Errorf("Expected error to contain %v but got '%v'", filesystem.ErrNotExist, err) 197 } 198 // Call delete on the new name. 199 err = rt.renter.DeleteFile(siaPathOne) 200 if err != nil { 201 t.Error(err) 202 } 203 204 // Check that all .sia files have been deleted. 205 var walkStr string 206 rt.renter.staticFileSystem.Walk(skymodules.RootSiaPath(), func(path string, _ os.FileInfo, _ error) error { 207 // capture only .sia files 208 if filepath.Ext(path) == ".sia" { 209 rel, _ := filepath.Rel(rt.renter.staticFileSystem.Root(), path) // strip testdir prefix 210 walkStr += rel 211 } 212 return nil 213 }) 214 expWalkStr := "" 215 if walkStr != expWalkStr { 216 t.Fatalf("Bad walk string: expected %q, got %q", expWalkStr, walkStr) 217 } 218 } 219 220 // TestRenterDeleteFileMissingParent tries to delete a file for which the parent 221 // has been deleted before. 222 func TestRenterDeleteFileMissingParent(t *testing.T) { 223 if testing.Short() { 224 t.SkipNow() 225 } 226 rt, err := newRenterTester(t.Name()) 227 if err != nil { 228 t.Fatal(err) 229 } 230 defer func() { 231 if err := rt.Close(); err != nil { 232 t.Fatal(err) 233 } 234 }() 235 236 // Put a file in the renter. 237 siaPath, err := skymodules.NewSiaPath("parent/file") 238 if err != nil { 239 t.Fatal(err) 240 } 241 dirSiaPath, err := siaPath.Dir() 242 if err != nil { 243 t.Fatal(err) 244 } 245 siaPath, rsc := testingFileParams() 246 up := skymodules.FileUploadParams{ 247 Source: "", 248 SiaPath: siaPath, 249 ErasureCode: rsc, 250 } 251 err = rt.renter.staticFileSystem.NewSiaFile(up.SiaPath, up.Source, up.ErasureCode, crypto.GenerateSiaKey(crypto.RandomCipherType()), 1000, persist.DefaultDiskPermissionsTest) 252 if err != nil { 253 t.Fatal(err) 254 } 255 // Delete the parent. 256 err = rt.renter.staticFileSystem.DeleteFile(dirSiaPath) 257 // NOTE: using strings.Contains because errors.Contains does not recognize 258 // errors when errors.Extend is used 259 if !strings.Contains(err.Error(), filesystem.ErrNotExist.Error()) { 260 t.Errorf("Expected error to contain %v but got '%v'", filesystem.ErrNotExist, err) 261 } 262 // Delete the file. This should not return an error since it's already 263 // deleted implicitly. 264 if err := rt.renter.staticFileSystem.DeleteFile(up.SiaPath); err != nil { 265 t.Fatal(err) 266 } 267 } 268 269 // TestRenterFileList probes the FileList method of the renter type. 270 func TestRenterFileList(t *testing.T) { 271 if testing.Short() { 272 t.SkipNow() 273 } 274 rt, err := newRenterTester(t.Name()) 275 if err != nil { 276 t.Fatal(err) 277 } 278 defer func() { 279 if err := rt.Close(); err != nil { 280 t.Fatal(err) 281 } 282 }() 283 284 // Get the file list of an empty renter. 285 files, err := rt.renter.FileListCollect(skymodules.RootSiaPath(), true, false) 286 if err != nil { 287 t.Fatal(err) 288 } 289 if len(files) != 0 { 290 t.Fatal("FileList has non-zero length for empty renter?") 291 } 292 293 // Put a file in the renter. 294 entry1, _ := rt.renter.newRenterTestFile() 295 files, err = rt.renter.FileListCollect(skymodules.RootSiaPath(), true, false) 296 if err != nil { 297 t.Fatal(err) 298 } 299 if len(files) != 1 { 300 t.Fatal("FileList is not returning the only file in the renter") 301 } 302 entry1SP := rt.renter.staticFileSystem.FileSiaPath(entry1) 303 if !files[0].SiaPath.Equals(entry1SP) { 304 t.Error("FileList is not returning the correct filename for the only file") 305 } 306 307 // Put multiple files in the renter. 308 entry2, _ := rt.renter.newRenterTestFile() 309 entry2SP := rt.renter.staticFileSystem.FileSiaPath(entry2) 310 files, err = rt.renter.FileListCollect(skymodules.RootSiaPath(), true, false) 311 if err != nil { 312 t.Fatal(err) 313 } 314 if len(files) != 2 { 315 t.Fatalf("Expected %v files, got %v", 2, len(files)) 316 } 317 files, err = rt.renter.FileListCollect(skymodules.RootSiaPath(), true, false) 318 if err != nil { 319 t.Fatal(err) 320 } 321 if !((files[0].SiaPath.Equals(entry1SP) || files[0].SiaPath.Equals(entry2SP)) && 322 (files[1].SiaPath.Equals(entry1SP) || files[1].SiaPath.Equals(entry2SP)) && 323 (files[0].SiaPath != files[1].SiaPath)) { 324 t.Log("files[0].SiaPath", files[0].SiaPath) 325 t.Log("files[1].SiaPath", files[1].SiaPath) 326 t.Log("file1.SiaPath()", rt.renter.staticFileSystem.FileSiaPath(entry1).String()) 327 t.Log("file2.SiaPath()", rt.renter.staticFileSystem.FileSiaPath(entry2).String()) 328 t.Error("FileList is returning wrong names for the files") 329 } 330 } 331 332 // TestRenterRenameFile probes the rename method of the renter. 333 func TestRenterRenameFile(t *testing.T) { 334 if testing.Short() { 335 t.SkipNow() 336 } 337 rt, err := newRenterTester(t.Name()) 338 if err != nil { 339 t.Fatal(err) 340 } 341 defer func() { 342 if err := rt.Close(); err != nil { 343 t.Fatal(err) 344 } 345 }() 346 347 // Rename a file that doesn't exist. 348 siaPath1, err := skymodules.NewSiaPath("1") 349 if err != nil { 350 t.Fatal(err) 351 } 352 siaPath1a, err := skymodules.NewSiaPath("1a") 353 if err != nil { 354 t.Fatal(err) 355 } 356 err = rt.renter.RenameFile(siaPath1, siaPath1a) 357 if err.Error() != filesystem.ErrNotExist.Error() { 358 t.Errorf("Expected '%v' got '%v'", filesystem.ErrNotExist, err) 359 } 360 361 // Get the filesystem. 362 sfs := rt.renter.staticFileSystem 363 364 // Rename a file that does exist. 365 entry, _ := rt.renter.newRenterTestFile() 366 var sp skymodules.SiaPath 367 if err := sp.FromSysPath(entry.SiaFilePath(), sfs.DirPath(skymodules.RootSiaPath())); err != nil { 368 t.Fatal(err) 369 } 370 err = rt.renter.RenameFile(sp, siaPath1) 371 if err != nil { 372 t.Fatal(err) 373 } 374 err = rt.renter.RenameFile(siaPath1, siaPath1a) 375 if err != nil { 376 t.Fatal(err) 377 } 378 files, err := rt.renter.FileListCollect(skymodules.RootSiaPath(), true, false) 379 if err != nil { 380 t.Fatal(err) 381 } 382 if len(files) != 1 { 383 t.Fatal("FileList has unexpected number of files:", len(files)) 384 } 385 if !files[0].SiaPath.Equals(siaPath1a) { 386 t.Errorf("RenameFile failed: expected %v, got %v", siaPath1a.String(), files[0].SiaPath) 387 } 388 // Confirm SiaFileSet was updated 389 _, err = rt.renter.staticFileSystem.OpenSiaFile(siaPath1a) 390 if err != nil { 391 t.Fatal("renter staticFileSet not updated to new file name:", err) 392 } 393 _, err = rt.renter.staticFileSystem.OpenSiaFile(siaPath1) 394 if err == nil { 395 t.Fatal("old name not removed from renter staticFileSet") 396 } 397 // Rename a file to an existing name. 398 entry2, err := rt.renter.newRenterTestFile() 399 if err != nil { 400 t.Fatal(err) 401 } 402 var sp2 skymodules.SiaPath 403 if err := sp2.FromSysPath(entry2.SiaFilePath(), sfs.DirPath(skymodules.RootSiaPath())); err != nil { 404 t.Fatal(err) 405 } 406 err = rt.renter.RenameFile(sp2, siaPath1) // Rename to "1" 407 if err != nil { 408 t.Fatal(err) 409 } 410 entry2.Close() 411 err = rt.renter.RenameFile(siaPath1, siaPath1a) 412 if !errors.Contains(err, filesystem.ErrExists) { 413 t.Fatal("Expecting ErrExists, got", err) 414 } 415 // Rename a file to the same name. 416 err = rt.renter.RenameFile(siaPath1, siaPath1) 417 if !errors.Contains(err, filesystem.ErrExists) { 418 t.Fatal("Expecting ErrExists, got", err) 419 } 420 421 // Confirm ability to rename file 422 siaPath1b, err := skymodules.NewSiaPath("1b") 423 if err != nil { 424 t.Fatal(err) 425 } 426 err = rt.renter.RenameFile(siaPath1, siaPath1b) 427 if err != nil { 428 t.Fatal(err) 429 } 430 // Rename file that would create a directory 431 siaPathWithDir, err := skymodules.NewSiaPath("new/name/with/dir/test") 432 if err != nil { 433 t.Fatal(err) 434 } 435 err = rt.renter.RenameFile(siaPath1b, siaPathWithDir) 436 if err != nil { 437 t.Fatal(err) 438 } 439 440 // Confirm directory metadatas exist 441 for !siaPathWithDir.Equals(skymodules.RootSiaPath()) { 442 siaPathWithDir, err = siaPathWithDir.Dir() 443 if err != nil { 444 t.Fatal(err) 445 } 446 _, err = rt.renter.staticFileSystem.OpenSiaDir(siaPathWithDir) 447 if err != nil { 448 t.Fatal(err) 449 } 450 } 451 } 452 453 // TestRenterFileDir tests that the renter files are uploaded to the files 454 // directory and not the root directory of the renter. 455 func TestRenterFileDir(t *testing.T) { 456 if testing.Short() { 457 t.SkipNow() 458 } 459 rt, err := newRenterTester(t.Name()) 460 if err != nil { 461 t.Fatal(err) 462 } 463 defer func() { 464 if err := rt.Close(); err != nil { 465 t.Fatal(err) 466 } 467 }() 468 469 // Create local file to upload 470 localDir := filepath.Join(rt.dir, "files") 471 if err := os.MkdirAll(localDir, 0700); err != nil { 472 t.Fatal(err) 473 } 474 size := 100 475 fileName := fmt.Sprintf("%dbytes %s", size, hex.EncodeToString(fastrand.Bytes(4))) 476 source := filepath.Join(localDir, fileName) 477 bytes := fastrand.Bytes(size) 478 if err := ioutil.WriteFile(source, bytes, 0600); err != nil { 479 t.Fatal(err) 480 } 481 482 // Upload local file 483 ec := skymodules.NewRSCodeDefault() 484 siaPath, err := skymodules.NewSiaPath(fileName) 485 if err != nil { 486 t.Fatal(err) 487 } 488 params := skymodules.FileUploadParams{ 489 Source: source, 490 SiaPath: siaPath, 491 ErasureCode: ec, 492 } 493 err = rt.renter.Upload(params) 494 if err != nil { 495 t.Fatal("failed to upload file:", err) 496 } 497 498 // Get file and check siapath 499 f, err := rt.renter.File(siaPath) 500 if err != nil { 501 t.Fatal(err) 502 } 503 if !f.SiaPath.Equals(siaPath) { 504 t.Fatalf("siapath not set as expected: got %v expected %v", f.SiaPath, fileName) 505 } 506 507 // Confirm .sia file exists on disk in the SiapathRoot directory 508 renterDir := filepath.Join(rt.dir, skymodules.RenterDir) 509 siapathRootDir := filepath.Join(renterDir, skymodules.FileSystemRoot) 510 fullPath := siaPath.SiaFileSysPath(siapathRootDir) 511 if _, err := os.Stat(fullPath); os.IsNotExist(err) { 512 t.Fatal("No .sia file found on disk") 513 } 514 }