go-hep.org/x/hep@v0.38.1/xrootd/fshandler_test.go (about) 1 // Copyright ©2018 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package xrootd_test // import "go-hep.org/x/hep/xrootd" 6 7 import ( 8 "context" 9 "crypto/rand" 10 "fmt" 11 "net" 12 "os" 13 "path" 14 "reflect" 15 "sync" 16 "testing" 17 18 "go-hep.org/x/hep/xrootd" 19 "go-hep.org/x/hep/xrootd/xrdfs" 20 "go-hep.org/x/hep/xrootd/xrdproto" 21 "go-hep.org/x/hep/xrootd/xrdproto/ping" 22 ) 23 24 func getTCPAddr() (string, error) { 25 addr, err := net.ResolveTCPAddr("tcp", "localhost:0") 26 if err != nil { 27 return "", err 28 } 29 l, err := net.ListenTCP("tcp", addr) 30 if err != nil { 31 return "", err 32 } 33 defer l.Close() 34 return l.Addr().String(), nil 35 } 36 37 func createServer(errorHandler func(err error)) (srv *xrootd.Server, addr, baseDir string, err error) { 38 baseDir, err = os.MkdirTemp("", "xrd-srv-") 39 if err != nil { 40 return nil, "", "", fmt.Errorf("xrd-srv: could not create test dir: %w", err) 41 } 42 43 addr, err = getTCPAddr() 44 if err != nil { 45 return nil, "", "", fmt.Errorf("xrd-srv: could not get free port to listen: %w", err) 46 } 47 48 listener, err := net.Listen("tcp", addr) 49 if err != nil { 50 return nil, "", "", fmt.Errorf("xrd-srv: could not listen on %q: %w", addr, err) 51 } 52 53 srv = xrootd.NewServer(xrootd.NewFSHandler(baseDir), func(err error) { 54 errorHandler(fmt.Errorf("xrd-srv: an error occured: %w", err)) 55 }) 56 57 go func() { 58 if err = srv.Serve(listener); err != nil && err != xrootd.ErrServerClosed { 59 errorHandler(fmt.Errorf("xrd-srv: could not serve: %w", err)) 60 } 61 }() 62 63 return srv, addr, baseDir, nil 64 } 65 66 func createClient(addr string) (*xrootd.Client, error) { 67 return xrootd.NewClient(context.Background(), addr, "gopher") 68 } 69 70 func TestHandler_Dirlist(t *testing.T) { 71 srv, addr, baseDir, err := createServer(func(err error) { 72 t.Error(err) 73 }) 74 if err != nil { 75 t.Fatal(err) 76 } 77 defer os.RemoveAll(baseDir) 78 defer func() { 79 _ = srv.Shutdown(context.Background()) 80 }() 81 82 file := path.Join(baseDir, "file1.txt") 83 err = os.WriteFile(file, nil, 0777) 84 if err != nil { 85 t.Fatalf("could not create test file: %v", err) 86 } 87 88 fileInfo, err := os.Stat(file) 89 if err != nil { 90 t.Fatalf("could not stat test file: %v", err) 91 } 92 93 cli, err := createClient(addr) 94 if err != nil { 95 t.Fatalf("could not create client: %v", err) 96 } 97 defer cli.Close() 98 99 got, err := cli.FS().Dirlist(context.Background(), "/") 100 if err != nil { 101 t.Fatalf("could not call Dirlist: %v", err) 102 } 103 104 want := []xrdfs.EntryStat{ 105 { 106 EntryName: "file1.txt", 107 HasStatInfo: true, 108 Flags: xrdfs.StatIsWritable | xrdfs.StatIsReadable, 109 Mtime: fileInfo.ModTime().Unix(), 110 }, 111 } 112 113 if !reflect.DeepEqual(got, want) { 114 t.Fatalf("wrong Dirlist response:\ngot = %v\nwant = %v", got, want) 115 } 116 } 117 func TestHandler_Dirlist_WhenPathIsInvalid(t *testing.T) { 118 srv, addr, baseDir, err := createServer(func(err error) { 119 t.Error(err) 120 }) 121 if err != nil { 122 t.Fatal(err) 123 } 124 defer os.RemoveAll(baseDir) 125 defer func() { 126 _ = srv.Shutdown(context.Background()) 127 }() 128 129 cli, err := createClient(addr) 130 if err != nil { 131 t.Fatalf("could not create client: %v", err) 132 } 133 defer cli.Close() 134 135 _, err = cli.FS().Dirlist(context.Background(), "/path/not/exist") 136 serverError, ok := err.(xrdproto.ServerError) 137 if !ok { 138 t.Fatalf("could not cast err to ServerError: %v", err) 139 } 140 if serverError.Code != xrdproto.IOError { 141 t.Fatalf("wrong error code:\ngot = %v\nwant = %v", serverError.Code, xrdproto.IOError) 142 } 143 } 144 145 func TestHandler_Dirlist_With1000Requests(t *testing.T) { 146 srv, addr, baseDir, err := createServer(func(err error) { 147 t.Error(err) 148 }) 149 if err != nil { 150 t.Fatal(err) 151 } 152 defer os.RemoveAll(baseDir) 153 defer func() { 154 _ = srv.Shutdown(context.Background()) 155 }() 156 157 file := path.Join(baseDir, "file1.txt") 158 err = os.WriteFile(file, nil, 0777) 159 if err != nil { 160 t.Fatalf("could not create test file: %v", err) 161 } 162 163 cli, err := createClient(addr) 164 if err != nil { 165 t.Fatalf("could not create client: %v", err) 166 } 167 defer cli.Close() 168 169 var wg sync.WaitGroup 170 wg.Add(1000) 171 for range 1000 { 172 go func() { 173 defer wg.Done() 174 _, err := cli.FS().Dirlist(context.Background(), "/") 175 if err != nil { 176 t.Errorf("could not call Dirlist: %v", err) 177 } 178 }() 179 } 180 wg.Wait() 181 } 182 183 func BenchmarkHandler_Dirlist(b *testing.B) { 184 srv, addr, baseDir, err := createServer(func(err error) { 185 b.Error(err) 186 }) 187 if err != nil { 188 b.Fatal(err) 189 } 190 defer os.RemoveAll(baseDir) 191 defer func() { 192 _ = srv.Shutdown(context.Background()) 193 }() 194 195 file := path.Join(baseDir, "file1.txt") 196 err = os.WriteFile(file, nil, 0777) 197 if err != nil { 198 b.Fatalf("could not create test file: %v", err) 199 } 200 201 cli, err := createClient(addr) 202 if err != nil { 203 b.Fatalf("could not create client: %v", err) 204 } 205 206 defer cli.Close() 207 b.ResetTimer() 208 for n := 0; n < b.N; n++ { 209 _, err = cli.FS().Dirlist(context.Background(), "/") 210 if err != nil { 211 b.Fatalf("could not call Dirlist: %v", err) 212 } 213 } 214 } 215 216 func TestHandler_Open(t *testing.T) { 217 for _, tc := range []struct { 218 testName string 219 file string 220 mode xrdfs.OpenMode 221 options xrdfs.OpenOptions 222 createFile bool 223 errCode xrdproto.ServerErrorCode 224 checkStatInfo bool 225 }{ 226 { 227 testName: "Readonly | created file", 228 options: xrdfs.OpenOptionsOpenRead, 229 createFile: true, 230 file: "test1.txt", 231 }, 232 { 233 testName: "Read & write | created file", 234 options: xrdfs.OpenOptionsOpenUpdate, 235 createFile: true, 236 file: "test1.txt", 237 }, 238 { 239 testName: "Append | created file", 240 options: xrdfs.OpenOptionsOpenAppend, 241 createFile: true, 242 file: "test1.txt", 243 }, 244 { 245 testName: "Read & Write | new file", 246 options: xrdfs.OpenOptionsOpenUpdate | xrdfs.OpenOptionsNew, 247 file: "test1.txt", 248 }, 249 { 250 testName: "Read & Write | create existing file", 251 options: xrdfs.OpenOptionsOpenUpdate | xrdfs.OpenOptionsNew, 252 createFile: true, 253 errCode: xrdproto.IOError, 254 file: "test1.txt", 255 }, 256 { 257 testName: "Read & Write | recreate file", 258 options: xrdfs.OpenOptionsOpenUpdate | xrdfs.OpenOptionsDelete, 259 createFile: true, 260 file: "test1.txt", 261 }, 262 { 263 testName: "Read & Write | new file in new directory without OpenOptionsMkPath", 264 options: xrdfs.OpenOptionsOpenUpdate | xrdfs.OpenOptionsNew, 265 file: path.Join("testdir", "test1.txt"), 266 errCode: xrdproto.IOError, 267 }, 268 { 269 testName: "Read & Write | new file in new directory with OpenOptionsMkPath", 270 options: xrdfs.OpenOptionsOpenUpdate | xrdfs.OpenOptionsNew | xrdfs.OpenOptionsMkPath, 271 file: path.Join("testdir", "test1.txt"), 272 mode: xrdfs.OpenModeOwnerRead | xrdfs.OpenModeOwnerWrite | xrdfs.OpenModeOwnerExecute, 273 }, 274 { 275 testName: "Read & Write | created file | with stat info", 276 options: xrdfs.OpenOptionsOpenUpdate | xrdfs.OpenOptionsReturnStatus, 277 file: "test1.txt", 278 createFile: true, 279 checkStatInfo: true, 280 }, 281 } { 282 t.Run(tc.testName, func(t *testing.T) { 283 srv, addr, baseDir, err := createServer(func(err error) { 284 t.Error(err) 285 }) 286 if err != nil { 287 t.Fatal(err) 288 } 289 defer os.RemoveAll(baseDir) 290 defer func() { 291 _ = srv.Shutdown(context.Background()) 292 }() 293 294 if tc.createFile { 295 err = os.WriteFile(path.Join(baseDir, tc.file), nil, 0777) 296 if err != nil { 297 t.Fatalf("could not create test file: %v", err) 298 } 299 } 300 301 cli, err := createClient(addr) 302 if err != nil { 303 t.Fatalf("could not create client: %v", err) 304 } 305 defer cli.Close() 306 307 got, err := cli.FS().Open(context.Background(), tc.file, tc.mode, tc.options) 308 if err != nil { 309 if serverError, ok := err.(xrdproto.ServerError); ok { 310 if serverError.Code != tc.errCode { 311 t.Fatalf("wrong error code:\ngot = %v\nwant = %v\nerror message = %q", serverError.Code, tc.errCode, serverError.Message) 312 } 313 return 314 } 315 t.Fatalf("could not call Open: %v", err) 316 } 317 if err == nil && tc.errCode != 0 { 318 t.Fatalf("unexpected successfull call\nwant error code = %v", tc.errCode) 319 } 320 321 if tc.checkStatInfo { 322 st, err := os.Stat(path.Join(baseDir, tc.file)) 323 if err != nil { 324 t.Fatalf("could not read stat info: %v", err) 325 } 326 want := xrdfs.EntryStatFrom(st) 327 want.EntryName = "" 328 if !reflect.DeepEqual(*got.Info(), want) { 329 t.Fatalf("wrong stat:\ngot = %v\nwant = %v", *got.Info(), want) 330 } 331 } 332 333 err = got.Close(context.Background()) 334 if err != nil { 335 t.Fatalf("could not call Close: %v", err) 336 } 337 }) 338 } 339 } 340 341 func TestHandler_Read(t *testing.T) { 342 bigData := make([]byte, 10*1024) 343 _, err := rand.Read(bigData) 344 if err != nil { 345 t.Fatalf("could not prepare test data: %v", err) 346 } 347 348 for _, tc := range []struct { 349 testName string 350 data []byte 351 want []byte 352 offset int64 353 length int 354 }{ 355 { 356 testName: "Without offset", 357 data: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 358 length: 6, 359 want: []byte{1, 2, 3, 4, 5, 6}, 360 }, 361 { 362 testName: "With offset", 363 data: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 364 length: 6, 365 offset: 1, 366 want: []byte{2, 3, 4, 5, 6, 7}, 367 }, 368 { 369 testName: "With offset with EOF", 370 data: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 371 length: 20, 372 offset: 1, 373 want: []byte{2, 3, 4, 5, 6, 7, 8}, 374 }, 375 { 376 testName: "With offset larger than file size", 377 data: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 378 length: 20, 379 offset: 40, 380 want: []byte{}, 381 }, 382 { 383 testName: "With big length", 384 data: bigData, 385 length: len(bigData), 386 offset: 40, 387 want: bigData[40:], 388 }, 389 } { 390 t.Run(tc.testName, func(t *testing.T) { 391 srv, addr, baseDir, err := createServer(func(err error) { 392 t.Error(err) 393 }) 394 if err != nil { 395 t.Fatal(err) 396 } 397 defer os.RemoveAll(baseDir) 398 defer func() { 399 _ = srv.Shutdown(context.Background()) 400 }() 401 402 file := path.Join(baseDir, "file1.txt") 403 404 err = os.WriteFile(file, tc.data, 0777) 405 if err != nil { 406 t.Fatalf("could not create test file: %v", err) 407 } 408 409 cli, err := createClient(addr) 410 if err != nil { 411 t.Fatalf("could not create client: %v", err) 412 } 413 defer cli.Close() 414 415 gotFile, err := cli.FS().Open(context.Background(), "file1.txt", xrdfs.OpenModeOwnerRead, xrdfs.OpenOptionsOpenRead) 416 if err != nil { 417 t.Fatalf("could not call Open: %v", err) 418 } 419 defer gotFile.Close(context.Background()) 420 421 got := make([]byte, tc.length) 422 _, err = gotFile.ReadAt(got, tc.offset) 423 424 if err != nil { 425 t.Fatalf("could not call ReadAt: %v", err) 426 } 427 428 if !reflect.DeepEqual(got[:len(tc.want)], tc.want) { 429 t.Fatalf("wrong data:\ngot = %v\nwant = %v", got[:len(tc.want)], tc.want) 430 } 431 }) 432 } 433 } 434 435 func TestHandler_Write(t *testing.T) { 436 bigData := make([]byte, 10*1024) 437 _, err := rand.Read(bigData) 438 if err != nil { 439 t.Fatalf("could not prepare test data: %v", err) 440 } 441 442 for _, tc := range []struct { 443 testName string 444 initialData []byte 445 data []byte 446 want []byte 447 n int 448 offset int64 449 }{ 450 { 451 testName: "Without offset", 452 data: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 453 want: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 454 n: 8, 455 }, 456 { 457 testName: "Without offset, with partial rewrite", 458 initialData: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 459 data: []byte{9, 8, 7, 6, 0}, 460 want: []byte{9, 8, 7, 6, 0, 6, 7, 8}, 461 n: 5, 462 }, 463 { 464 testName: "With offset, with partial rewrite", 465 initialData: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 466 data: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 467 offset: 1, 468 want: []byte{1, 1, 2, 3, 4, 5, 6, 7, 8}, 469 n: 8, 470 }, 471 { 472 testName: "With offset larger than file size", 473 data: []byte{1, 2, 3, 4, 5, 6, 7, 8}, 474 offset: 2, 475 want: []byte{0, 0, 1, 2, 3, 4, 5, 6, 7, 8}, 476 n: 8, 477 }, 478 { 479 testName: "With big length", 480 data: bigData, 481 offset: 0, 482 want: bigData, 483 n: len(bigData), 484 }, 485 } { 486 t.Run(tc.testName, func(t *testing.T) { 487 srv, addr, baseDir, err := createServer(func(err error) { 488 t.Error(err) 489 }) 490 if err != nil { 491 t.Fatal(err) 492 } 493 defer os.RemoveAll(baseDir) 494 defer func() { 495 _ = srv.Shutdown(context.Background()) 496 }() 497 498 file := path.Join(baseDir, "file1.txt") 499 500 err = os.WriteFile(file, tc.initialData, 0777) 501 if err != nil { 502 t.Fatalf("could not create test file: %v", err) 503 } 504 505 cli, err := createClient(addr) 506 if err != nil { 507 t.Fatalf("could not create client: %v", err) 508 } 509 defer cli.Close() 510 511 gotFile, err := cli.FS().Open(context.Background(), "file1.txt", xrdfs.OpenModeOwnerWrite, xrdfs.OpenOptionsOpenUpdate) 512 if err != nil { 513 t.Fatalf("could not call Open: %v", err) 514 } 515 defer gotFile.Close(context.Background()) 516 517 n, err := gotFile.WriteAt(tc.data, tc.offset) 518 if err != nil { 519 t.Fatalf("could not call WriteAt: %v", err) 520 } 521 522 if n != tc.n { 523 t.Fatalf("wrong length:\ngot = %v\nwant = %v", n, tc.n) 524 } 525 526 if err := gotFile.Sync(context.Background()); err != nil { 527 t.Fatalf("could not call Sync: %v", err) 528 } 529 530 got, err := os.ReadFile(file) 531 if err != nil { 532 t.Fatalf("could not read written data: %v", err) 533 } 534 535 if !reflect.DeepEqual(got, tc.want) { 536 t.Fatalf("wrong data:\ngot = %v\nwant = %v", got, tc.want) 537 } 538 }) 539 } 540 } 541 542 func TestHandler_Stat(t *testing.T) { 543 for _, tc := range []struct { 544 testName string 545 isFile bool 546 withPath bool 547 }{ 548 { 549 testName: "Stat of file by file handle", 550 isFile: true, 551 withPath: false, 552 }, 553 { 554 testName: "Stat of file by path", 555 isFile: true, 556 withPath: true, 557 }, 558 { 559 testName: "Stat of directory by path", 560 isFile: false, 561 withPath: true, 562 }, 563 } { 564 t.Run(tc.testName, func(t *testing.T) { 565 srv, addr, baseDir, err := createServer(func(err error) { 566 t.Error(err) 567 }) 568 if err != nil { 569 t.Fatal(err) 570 } 571 defer os.RemoveAll(baseDir) 572 defer func() { 573 _ = srv.Shutdown(context.Background()) 574 }() 575 576 var entry string 577 if tc.isFile { 578 entry = "file1.txt" 579 err := os.WriteFile(path.Join(baseDir, entry), []byte{1, 2, 3, 4, 5}, 0777) 580 if err != nil { 581 t.Fatalf("could not create test file: %v", err) 582 } 583 } else { 584 entry = "dir1" 585 err := os.MkdirAll(path.Join(baseDir, entry), 0777) 586 if err != nil { 587 t.Fatalf("could not create test directory: %v", err) 588 } 589 } 590 591 stat, err := os.Stat(path.Join(baseDir, entry)) 592 if err != nil { 593 t.Fatalf("could not read stat info: %v", err) 594 } 595 596 want := xrdfs.EntryStatFrom(stat) 597 want.EntryName = "" 598 599 cli, err := createClient(addr) 600 if err != nil { 601 t.Fatalf("could not create client: %v", err) 602 } 603 defer cli.Close() 604 605 var got xrdfs.EntryStat 606 if tc.withPath { 607 got, err = cli.FS().Stat(context.Background(), entry) 608 if err != nil { 609 t.Fatalf("could not call Stat: %v", err) 610 } 611 } else { 612 file, err := cli.FS().Open(context.Background(), entry, xrdfs.OpenModeOwnerRead, xrdfs.OpenOptionsOpenRead) 613 if err != nil { 614 t.Fatalf("could not call Open: %v", err) 615 } 616 got, err = file.Stat(context.Background()) 617 if err != nil { 618 t.Fatalf("could not call Stat: %v", err) 619 } 620 if err := file.Close(context.Background()); err != nil { 621 t.Fatalf("could not call Close: %v", err) 622 } 623 } 624 625 if !reflect.DeepEqual(got, want) { 626 t.Fatalf("wrong stat:\ngot = %v\nwant = %v", got, want) 627 } 628 }) 629 } 630 } 631 632 func TestHandler_Truncate(t *testing.T) { 633 for _, tc := range []struct { 634 testName string 635 data []byte 636 want []byte 637 size int64 638 withPath bool 639 }{ 640 { 641 testName: "Truncate file by file handle", 642 data: []byte{1, 2, 3, 4, 5, 6}, 643 want: []byte{1, 2, 3}, 644 size: 3, 645 withPath: false, 646 }, 647 { 648 testName: "Truncate file by path", 649 data: []byte{1, 2, 3, 4, 5, 6}, 650 want: []byte{1, 2, 3}, 651 size: 3, 652 withPath: true, 653 }, 654 { 655 testName: "Extend file by file handle", 656 data: []byte{1, 2, 3, 4, 5, 6}, 657 want: []byte{1, 2, 3, 4, 5, 6, 0, 0}, 658 size: 8, 659 withPath: false, 660 }, 661 { 662 testName: "Extend file by path", 663 data: []byte{1, 2, 3, 4, 5, 6}, 664 want: []byte{1, 2, 3, 4, 5, 6, 0, 0}, 665 size: 8, 666 withPath: true, 667 }, 668 } { 669 t.Run(tc.testName, func(t *testing.T) { 670 srv, addr, baseDir, err := createServer(func(err error) { 671 t.Error(err) 672 }) 673 if err != nil { 674 t.Fatal(err) 675 } 676 defer os.RemoveAll(baseDir) 677 defer func() { 678 _ = srv.Shutdown(context.Background()) 679 }() 680 681 entry := "file1.txt" 682 err = os.WriteFile(path.Join(baseDir, entry), tc.data, 0777) 683 if err != nil { 684 t.Fatalf("could not create test file: %v", err) 685 } 686 687 cli, err := createClient(addr) 688 if err != nil { 689 t.Fatalf("could not create client: %v", err) 690 } 691 defer cli.Close() 692 693 if tc.withPath { 694 err = cli.FS().Truncate(context.Background(), entry, tc.size) 695 if err != nil { 696 t.Fatalf("could not call Truncate: %v", err) 697 } 698 } else { 699 file, err := cli.FS().Open(context.Background(), entry, xrdfs.OpenModeOwnerWrite, xrdfs.OpenOptionsOpenUpdate) 700 if err != nil { 701 t.Fatalf("could not call Open: %v", err) 702 } 703 if err = file.Truncate(context.Background(), tc.size); err != nil { 704 t.Fatalf("could not call Truncate: %v", err) 705 } 706 if err := file.Sync(context.Background()); err != nil { 707 t.Fatalf("could not call Sync: %v", err) 708 } 709 if err := file.Close(context.Background()); err != nil { 710 t.Fatalf("could not call Close: %v", err) 711 } 712 } 713 714 s, err := os.Stat(path.Join(baseDir, entry)) 715 if err != nil { 716 t.Fatalf("could not read stat info: %v", err) 717 } 718 719 if !reflect.DeepEqual(s.Size(), tc.size) { 720 t.Fatalf("wrong size:\ngot = %v\nwant = %v", s.Size(), tc.size) 721 } 722 }) 723 } 724 } 725 726 func TestHandler_Rename(t *testing.T) { 727 for _, tc := range []struct { 728 testName string 729 oldPathExist bool 730 newPathExist bool 731 }{ 732 { 733 testName: "Old path exists, new path doesn't exist", 734 oldPathExist: true, 735 newPathExist: false, 736 }, 737 { 738 testName: "Old path exists, new path exists", 739 oldPathExist: true, 740 newPathExist: true, 741 }, 742 { 743 testName: "Old path doesn't exist, new path doesn't exist", 744 oldPathExist: true, 745 newPathExist: false, 746 }, 747 } { 748 t.Run(tc.testName, func(t *testing.T) { 749 srv, addr, baseDir, err := createServer(func(err error) { 750 t.Error(err) 751 }) 752 if err != nil { 753 t.Fatal(err) 754 } 755 defer os.RemoveAll(baseDir) 756 defer func() { 757 _ = srv.Shutdown(context.Background()) 758 }() 759 760 oldName := "old.txt" 761 newName := "new.txt" 762 763 if tc.oldPathExist { 764 if err := os.WriteFile(path.Join(baseDir, oldName), nil, 0777); err != nil { 765 t.Fatalf("could not create test file: %v", err) 766 } 767 } 768 if tc.newPathExist { 769 if err := os.WriteFile(path.Join(baseDir, newName), nil, 0777); err != nil { 770 t.Fatalf("could not create test file: %v", err) 771 } 772 } 773 774 cli, err := createClient(addr) 775 if err != nil { 776 t.Fatalf("could not create client: %v", err) 777 } 778 defer cli.Close() 779 780 if err := cli.FS().Rename(context.Background(), oldName, newName); err != nil { 781 t.Fatalf("could not call Rename: %v", err) 782 } 783 784 if _, err := os.Stat(path.Join(baseDir, oldName)); !os.IsNotExist(err) { 785 t.Fatalf("old file was not removed after rename") 786 } 787 if _, err := os.Stat(path.Join(baseDir, newName)); os.IsNotExist(err) { 788 t.Fatalf("new file was not created after rename") 789 } 790 }) 791 } 792 } 793 794 func TestHandler_Mkdir(t *testing.T) { 795 for _, tc := range []struct { 796 testName string 797 path string 798 createFile bool 799 mkdirAll bool 800 errCode xrdproto.ServerErrorCode 801 }{ 802 { 803 testName: "existing dir", 804 createFile: true, 805 path: "testdir", 806 errCode: xrdproto.IOError, 807 }, 808 { 809 testName: "new dir", 810 createFile: false, 811 path: "testdir", 812 }, 813 { 814 testName: "nested dir", 815 createFile: false, 816 path: "nested/testdir", 817 errCode: xrdproto.IOError, 818 }, 819 { 820 testName: "nested dir and MkdirAll", 821 createFile: false, 822 path: "nested/testdir", 823 mkdirAll: true, 824 }, 825 } { 826 t.Run(tc.testName, func(t *testing.T) { 827 srv, addr, baseDir, err := createServer(func(err error) { 828 t.Error(err) 829 }) 830 if err != nil { 831 t.Fatal(err) 832 } 833 defer os.RemoveAll(baseDir) 834 defer func() { 835 _ = srv.Shutdown(context.Background()) 836 }() 837 838 if tc.createFile { 839 err = os.MkdirAll(path.Join(baseDir, tc.path), os.FileMode(0777)) 840 if err != nil { 841 t.Fatalf("could not create test dir: %v", err) 842 } 843 } 844 845 cli, err := createClient(addr) 846 if err != nil { 847 t.Fatalf("could not create client: %v", err) 848 } 849 defer cli.Close() 850 851 if tc.mkdirAll { 852 err = cli.FS().MkdirAll(context.Background(), tc.path, xrdfs.OpenModeOwnerRead|xrdfs.OpenModeOwnerWrite|xrdfs.OpenModeOwnerExecute) 853 } else { 854 err = cli.FS().Mkdir(context.Background(), tc.path, xrdfs.OpenModeOwnerRead|xrdfs.OpenModeOwnerWrite|xrdfs.OpenModeOwnerExecute) 855 } 856 if err != nil { 857 if serverError, ok := err.(xrdproto.ServerError); ok { 858 if serverError.Code != tc.errCode { 859 t.Fatalf("wrong error code:\ngot = %v\nwant = %v\nerror message = %q", serverError.Code, tc.errCode, serverError.Message) 860 } 861 return 862 } 863 t.Fatalf("could not call Mkdir: %v", err) 864 } 865 if err == nil && tc.errCode != 0 { 866 t.Fatalf("unexpected successfull call\nwant error code = %v", tc.errCode) 867 } 868 }) 869 } 870 } 871 872 func TestHandler_Remove(t *testing.T) { 873 for _, tc := range []struct { 874 testName string 875 path string 876 createFile bool 877 errCode xrdproto.ServerErrorCode 878 }{ 879 { 880 testName: "existing file", 881 createFile: true, 882 path: "testfile", 883 }, 884 { 885 testName: "non-existing file", 886 createFile: false, 887 path: "testfile", 888 errCode: xrdproto.IOError, 889 }, 890 } { 891 t.Run(tc.testName, func(t *testing.T) { 892 srv, addr, baseDir, err := createServer(func(err error) { 893 t.Error(err) 894 }) 895 if err != nil { 896 t.Fatal(err) 897 } 898 defer os.RemoveAll(baseDir) 899 defer func() { 900 _ = srv.Shutdown(context.Background()) 901 }() 902 903 if tc.createFile { 904 f, err := os.Create(path.Join(baseDir, tc.path)) 905 if err != nil { 906 t.Fatalf("could not create test file: %v", err) 907 } 908 err = f.Close() 909 if err != nil { 910 t.Fatalf("could not close test file: %v", err) 911 } 912 } 913 914 cli, err := createClient(addr) 915 if err != nil { 916 t.Fatalf("could not create client: %v", err) 917 } 918 defer cli.Close() 919 920 err = cli.FS().RemoveFile(context.Background(), tc.path) 921 if err != nil { 922 if serverError, ok := err.(xrdproto.ServerError); ok { 923 if serverError.Code != tc.errCode { 924 t.Fatalf("wrong error code:\ngot = %v\nwant = %v\nerror message = %q", serverError.Code, tc.errCode, serverError.Message) 925 } 926 return 927 } 928 t.Fatalf("could not call RemoveFile: %v", err) 929 } 930 if err == nil && tc.errCode != 0 { 931 t.Fatalf("unexpected successfull call\nwant error code = %v", tc.errCode) 932 } 933 }) 934 } 935 } 936 937 func TestHandler_RemoveDir(t *testing.T) { 938 for _, tc := range []struct { 939 testName string 940 path string 941 createFile bool 942 createDir bool 943 errCode xrdproto.ServerErrorCode 944 }{ 945 { 946 testName: "empty existing dir", 947 createFile: false, 948 createDir: true, 949 path: "testdir", 950 }, 951 { 952 testName: "non-existing dir", 953 createFile: false, 954 createDir: false, 955 path: "testdir", 956 errCode: xrdproto.IOError, 957 }, 958 { 959 testName: "non-empty existing dir", 960 createFile: true, 961 createDir: true, 962 path: "testdir", 963 errCode: xrdproto.IOError, 964 }, 965 } { 966 t.Run(tc.testName, func(t *testing.T) { 967 srv, addr, baseDir, err := createServer(func(err error) { 968 t.Error(err) 969 }) 970 if err != nil { 971 t.Fatal(err) 972 } 973 defer os.RemoveAll(baseDir) 974 defer func() { 975 _ = srv.Shutdown(context.Background()) 976 }() 977 978 dirPath := path.Join(baseDir, tc.path) 979 if tc.createDir { 980 err := os.MkdirAll(dirPath, os.FileMode(0777)) 981 if err != nil { 982 t.Fatalf("could not create test dir: %v", err) 983 } 984 } 985 986 if tc.createFile { 987 f, err := os.Create(path.Join(dirPath, "file.txt")) 988 if err != nil { 989 t.Fatalf("could not create test file: %v", err) 990 } 991 err = f.Close() 992 if err != nil { 993 t.Fatalf("could not close test file: %v", err) 994 } 995 } 996 997 cli, err := createClient(addr) 998 if err != nil { 999 t.Fatalf("could not create client: %v", err) 1000 } 1001 defer cli.Close() 1002 1003 err = cli.FS().RemoveDir(context.Background(), tc.path) 1004 if err != nil { 1005 if serverError, ok := err.(xrdproto.ServerError); ok { 1006 if serverError.Code != tc.errCode { 1007 t.Fatalf("wrong error code:\ngot = %v\nwant = %v\nerror message = %q", serverError.Code, tc.errCode, serverError.Message) 1008 } 1009 return 1010 } 1011 t.Fatalf("could not call RemoveDir: %v", err) 1012 } 1013 if err == nil && tc.errCode != 0 { 1014 t.Fatalf("unexpected successfull call\nwant error code = %v", tc.errCode) 1015 } 1016 }) 1017 } 1018 } 1019 1020 func TestHandler_Ping(t *testing.T) { 1021 srv, addr, baseDir, err := createServer(func(err error) { 1022 t.Error(err) 1023 }) 1024 if err != nil { 1025 t.Fatal(err) 1026 } 1027 defer os.RemoveAll(baseDir) 1028 defer func() { 1029 _ = srv.Shutdown(context.Background()) 1030 }() 1031 1032 cli, err := createClient(addr) 1033 if err != nil { 1034 t.Fatalf("could not create client: %v", err) 1035 } 1036 defer cli.Close() 1037 1038 _, err = cli.Send(context.Background(), nil, &ping.Request{}) 1039 if err != nil { 1040 t.Fatalf("could not call Ping: %v", err) 1041 } 1042 }