storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/fs-v1-helpers_test.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2016, 2017 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 "bytes" 21 "io" 22 "io/ioutil" 23 "os" 24 "path" 25 "testing" 26 27 "storj.io/minio/pkg/lock" 28 ) 29 30 func TestFSRenameFile(t *testing.T) { 31 // create xlStorage test setup 32 _, path, err := newXLStorageTestSetup() 33 if err != nil { 34 t.Fatalf("Unable to create xlStorage test setup, %s", err) 35 } 36 defer os.RemoveAll(path) 37 38 if err = fsMkdir(GlobalContext, pathJoin(path, "testvolume1")); err != nil { 39 t.Fatal(err) 40 } 41 if err = fsRenameFile(GlobalContext, pathJoin(path, "testvolume1"), pathJoin(path, "testvolume2")); err != nil { 42 t.Fatal(err) 43 } 44 if err = fsRenameFile(GlobalContext, pathJoin(path, "testvolume1"), pathJoin(path, "testvolume2")); err != errFileNotFound { 45 t.Fatal(err) 46 } 47 if err = fsRenameFile(GlobalContext, pathJoin(path, "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"), pathJoin(path, "testvolume2")); err != errFileNameTooLong { 48 t.Fatal("Unexpected error", err) 49 } 50 if err = fsRenameFile(GlobalContext, pathJoin(path, "testvolume1"), pathJoin(path, "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")); err != errFileNameTooLong { 51 t.Fatal("Unexpected error", err) 52 } 53 } 54 55 func TestFSStats(t *testing.T) { 56 // create xlStorage test setup 57 _, path, err := newXLStorageTestSetup() 58 if err != nil { 59 t.Fatalf("Unable to create xlStorage test setup, %s", err) 60 } 61 defer os.RemoveAll(path) 62 63 // Setup test environment. 64 65 if err = fsMkdir(GlobalContext, ""); err != errInvalidArgument { 66 t.Fatal("Unexpected error", err) 67 } 68 69 if err = fsMkdir(GlobalContext, pathJoin(path, "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")); err != errFileNameTooLong { 70 t.Fatal("Unexpected error", err) 71 } 72 73 if err = fsMkdir(GlobalContext, pathJoin(path, "success-vol")); err != nil { 74 t.Fatalf("Unable to create volume, %s", err) 75 } 76 77 var reader = bytes.NewReader([]byte("Hello, world")) 78 if _, err = fsCreateFile(GlobalContext, pathJoin(path, "success-vol", "success-file"), reader, 0); err != nil { 79 t.Fatalf("Unable to create file, %s", err) 80 } 81 // Seek back. 82 reader.Seek(0, 0) 83 84 if err = fsMkdir(GlobalContext, pathJoin(path, "success-vol", "success-file")); err != errVolumeExists { 85 t.Fatal("Unexpected error", err) 86 } 87 88 if _, err = fsCreateFile(GlobalContext, pathJoin(path, "success-vol", "path/to/success-file"), reader, 0); err != nil { 89 t.Fatalf("Unable to create file, %s", err) 90 } 91 // Seek back. 92 reader.Seek(0, 0) 93 94 testCases := []struct { 95 srcFSPath string 96 srcVol string 97 srcPath string 98 expectedErr error 99 }{ 100 // Test case - 1. 101 // Test case with valid inputs, expected to pass. 102 { 103 srcFSPath: path, 104 srcVol: "success-vol", 105 srcPath: "success-file", 106 expectedErr: nil, 107 }, 108 // Test case - 2. 109 // Test case with valid inputs, expected to pass. 110 { 111 srcFSPath: path, 112 srcVol: "success-vol", 113 srcPath: "path/to/success-file", 114 expectedErr: nil, 115 }, 116 // Test case - 3. 117 // Test case with non-existent file. 118 { 119 srcFSPath: path, 120 srcVol: "success-vol", 121 srcPath: "nonexistent-file", 122 expectedErr: errFileNotFound, 123 }, 124 // Test case - 4. 125 // Test case with non-existent file path. 126 { 127 srcFSPath: path, 128 srcVol: "success-vol", 129 srcPath: "path/2/success-file", 130 expectedErr: errFileNotFound, 131 }, 132 // Test case - 5. 133 // Test case with path being a directory. 134 { 135 srcFSPath: path, 136 srcVol: "success-vol", 137 srcPath: "path", 138 expectedErr: errFileNotFound, 139 }, 140 // Test case - 6. 141 // Test case with src path segment > 255. 142 { 143 srcFSPath: path, 144 srcVol: "success-vol", 145 srcPath: "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", 146 expectedErr: errFileNameTooLong, 147 }, 148 // Test case - 7. 149 // Test case validate only srcVol exists. 150 { 151 srcFSPath: path, 152 srcVol: "success-vol", 153 expectedErr: nil, 154 }, 155 // Test case - 8. 156 // Test case validate only srcVol doesn't exist. 157 { 158 srcFSPath: path, 159 srcVol: "success-vol-non-existent", 160 expectedErr: errVolumeNotFound, 161 }, 162 // Test case - 9. 163 // Test case validate invalid argument. 164 { 165 expectedErr: errInvalidArgument, 166 }, 167 } 168 169 for i, testCase := range testCases { 170 if testCase.srcPath != "" { 171 if _, err := fsStatFile(GlobalContext, pathJoin(testCase.srcFSPath, testCase.srcVol, 172 testCase.srcPath)); err != testCase.expectedErr { 173 t.Fatalf("TestErasureStorage case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) 174 } 175 } else { 176 if _, err := fsStatVolume(GlobalContext, pathJoin(testCase.srcFSPath, testCase.srcVol)); err != testCase.expectedErr { 177 t.Fatalf("TestFS case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) 178 } 179 } 180 } 181 } 182 183 func TestFSCreateAndOpen(t *testing.T) { 184 // Setup test environment. 185 _, path, err := newXLStorageTestSetup() 186 if err != nil { 187 t.Fatalf("Unable to create xlStorage test setup, %s", err) 188 } 189 defer os.RemoveAll(path) 190 191 if err = fsMkdir(GlobalContext, pathJoin(path, "success-vol")); err != nil { 192 t.Fatalf("Unable to create directory, %s", err) 193 } 194 195 if _, err = fsCreateFile(GlobalContext, "", nil, 0); err != errInvalidArgument { 196 t.Fatal("Unexpected error", err) 197 } 198 199 if _, _, err = fsOpenFile(GlobalContext, "", -1); err != errInvalidArgument { 200 t.Fatal("Unexpected error", err) 201 } 202 203 var reader = bytes.NewReader([]byte("Hello, world")) 204 if _, err = fsCreateFile(GlobalContext, pathJoin(path, "success-vol", "success-file"), reader, 0); err != nil { 205 t.Fatalf("Unable to create file, %s", err) 206 } 207 // Seek back. 208 reader.Seek(0, 0) 209 210 testCases := []struct { 211 srcVol string 212 srcPath string 213 expectedErr error 214 }{ 215 // Test case - 1. 216 // Test case with segment of the volume name > 255. 217 { 218 srcVol: "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", 219 srcPath: "success-file", 220 expectedErr: errFileNameTooLong, 221 }, 222 // Test case - 2. 223 // Test case with src path segment > 255. 224 { 225 srcVol: "success-vol", 226 srcPath: "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", 227 expectedErr: errFileNameTooLong, 228 }, 229 } 230 231 for i, testCase := range testCases { 232 _, err = fsCreateFile(GlobalContext, pathJoin(path, testCase.srcVol, testCase.srcPath), reader, 0) 233 if err != testCase.expectedErr { 234 t.Errorf("Test case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) 235 } 236 _, _, err = fsOpenFile(GlobalContext, pathJoin(path, testCase.srcVol, testCase.srcPath), 0) 237 if err != testCase.expectedErr { 238 t.Errorf("Test case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) 239 } 240 } 241 242 // Attempt to open a directory. 243 if _, _, err = fsOpenFile(GlobalContext, pathJoin(path), 0); err != errIsNotRegular { 244 t.Fatal("Unexpected error", err) 245 } 246 } 247 248 func TestFSDeletes(t *testing.T) { 249 // create xlStorage test setup 250 _, path, err := newXLStorageTestSetup() 251 if err != nil { 252 t.Fatalf("Unable to create xlStorage test setup, %s", err) 253 } 254 defer os.RemoveAll(path) 255 256 // Setup test environment. 257 if err = fsMkdir(GlobalContext, pathJoin(path, "success-vol")); err != nil { 258 t.Fatalf("Unable to create directory, %s", err) 259 } 260 261 var reader = bytes.NewReader([]byte("Hello, world")) 262 if _, err = fsCreateFile(GlobalContext, pathJoin(path, "success-vol", "success-file"), reader, reader.Size()); err != nil { 263 t.Fatalf("Unable to create file, %s", err) 264 } 265 // Seek back. 266 reader.Seek(0, io.SeekStart) 267 268 // folder is not empty 269 err = fsMkdir(GlobalContext, pathJoin(path, "success-vol", "not-empty")) 270 if err != nil { 271 t.Fatal(err) 272 } 273 err = ioutil.WriteFile(pathJoin(path, "success-vol", "not-empty", "file"), []byte("data"), 0777) 274 if err != nil { 275 t.Fatal(err) 276 } 277 278 // recursive 279 if err = fsMkdir(GlobalContext, pathJoin(path, "success-vol", "parent")); err != nil { 280 t.Fatal(err) 281 } 282 if err = fsMkdir(GlobalContext, pathJoin(path, "success-vol", "parent", "dir")); err != nil { 283 t.Fatal(err) 284 } 285 286 testCases := []struct { 287 basePath string 288 srcVol string 289 srcPath string 290 expectedErr error 291 }{ 292 // valid case with existing volume and file to delete. 293 { 294 basePath: path, 295 srcVol: "success-vol", 296 srcPath: "success-file", 297 expectedErr: nil, 298 }, 299 // The file was deleted in the last case, so Delete should fail. 300 { 301 basePath: path, 302 srcVol: "success-vol", 303 srcPath: "success-file", 304 expectedErr: errFileNotFound, 305 }, 306 // Test case with segment of the volume name > 255. 307 { 308 basePath: path, 309 srcVol: "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", 310 srcPath: "success-file", 311 expectedErr: errFileNameTooLong, 312 }, 313 // Test case with src path segment > 255. 314 { 315 basePath: path, 316 srcVol: "success-vol", 317 srcPath: "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", 318 expectedErr: errFileNameTooLong, 319 }, 320 // Base path is way too long. 321 { 322 basePath: "path03333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333", 323 srcVol: "success-vol", 324 srcPath: "object", 325 expectedErr: errFileNameTooLong, 326 }, 327 // Directory is not empty. Should give nil, but won't delete. 328 { 329 basePath: path, 330 srcVol: "success-vol", 331 srcPath: "not-empty", 332 expectedErr: nil, 333 }, 334 // Should delete recursively. 335 { 336 basePath: path, 337 srcVol: "success-vol", 338 srcPath: pathJoin("parent", "dir"), 339 expectedErr: nil, 340 }, 341 } 342 343 for i, testCase := range testCases { 344 if err = fsDeleteFile(GlobalContext, testCase.basePath, pathJoin(testCase.basePath, testCase.srcVol, testCase.srcPath)); err != testCase.expectedErr { 345 t.Errorf("Test case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) 346 } 347 } 348 } 349 350 func BenchmarkFSDeleteFile(b *testing.B) { 351 // create xlStorage test setup 352 _, path, err := newXLStorageTestSetup() 353 if err != nil { 354 b.Fatalf("Unable to create xlStorage test setup, %s", err) 355 } 356 defer os.RemoveAll(path) 357 358 // Setup test environment. 359 if err = fsMkdir(GlobalContext, pathJoin(path, "benchmark")); err != nil { 360 b.Fatalf("Unable to create directory, %s", err) 361 } 362 363 benchDir := pathJoin(path, "benchmark") 364 filename := pathJoin(benchDir, "file.txt") 365 366 b.ResetTimer() 367 // We need to create and delete the file sequentially inside the benchmark. 368 for i := 0; i < b.N; i++ { 369 b.StopTimer() 370 err = ioutil.WriteFile(filename, []byte("data"), 0777) 371 if err != nil { 372 b.Fatal(err) 373 } 374 b.StartTimer() 375 376 err = fsDeleteFile(GlobalContext, benchDir, filename) 377 if err != nil { 378 b.Fatal(err) 379 } 380 } 381 } 382 383 // Tests fs removes. 384 func TestFSRemoves(t *testing.T) { 385 // create xlStorage test setup 386 _, path, err := newXLStorageTestSetup() 387 if err != nil { 388 t.Fatalf("Unable to create xlStorage test setup, %s", err) 389 } 390 defer os.RemoveAll(path) 391 392 // Setup test environment. 393 if err = fsMkdir(GlobalContext, pathJoin(path, "success-vol")); err != nil { 394 t.Fatalf("Unable to create directory, %s", err) 395 } 396 397 var reader = bytes.NewReader([]byte("Hello, world")) 398 if _, err = fsCreateFile(GlobalContext, pathJoin(path, "success-vol", "success-file"), reader, 0); err != nil { 399 t.Fatalf("Unable to create file, %s", err) 400 } 401 // Seek back. 402 reader.Seek(0, 0) 403 404 if _, err = fsCreateFile(GlobalContext, pathJoin(path, "success-vol", "success-file-new"), reader, 0); err != nil { 405 t.Fatalf("Unable to create file, %s", err) 406 } 407 // Seek back. 408 reader.Seek(0, 0) 409 410 testCases := []struct { 411 srcFSPath string 412 srcVol string 413 srcPath string 414 expectedErr error 415 }{ 416 // Test case - 1. 417 // valid case with existing volume and file to delete. 418 { 419 srcFSPath: path, 420 srcVol: "success-vol", 421 srcPath: "success-file", 422 expectedErr: nil, 423 }, 424 // Test case - 2. 425 // The file was deleted in the last case, so Delete should fail. 426 { 427 srcFSPath: path, 428 srcVol: "success-vol", 429 srcPath: "success-file", 430 expectedErr: errFileNotFound, 431 }, 432 // Test case - 3. 433 // Test case with segment of the volume name > 255. 434 { 435 srcFSPath: path, 436 srcVol: "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", 437 srcPath: "success-file", 438 expectedErr: errFileNameTooLong, 439 }, 440 // Test case - 4. 441 // Test case with src path segment > 255. 442 { 443 srcFSPath: path, 444 srcVol: "success-vol", 445 srcPath: "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", 446 expectedErr: errFileNameTooLong, 447 }, 448 // Test case - 5. 449 // Test case with src path empty. 450 { 451 srcFSPath: path, 452 srcVol: "success-vol", 453 expectedErr: errVolumeNotEmpty, 454 }, 455 // Test case - 6. 456 // Test case with src path empty. 457 { 458 srcFSPath: path, 459 srcVol: "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", 460 expectedErr: errFileNameTooLong, 461 }, 462 // Test case - 7. 463 // Test case with src path empty. 464 { 465 srcFSPath: path, 466 srcVol: "non-existent", 467 expectedErr: errVolumeNotFound, 468 }, 469 // Test case - 8. 470 // Test case with src and volume path empty. 471 { 472 expectedErr: errInvalidArgument, 473 }, 474 } 475 476 for i, testCase := range testCases { 477 if testCase.srcPath != "" { 478 if err = fsRemoveFile(GlobalContext, pathJoin(testCase.srcFSPath, testCase.srcVol, testCase.srcPath)); err != testCase.expectedErr { 479 t.Errorf("Test case %d: Expected: \"%s\", got: \"%s\"", i+1, testCase.expectedErr, err) 480 } 481 } else { 482 if err = fsRemoveDir(GlobalContext, pathJoin(testCase.srcFSPath, testCase.srcVol, testCase.srcPath)); err != testCase.expectedErr { 483 t.Error(err) 484 } 485 } 486 } 487 488 if err = fsRemoveAll(GlobalContext, pathJoin(path, "success-vol")); err != nil { 489 t.Fatal(err) 490 } 491 492 if err = fsRemoveAll(GlobalContext, ""); err != errInvalidArgument { 493 t.Fatal(err) 494 } 495 496 if err = fsRemoveAll(GlobalContext, "my-obj-del-0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); err != errFileNameTooLong { 497 t.Fatal(err) 498 } 499 } 500 501 func TestFSRemoveMeta(t *testing.T) { 502 // create xlStorage test setup 503 _, fsPath, err := newXLStorageTestSetup() 504 if err != nil { 505 t.Fatalf("Unable to create xlStorage test setup, %s", err) 506 } 507 defer os.RemoveAll(fsPath) 508 509 // Setup test environment. 510 if err = fsMkdir(GlobalContext, pathJoin(fsPath, "success-vol")); err != nil { 511 t.Fatalf("Unable to create directory, %s", err) 512 } 513 514 filePath := pathJoin(fsPath, "success-vol", "success-file") 515 516 var reader = bytes.NewReader([]byte("Hello, world")) 517 if _, err = fsCreateFile(GlobalContext, filePath, reader, 0); err != nil { 518 t.Fatalf("Unable to create file, %s", err) 519 } 520 521 rwPool := &fsIOPool{ 522 readersMap: make(map[string]*lock.RLockedFile), 523 } 524 525 if _, err := rwPool.Open(filePath); err != nil { 526 t.Fatalf("Unable to lock file %s", filePath) 527 } 528 529 defer rwPool.Close(filePath) 530 531 tmpDir, tmpErr := ioutil.TempDir(globalTestTmpDir, "minio-") 532 if tmpErr != nil { 533 t.Fatal(tmpErr) 534 } 535 536 if err := fsRemoveMeta(GlobalContext, fsPath, filePath, tmpDir); err != nil { 537 t.Fatalf("Unable to remove file, %s", err) 538 } 539 540 if _, err := os.Stat((filePath)); !osIsNotExist(err) { 541 t.Fatalf("`%s` file found though it should have been deleted.", filePath) 542 } 543 544 if _, err := os.Stat((path.Dir(filePath))); !osIsNotExist(err) { 545 t.Fatalf("`%s` parent directory found though it should have been deleted.", filePath) 546 } 547 } 548 549 func TestFSIsFile(t *testing.T) { 550 dirPath, err := ioutil.TempDir(globalTestTmpDir, "minio-") 551 if err != nil { 552 t.Fatalf("Unable to create tmp directory %s", err) 553 } 554 defer os.RemoveAll(dirPath) 555 556 filePath := pathJoin(dirPath, "tmpfile") 557 558 if err = ioutil.WriteFile(filePath, nil, 0777); err != nil { 559 t.Fatalf("Unable to create file %s", filePath) 560 } 561 562 if !fsIsFile(GlobalContext, filePath) { 563 t.Fatalf("Expected %s to be a file", filePath) 564 } 565 }