github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/vfs/read_write_test.go (about) 1 package vfs 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "io" 8 "os" 9 "testing" 10 "time" 11 12 "github.com/rclone/rclone/fs" 13 "github.com/rclone/rclone/fs/operations" 14 "github.com/rclone/rclone/fstest" 15 "github.com/rclone/rclone/vfs/vfscommon" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/require" 18 ) 19 20 // Check interfaces 21 var ( 22 _ io.Reader = (*RWFileHandle)(nil) 23 _ io.ReaderAt = (*RWFileHandle)(nil) 24 _ io.Writer = (*RWFileHandle)(nil) 25 _ io.WriterAt = (*RWFileHandle)(nil) 26 _ io.Seeker = (*RWFileHandle)(nil) 27 _ io.Closer = (*RWFileHandle)(nil) 28 _ Handle = (*RWFileHandle)(nil) 29 ) 30 31 // Create a file and open it with the flags passed in 32 func rwHandleCreateFlags(t *testing.T, create bool, filename string, flags int) (r *fstest.Run, vfs *VFS, fh *RWFileHandle) { 33 opt := vfscommon.DefaultOpt 34 opt.CacheMode = vfscommon.CacheModeFull 35 opt.WriteBack = writeBackDelay 36 r, vfs = newTestVFSOpt(t, &opt) 37 38 if create { 39 file1 := r.WriteObject(context.Background(), filename, "0123456789abcdef", t1) 40 r.CheckRemoteItems(t, file1) 41 } 42 43 h, err := vfs.OpenFile(filename, flags, 0777) 44 require.NoError(t, err) 45 fh, ok := h.(*RWFileHandle) 46 require.True(t, ok) 47 48 return r, vfs, fh 49 } 50 51 // Open a file for read 52 func rwHandleCreateReadOnly(t *testing.T) (r *fstest.Run, vfs *VFS, fh *RWFileHandle) { 53 return rwHandleCreateFlags(t, true, "dir/file1", os.O_RDONLY) 54 } 55 56 // Open a file for write 57 func rwHandleCreateWriteOnly(t *testing.T) (r *fstest.Run, vfs *VFS, fh *RWFileHandle) { 58 return rwHandleCreateFlags(t, false, "file1", os.O_WRONLY|os.O_CREATE) 59 } 60 61 // read data from the string 62 func rwReadString(t *testing.T, fh *RWFileHandle, n int) string { 63 buf := make([]byte, n) 64 n, err := fh.Read(buf) 65 if err != io.EOF { 66 assert.NoError(t, err) 67 } 68 return string(buf[:n]) 69 } 70 71 func TestRWFileHandleMethodsRead(t *testing.T) { 72 _, _, fh := rwHandleCreateReadOnly(t) 73 74 // String 75 assert.Equal(t, "dir/file1 (rw)", fh.String()) 76 assert.Equal(t, "<nil *RWFileHandle>", (*RWFileHandle)(nil).String()) 77 assert.Equal(t, "<nil *RWFileHandle.file>", new(RWFileHandle).String()) 78 79 // Node 80 node := fh.Node() 81 assert.Equal(t, "file1", node.Name()) 82 83 // Size 84 assert.Equal(t, int64(16), fh.Size()) 85 86 // Read 1 87 assert.Equal(t, "0", rwReadString(t, fh, 1)) 88 89 // Read remainder 90 assert.Equal(t, "123456789abcdef", rwReadString(t, fh, 256)) 91 92 // Read EOF 93 buf := make([]byte, 16) 94 _, err := fh.Read(buf) 95 assert.Equal(t, io.EOF, err) 96 97 // Sync 98 err = fh.Sync() 99 assert.NoError(t, err) 100 101 // Stat 102 var fi os.FileInfo 103 fi, err = fh.Stat() 104 assert.NoError(t, err) 105 assert.Equal(t, int64(16), fi.Size()) 106 assert.Equal(t, "file1", fi.Name()) 107 108 // Close 109 assert.False(t, fh.closed) 110 assert.Equal(t, nil, fh.Close()) 111 assert.True(t, fh.closed) 112 113 // Close again 114 assert.Equal(t, ECLOSED, fh.Close()) 115 } 116 117 func TestRWFileHandleSeek(t *testing.T) { 118 _, _, fh := rwHandleCreateReadOnly(t) 119 120 assert.Equal(t, fh.opened, false) 121 122 // Check null seeks don't open the file 123 n, err := fh.Seek(0, io.SeekStart) 124 assert.NoError(t, err) 125 assert.Equal(t, int64(0), n) 126 assert.Equal(t, fh.opened, false) 127 n, err = fh.Seek(0, io.SeekCurrent) 128 assert.NoError(t, err) 129 assert.Equal(t, int64(0), n) 130 assert.Equal(t, fh.opened, false) 131 132 assert.Equal(t, "0", rwReadString(t, fh, 1)) 133 134 // 0 means relative to the origin of the file, 135 n, err = fh.Seek(5, io.SeekStart) 136 assert.NoError(t, err) 137 assert.Equal(t, int64(5), n) 138 assert.Equal(t, "5", rwReadString(t, fh, 1)) 139 140 // 1 means relative to the current offset 141 n, err = fh.Seek(-3, io.SeekCurrent) 142 assert.NoError(t, err) 143 assert.Equal(t, int64(3), n) 144 assert.Equal(t, "3", rwReadString(t, fh, 1)) 145 146 // 2 means relative to the end. 147 n, err = fh.Seek(-3, io.SeekEnd) 148 assert.NoError(t, err) 149 assert.Equal(t, int64(13), n) 150 assert.Equal(t, "d", rwReadString(t, fh, 1)) 151 152 // Seek off the end 153 _, err = fh.Seek(100, io.SeekStart) 154 assert.NoError(t, err) 155 156 // Get the error on read 157 buf := make([]byte, 16) 158 l, err := fh.Read(buf) 159 assert.Equal(t, io.EOF, err) 160 assert.Equal(t, 0, l) 161 162 // Close 163 assert.Equal(t, nil, fh.Close()) 164 } 165 166 func TestRWFileHandleReadAt(t *testing.T) { 167 _, _, fh := rwHandleCreateReadOnly(t) 168 169 // read from start 170 buf := make([]byte, 1) 171 n, err := fh.ReadAt(buf, 0) 172 require.NoError(t, err) 173 assert.Equal(t, 1, n) 174 assert.Equal(t, "0", string(buf[:n])) 175 176 // seek forwards 177 n, err = fh.ReadAt(buf, 5) 178 require.NoError(t, err) 179 assert.Equal(t, 1, n) 180 assert.Equal(t, "5", string(buf[:n])) 181 182 // seek backwards 183 n, err = fh.ReadAt(buf, 1) 184 require.NoError(t, err) 185 assert.Equal(t, 1, n) 186 assert.Equal(t, "1", string(buf[:n])) 187 188 // read exactly to the end 189 buf = make([]byte, 6) 190 n, err = fh.ReadAt(buf, 10) 191 require.NoError(t, err) 192 assert.Equal(t, 6, n) 193 assert.Equal(t, "abcdef", string(buf[:n])) 194 195 // read off the end 196 buf = make([]byte, 256) 197 n, err = fh.ReadAt(buf, 10) 198 assert.Equal(t, io.EOF, err) 199 assert.Equal(t, 6, n) 200 assert.Equal(t, "abcdef", string(buf[:n])) 201 202 // read starting off the end 203 n, err = fh.ReadAt(buf, 100) 204 assert.Equal(t, io.EOF, err) 205 assert.Equal(t, 0, n) 206 207 // Properly close the file 208 assert.NoError(t, fh.Close()) 209 210 // check reading on closed file 211 _, err = fh.ReadAt(buf, 100) 212 assert.Equal(t, ECLOSED, err) 213 } 214 215 func TestRWFileHandleFlushRead(t *testing.T) { 216 _, _, fh := rwHandleCreateReadOnly(t) 217 218 // Check Flush does nothing if read not called 219 err := fh.Flush() 220 assert.NoError(t, err) 221 assert.False(t, fh.closed) 222 223 // Read data 224 buf := make([]byte, 256) 225 n, err := fh.Read(buf) 226 assert.True(t, err == io.EOF || err == nil) 227 assert.Equal(t, 16, n) 228 229 // Check Flush does nothing if read called 230 err = fh.Flush() 231 assert.NoError(t, err) 232 assert.False(t, fh.closed) 233 234 // Check flush does nothing if called again 235 err = fh.Flush() 236 assert.NoError(t, err) 237 assert.False(t, fh.closed) 238 239 // Properly close the file 240 assert.NoError(t, fh.Close()) 241 } 242 243 func TestRWFileHandleReleaseRead(t *testing.T) { 244 _, _, fh := rwHandleCreateReadOnly(t) 245 246 // Read data 247 buf := make([]byte, 256) 248 n, err := fh.Read(buf) 249 assert.True(t, err == io.EOF || err == nil) 250 assert.Equal(t, 16, n) 251 252 // Check Release closes file 253 err = fh.Release() 254 assert.NoError(t, err) 255 assert.True(t, fh.closed) 256 257 // Check Release does nothing if called again 258 err = fh.Release() 259 assert.NoError(t, err) 260 assert.True(t, fh.closed) 261 } 262 263 /// ------------------------------------------------------------ 264 265 func TestRWFileHandleMethodsWrite(t *testing.T) { 266 r, vfs, fh := rwHandleCreateWriteOnly(t) 267 268 // String 269 assert.Equal(t, "file1 (rw)", fh.String()) 270 assert.Equal(t, "<nil *RWFileHandle>", (*RWFileHandle)(nil).String()) 271 assert.Equal(t, "<nil *RWFileHandle.file>", new(RWFileHandle).String()) 272 273 // Node 274 node := fh.Node() 275 assert.Equal(t, "file1", node.Name()) 276 277 offset := func() int64 { 278 n, err := fh.Seek(0, io.SeekCurrent) 279 require.NoError(t, err) 280 return n 281 } 282 283 // Offset #1 284 assert.Equal(t, int64(0), offset()) 285 assert.Equal(t, int64(0), node.Size()) 286 287 // Size #1 288 assert.Equal(t, int64(0), fh.Size()) 289 290 // Write 291 n, err := fh.Write([]byte("hello")) 292 assert.NoError(t, err) 293 assert.Equal(t, 5, n) 294 295 // Offset #2 296 assert.Equal(t, int64(5), offset()) 297 assert.Equal(t, int64(5), node.Size()) 298 299 // Size #2 300 assert.Equal(t, int64(5), fh.Size()) 301 302 // WriteString 303 n, err = fh.WriteString(" world!") 304 assert.NoError(t, err) 305 assert.Equal(t, 7, n) 306 307 // Sync 308 err = fh.Sync() 309 assert.NoError(t, err) 310 311 // Stat 312 var fi os.FileInfo 313 fi, err = fh.Stat() 314 assert.NoError(t, err) 315 assert.Equal(t, int64(12), fi.Size()) 316 assert.Equal(t, "file1", fi.Name()) 317 318 // Truncate 319 err = fh.Truncate(11) 320 assert.NoError(t, err) 321 322 // Close 323 assert.NoError(t, fh.Close()) 324 325 // Check double close 326 err = fh.Close() 327 assert.Equal(t, ECLOSED, err) 328 329 // check vfs 330 root, err := vfs.Root() 331 require.NoError(t, err) 332 checkListing(t, root, []string{"file1,11,false"}) 333 334 // check the underlying r.Fremote but not the modtime 335 file1 := fstest.NewItem("file1", "hello world", t1) 336 vfs.WaitForWriters(waitForWritersDelay) 337 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{}, fs.ModTimeNotSupported) 338 } 339 340 func TestRWFileHandleWriteAt(t *testing.T) { 341 r, vfs, fh := rwHandleCreateWriteOnly(t) 342 343 offset := func() int64 { 344 n, err := fh.Seek(0, io.SeekCurrent) 345 require.NoError(t, err) 346 return n 347 } 348 349 // Name 350 assert.Equal(t, "file1", fh.Name()) 351 352 // Preconditions 353 assert.Equal(t, int64(0), offset()) 354 assert.True(t, fh.opened) 355 assert.False(t, fh.writeCalled) 356 357 // Write the data 358 n, err := fh.WriteAt([]byte("hello**"), 0) 359 assert.NoError(t, err) 360 assert.Equal(t, 7, n) 361 362 // After write 363 assert.Equal(t, int64(0), offset()) 364 assert.True(t, fh.writeCalled) 365 366 // Write more data 367 n, err = fh.WriteAt([]byte(" world"), 5) 368 assert.NoError(t, err) 369 assert.Equal(t, 6, n) 370 371 // Close 372 assert.NoError(t, fh.Close()) 373 374 // Check can't write on closed handle 375 n, err = fh.WriteAt([]byte("hello"), 0) 376 assert.Equal(t, ECLOSED, err) 377 assert.Equal(t, 0, n) 378 379 // check vfs 380 root, err := vfs.Root() 381 require.NoError(t, err) 382 checkListing(t, root, []string{"file1,11,false"}) 383 384 // check the underlying r.Fremote but not the modtime 385 file1 := fstest.NewItem("file1", "hello world", t1) 386 vfs.WaitForWriters(waitForWritersDelay) 387 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1}, []string{}, fs.ModTimeNotSupported) 388 } 389 390 func TestRWFileHandleWriteNoWrite(t *testing.T) { 391 r, vfs, fh := rwHandleCreateWriteOnly(t) 392 393 // Close the file without writing to it 394 err := fh.Close() 395 if errors.Is(err, fs.ErrorCantUploadEmptyFiles) { 396 t.Logf("skipping test: %v", err) 397 return 398 } 399 assert.NoError(t, err) 400 401 // Create a different file (not in the cache) 402 h, err := vfs.OpenFile("file2", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0777) 403 require.NoError(t, err) 404 405 // Close it with Flush and Release 406 err = h.Flush() 407 assert.NoError(t, err) 408 err = h.Release() 409 assert.NoError(t, err) 410 411 // check vfs 412 root, err := vfs.Root() 413 require.NoError(t, err) 414 checkListing(t, root, []string{"file1,0,false", "file2,0,false"}) 415 416 // check the underlying r.Fremote but not the modtime 417 file1 := fstest.NewItem("file1", "", t1) 418 file2 := fstest.NewItem("file2", "", t1) 419 vfs.WaitForWriters(waitForWritersDelay) 420 fstest.CheckListingWithPrecision(t, r.Fremote, []fstest.Item{file1, file2}, []string{}, fs.ModTimeNotSupported) 421 } 422 423 func TestRWFileHandleFlushWrite(t *testing.T) { 424 _, _, fh := rwHandleCreateWriteOnly(t) 425 426 // Check that the file has been create and is open 427 assert.True(t, fh.opened) 428 429 // Write some data 430 n, err := fh.Write([]byte("hello")) 431 assert.NoError(t, err) 432 assert.Equal(t, 5, n) 433 assert.True(t, fh.opened) 434 435 // Check Flush does not close file if write called 436 err = fh.Flush() 437 assert.NoError(t, err) 438 assert.False(t, fh.closed) 439 440 // Check flush does nothing if called again 441 err = fh.Flush() 442 assert.NoError(t, err) 443 assert.False(t, fh.closed) 444 445 // Check that Close closes the file 446 err = fh.Close() 447 assert.NoError(t, err) 448 assert.True(t, fh.closed) 449 } 450 451 func TestRWFileHandleReleaseWrite(t *testing.T) { 452 _, _, fh := rwHandleCreateWriteOnly(t) 453 454 // Write some data 455 n, err := fh.Write([]byte("hello")) 456 assert.NoError(t, err) 457 assert.Equal(t, 5, n) 458 459 // Check Release closes file 460 err = fh.Release() 461 assert.NoError(t, err) 462 assert.True(t, fh.closed) 463 464 // Check Release does nothing if called again 465 err = fh.Release() 466 assert.NoError(t, err) 467 assert.True(t, fh.closed) 468 } 469 470 // check the size of the file through the open file (if not nil) and via stat 471 func assertSize(t *testing.T, vfs *VFS, fh *RWFileHandle, filepath string, size int64) { 472 if fh != nil { 473 assert.Equal(t, size, fh.Size()) 474 } 475 fi, err := vfs.Stat(filepath) 476 require.NoError(t, err) 477 assert.Equal(t, size, fi.Size()) 478 } 479 480 func TestRWFileHandleSizeTruncateExisting(t *testing.T) { 481 _, vfs, fh := rwHandleCreateFlags(t, true, "dir/file1", os.O_WRONLY|os.O_TRUNC) 482 483 // check initial size after opening 484 assertSize(t, vfs, fh, "dir/file1", 0) 485 486 // write some bytes 487 n, err := fh.Write([]byte("hello")) 488 assert.NoError(t, err) 489 assert.Equal(t, 5, n) 490 491 // check size after writing 492 assertSize(t, vfs, fh, "dir/file1", 5) 493 494 // close 495 assert.NoError(t, fh.Close()) 496 497 // check size after close 498 assertSize(t, vfs, nil, "dir/file1", 5) 499 } 500 501 func TestRWFileHandleSizeCreateExisting(t *testing.T) { 502 _, vfs, fh := rwHandleCreateFlags(t, true, "dir/file1", os.O_WRONLY|os.O_CREATE) 503 504 // check initial size after opening 505 assertSize(t, vfs, fh, "dir/file1", 16) 506 507 // write some bytes 508 n, err := fh.Write([]byte("hello")) 509 assert.NoError(t, err) 510 assert.Equal(t, 5, n) 511 512 // check size after writing 513 assertSize(t, vfs, fh, "dir/file1", 16) 514 515 // write some more bytes 516 n, err = fh.Write([]byte("helloHELLOhello")) 517 assert.NoError(t, err) 518 assert.Equal(t, 15, n) 519 520 // check size after writing 521 assertSize(t, vfs, fh, "dir/file1", 20) 522 523 // close 524 assert.NoError(t, fh.Close()) 525 526 // check size after close 527 assertSize(t, vfs, nil, "dir/file1", 20) 528 } 529 530 func TestRWFileHandleSizeCreateNew(t *testing.T) { 531 _, vfs, fh := rwHandleCreateFlags(t, false, "file1", os.O_WRONLY|os.O_CREATE) 532 533 // check initial size after opening 534 assertSize(t, vfs, fh, "file1", 0) 535 536 // write some bytes 537 n, err := fh.Write([]byte("hello")) 538 assert.NoError(t, err) 539 assert.Equal(t, 5, n) 540 541 // check size after writing 542 assertSize(t, vfs, fh, "file1", 5) 543 544 // check size after writing 545 assertSize(t, vfs, fh, "file1", 5) 546 547 // close 548 assert.NoError(t, fh.Close()) 549 550 // check size after close 551 assertSize(t, vfs, nil, "file1", 5) 552 } 553 554 func testRWFileHandleOpenTest(t *testing.T, vfs *VFS, test *openTest) { 555 fileName := "open-test-file" 556 557 // Make sure we delete the file on failure too 558 defer func() { 559 _ = vfs.Remove(fileName) 560 }() 561 562 // first try with file not existing 563 _, err := vfs.Stat(fileName) 564 require.True(t, os.IsNotExist(err)) 565 566 f, openNonExistentErr := vfs.OpenFile(fileName, test.flags, 0666) 567 568 var readNonExistentErr error 569 var writeNonExistentErr error 570 if openNonExistentErr == nil { 571 // read some bytes 572 buf := []byte{0, 0} 573 _, readNonExistentErr = f.Read(buf) 574 575 // write some bytes 576 _, writeNonExistentErr = f.Write([]byte("hello")) 577 578 // close 579 err = f.Close() 580 require.NoError(t, err) 581 } 582 583 // write the file 584 f, err = vfs.OpenFile(fileName, os.O_WRONLY|os.O_CREATE, 0777) 585 require.NoError(t, err) 586 _, err = f.Write([]byte("hello")) 587 require.NoError(t, err) 588 err = f.Close() 589 require.NoError(t, err) 590 591 // then open file and try with file existing 592 593 f, openExistingErr := vfs.OpenFile(fileName, test.flags, 0666) 594 var readExistingErr error 595 var writeExistingErr error 596 if openExistingErr == nil { 597 // read some bytes 598 buf := []byte{0, 0} 599 _, readExistingErr = f.Read(buf) 600 601 // write some bytes 602 _, writeExistingErr = f.Write([]byte("HEL")) 603 604 // close 605 err = f.Close() 606 require.NoError(t, err) 607 } 608 609 // read the file 610 f, err = vfs.OpenFile(fileName, os.O_RDONLY, 0) 611 require.NoError(t, err) 612 buf, err := io.ReadAll(f) 613 require.NoError(t, err) 614 err = f.Close() 615 require.NoError(t, err) 616 contents := string(buf) 617 618 // remove file 619 node, err := vfs.Stat(fileName) 620 require.NoError(t, err) 621 err = node.Remove() 622 require.NoError(t, err) 623 624 // check 625 assert.Equal(t, test.openNonExistentErr, openNonExistentErr, "openNonExistentErr: want=%v, got=%v", test.openNonExistentErr, openNonExistentErr) 626 assert.Equal(t, test.readNonExistentErr, readNonExistentErr, "readNonExistentErr: want=%v, got=%v", test.readNonExistentErr, readNonExistentErr) 627 assert.Equal(t, test.writeNonExistentErr, writeNonExistentErr, "writeNonExistentErr: want=%v, got=%v", test.writeNonExistentErr, writeNonExistentErr) 628 assert.Equal(t, test.openExistingErr, openExistingErr, "openExistingErr: want=%v, got=%v", test.openExistingErr, openExistingErr) 629 assert.Equal(t, test.readExistingErr, readExistingErr, "readExistingErr: want=%v, got=%v", test.readExistingErr, readExistingErr) 630 assert.Equal(t, test.writeExistingErr, writeExistingErr, "writeExistingErr: want=%v, got=%v", test.writeExistingErr, writeExistingErr) 631 assert.Equal(t, test.contents, contents) 632 } 633 634 func TestRWFileHandleOpenTests(t *testing.T) { 635 for _, cacheMode := range []vfscommon.CacheMode{vfscommon.CacheModeWrites, vfscommon.CacheModeFull} { 636 t.Run(cacheMode.String(), func(t *testing.T) { 637 opt := vfscommon.DefaultOpt 638 opt.CacheMode = cacheMode 639 opt.WriteBack = writeBackDelay 640 _, vfs := newTestVFSOpt(t, &opt) 641 642 for _, test := range openTests { 643 t.Run(test.what, func(t *testing.T) { 644 testRWFileHandleOpenTest(t, vfs, &test) 645 }) 646 } 647 }) 648 } 649 } 650 651 // tests mod time on open files 652 func TestRWFileModTimeWithOpenWriters(t *testing.T) { 653 r, vfs, fh := rwHandleCreateWriteOnly(t) 654 if !canSetModTime(t, r) { 655 t.Skip("can't set mod time") 656 } 657 658 mtime := time.Date(2012, time.November, 18, 17, 32, 31, 0, time.UTC) 659 660 _, err := fh.Write([]byte{104, 105}) 661 require.NoError(t, err) 662 663 err = fh.Node().SetModTime(mtime) 664 require.NoError(t, err) 665 666 // Using Flush/Release to mimic mount instead of Close 667 668 err = fh.Flush() 669 require.NoError(t, err) 670 671 err = fh.Release() 672 require.NoError(t, err) 673 674 info, err := vfs.Stat("file1") 675 require.NoError(t, err) 676 677 if r.Fremote.Precision() != fs.ModTimeNotSupported { 678 // avoid errors because of timezone differences 679 assert.Equal(t, info.ModTime().Unix(), mtime.Unix(), fmt.Sprintf("Time mismatch: %v != %v", info.ModTime(), mtime)) 680 } 681 682 file1 := fstest.NewItem("file1", "hi", mtime) 683 vfs.WaitForWriters(waitForWritersDelay) 684 r.CheckRemoteItems(t, file1) 685 } 686 687 func TestRWCacheRename(t *testing.T) { 688 opt := vfscommon.DefaultOpt 689 opt.CacheMode = vfscommon.CacheModeFull 690 opt.WriteBack = writeBackDelay 691 r, vfs := newTestVFSOpt(t, &opt) 692 693 if !operations.CanServerSideMove(r.Fremote) { 694 t.Skip("skip as can't rename files") 695 } 696 697 h, err := vfs.OpenFile("rename_me", os.O_WRONLY|os.O_CREATE, 0777) 698 require.NoError(t, err) 699 _, err = h.WriteString("hello") 700 require.NoError(t, err) 701 fh, ok := h.(*RWFileHandle) 702 require.True(t, ok) 703 704 err = fh.Sync() 705 require.NoError(t, err) 706 err = fh.Close() 707 require.NoError(t, err) 708 709 assert.True(t, vfs.cache.Exists("rename_me")) 710 711 err = vfs.Rename("rename_me", "i_was_renamed") 712 require.NoError(t, err) 713 714 assert.False(t, vfs.cache.Exists("rename_me")) 715 assert.True(t, vfs.cache.Exists("i_was_renamed")) 716 } 717 718 // Test the cache reading a file that is updated externally 719 // 720 // See: https://github.com/rclone/rclone/issues/6053 721 func TestRWCacheUpdate(t *testing.T) { 722 opt := vfscommon.DefaultOpt 723 opt.CacheMode = vfscommon.CacheModeFull 724 opt.WriteBack = writeBackDelay 725 opt.DirCacheTime = 100 * time.Millisecond 726 r, vfs := newTestVFSOpt(t, &opt) 727 728 if r.Fremote.Precision() == fs.ModTimeNotSupported { 729 t.Skip("skip as modtime not supported") 730 } 731 732 const filename = "TestRWCacheUpdate" 733 734 modTime := time.Now().Add(-time.Hour) 735 for i := 0; i < 10; i++ { 736 modTime = modTime.Add(time.Minute) 737 // Refresh test file 738 contents := fmt.Sprintf("TestRWCacheUpdate%03d", i) 739 // Increase the size for second half of test 740 for j := 5; j < i; j++ { 741 contents += "*" 742 } 743 file1 := r.WriteObject(context.Background(), filename, contents, modTime) 744 r.CheckRemoteItems(t, file1) 745 746 // Wait for directory cache to expire 747 time.Sleep(2 * opt.DirCacheTime) 748 749 // Check the file is OK via the VFS 750 data, err := vfs.ReadFile(filename) 751 require.NoError(t, err) 752 require.Equal(t, contents, string(data)) 753 754 // Check Stat 755 fi, err := vfs.Stat(filename) 756 require.NoError(t, err) 757 assert.Equal(t, int64(len(contents)), fi.Size()) 758 fstest.AssertTimeEqualWithPrecision(t, filename, modTime, fi.ModTime(), r.Fremote.Precision()) 759 } 760 }