github.com/scaleoutsean/fusego@v0.0.0-20220224074057-4a6429e46bb8/samples/flushfs/flush_fs_test.go (about) 1 // Copyright 2015 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package flushfs_test 16 17 import ( 18 "bufio" 19 "encoding/hex" 20 "fmt" 21 "io" 22 "io/ioutil" 23 "os" 24 "path" 25 "runtime" 26 "syscall" 27 "testing" 28 "time" 29 "unsafe" 30 31 "golang.org/x/sys/unix" 32 33 "github.com/scaleoutsean/fusego/fsutil" 34 "github.com/scaleoutsean/fusego/fusetesting" 35 "github.com/scaleoutsean/fusego/samples" 36 . "github.com/jacobsa/oglematchers" 37 . "github.com/jacobsa/ogletest" 38 ) 39 40 func TestFlushFS(t *testing.T) { RunTests(t) } 41 42 //////////////////////////////////////////////////////////////////////// 43 // Boilerplate 44 //////////////////////////////////////////////////////////////////////// 45 46 type flushFSTest struct { 47 samples.SubprocessTest 48 49 // Files to which mount_sample is writing reported flushes and fsyncs. 50 flushes *os.File 51 fsyncs *os.File 52 53 // File handles that are closed in TearDown if non-nil. 54 f1 *os.File 55 f2 *os.File 56 } 57 58 func (t *flushFSTest) setUp( 59 ti *TestInfo, 60 flushErr syscall.Errno, 61 fsyncErr syscall.Errno, 62 readOnly bool) { 63 var err error 64 65 // Set up files to receive flush and fsync reports. 66 t.flushes, err = fsutil.AnonymousFile("") 67 AssertEq(nil, err) 68 69 t.fsyncs, err = fsutil.AnonymousFile("") 70 AssertEq(nil, err) 71 72 // Set up test config. 73 t.MountType = "flushfs" 74 t.MountFlags = []string{ 75 "--flushfs.flush_error", 76 fmt.Sprintf("%d", int(flushErr)), 77 78 "--flushfs.fsync_error", 79 fmt.Sprintf("%d", int(fsyncErr)), 80 } 81 82 if readOnly { 83 t.MountFlags = append(t.MountFlags, "--read_only") 84 } 85 86 t.MountFiles = map[string]*os.File{ 87 "flushfs.flushes_file": t.flushes, 88 "flushfs.fsyncs_file": t.fsyncs, 89 } 90 91 t.SubprocessTest.SetUp(ti) 92 } 93 94 func (t *flushFSTest) TearDown() { 95 // Unlink reporting files. 96 os.Remove(t.flushes.Name()) 97 os.Remove(t.fsyncs.Name()) 98 99 // Close reporting files. 100 t.flushes.Close() 101 t.fsyncs.Close() 102 103 // Close test files if non-nil. 104 if t.f1 != nil { 105 ExpectEq(nil, t.f1.Close()) 106 } 107 108 if t.f2 != nil { 109 ExpectEq(nil, t.f2.Close()) 110 } 111 112 // Finish tearing down. 113 t.SubprocessTest.TearDown() 114 } 115 116 //////////////////////////////////////////////////////////////////////// 117 // Helpers 118 //////////////////////////////////////////////////////////////////////// 119 120 var isDarwin = runtime.GOOS == "darwin" 121 122 func readReports(f *os.File) (reports []string, err error) { 123 // Seek the file to the start. 124 if _, err := f.Seek(0, 0); err != nil { 125 return nil, fmt.Errorf("Seek: %v", err) 126 } 127 128 // We expect reports to end in a newline (including the final one). 129 reader := bufio.NewReader(f) 130 for { 131 record, err := reader.ReadBytes('\n') 132 if err == io.EOF { 133 if len(record) != 0 { 134 return nil, fmt.Errorf("Unexpected record:\n%s", hex.Dump(record)) 135 } 136 137 return reports, nil 138 } 139 140 if err != nil { 141 return nil, fmt.Errorf("ReadBytes: %v", err) 142 } 143 144 // Strip the newline. 145 reports = append(reports, string(record[:len(record)-1])) 146 } 147 } 148 149 // Return a copy of the current contents of t.flushes. 150 func (t *flushFSTest) getFlushes() []string { 151 p, err := readReports(t.flushes) 152 if err != nil { 153 panic(err) 154 } 155 return p 156 } 157 158 // Return a copy of the current contents of t.fsyncs. 159 func (t *flushFSTest) getFsyncs() []string { 160 p, err := readReports(t.fsyncs) 161 if err != nil { 162 panic(err) 163 } 164 return p 165 } 166 167 // Like syscall.Dup2, but correctly annotates the syscall as blocking. See here 168 // for more info: https://github.com/golang/go/issues/10202 169 func dup2(oldfd int, newfd int) error { 170 _, _, e1 := syscall.Syscall( 171 syscall.SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0) 172 173 if e1 != 0 { 174 return e1 175 } 176 177 return nil 178 } 179 180 // Call msync(2) with the MS_SYNC flag on a slice previously returned by 181 // mmap(2). 182 func msync(p []byte) error { 183 _, _, errno := unix.Syscall( 184 unix.SYS_MSYNC, 185 uintptr(unsafe.Pointer(&p[0])), 186 uintptr(len(p)), 187 unix.MS_SYNC) 188 189 if errno != 0 { 190 return errno 191 } 192 193 return nil 194 } 195 196 //////////////////////////////////////////////////////////////////////// 197 // No errors 198 //////////////////////////////////////////////////////////////////////// 199 200 type NoErrorsTest struct { 201 flushFSTest 202 } 203 204 func init() { RegisterTestSuite(&NoErrorsTest{}) } 205 206 func (t *NoErrorsTest) SetUp(ti *TestInfo) { 207 const noErr = 0 208 t.flushFSTest.setUp(ti, noErr, noErr, false) 209 } 210 211 func (t *NoErrorsTest) Close_ReadWrite() { 212 var n int 213 var off int64 214 var err error 215 buf := make([]byte, 1024) 216 217 // Open the file. 218 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) 219 AssertEq(nil, err) 220 221 // Write some contents to the file. 222 n, err = t.f1.Write([]byte("taco")) 223 AssertEq(nil, err) 224 AssertEq(4, n) 225 226 // Seek and read them back. 227 off, err = t.f1.Seek(0, 0) 228 AssertEq(nil, err) 229 AssertEq(0, off) 230 231 n, err = t.f1.Read(buf) 232 AssertThat(err, AnyOf(nil, io.EOF)) 233 AssertEq("taco", string(buf[:n])) 234 235 // At this point, no flushes or fsyncs should have happened. 236 AssertThat(t.getFlushes(), ElementsAre()) 237 AssertThat(t.getFsyncs(), ElementsAre()) 238 239 // Close the file. 240 err = t.f1.Close() 241 t.f1 = nil 242 AssertEq(nil, err) 243 244 // Now we should have received the flush operation (but still no fsync). 245 ExpectThat(t.getFlushes(), ElementsAre("taco")) 246 ExpectThat(t.getFsyncs(), ElementsAre()) 247 } 248 249 func (t *NoErrorsTest) Close_ReadOnly() { 250 var err error 251 252 // Open the file. 253 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDONLY, 0) 254 AssertEq(nil, err) 255 256 // At this point, no flushes or fsyncs should have happened. 257 AssertThat(t.getFlushes(), ElementsAre()) 258 AssertThat(t.getFsyncs(), ElementsAre()) 259 260 // Close the file. 261 err = t.f1.Close() 262 t.f1 = nil 263 AssertEq(nil, err) 264 265 // Now we should have received the flush operation (but still no fsync). 266 ExpectThat(t.getFlushes(), ElementsAre("")) 267 ExpectThat(t.getFsyncs(), ElementsAre()) 268 } 269 270 func (t *NoErrorsTest) Close_WriteOnly() { 271 var n int 272 var err error 273 274 // Open the file. 275 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 276 AssertEq(nil, err) 277 278 // Write some contents to the file. 279 n, err = t.f1.Write([]byte("taco")) 280 AssertEq(nil, err) 281 AssertEq(4, n) 282 283 // At this point, no flushes or fsyncs should have happened. 284 AssertThat(t.getFlushes(), ElementsAre()) 285 AssertThat(t.getFsyncs(), ElementsAre()) 286 287 // Close the file. 288 err = t.f1.Close() 289 t.f1 = nil 290 AssertEq(nil, err) 291 292 // Now we should have received the flush operation (but still no fsync). 293 ExpectThat(t.getFlushes(), ElementsAre("taco")) 294 ExpectThat(t.getFsyncs(), ElementsAre()) 295 } 296 297 func (t *NoErrorsTest) Close_MultipleTimes_NonOverlappingFileHandles() { 298 var n int 299 var err error 300 301 // Open the file. 302 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 303 AssertEq(nil, err) 304 305 // Write some contents to the file. 306 n, err = t.f1.Write([]byte("taco")) 307 AssertEq(nil, err) 308 AssertEq(4, n) 309 310 // At this point, no flushes or fsyncs should have happened. 311 AssertThat(t.getFlushes(), ElementsAre()) 312 AssertThat(t.getFsyncs(), ElementsAre()) 313 314 // Close the file. 315 err = t.f1.Close() 316 t.f1 = nil 317 AssertEq(nil, err) 318 319 // Now we should have received the flush operation (but still no fsync). 320 AssertThat(t.getFlushes(), ElementsAre("taco")) 321 AssertThat(t.getFsyncs(), ElementsAre()) 322 323 // Open the file again. 324 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 325 AssertEq(nil, err) 326 327 // Write again; expect no further flushes. 328 n, err = t.f1.Write([]byte("p")) 329 AssertEq(nil, err) 330 AssertEq(1, n) 331 332 AssertThat(t.getFlushes(), ElementsAre("taco")) 333 AssertThat(t.getFsyncs(), ElementsAre()) 334 335 // Close the file. Now the new contents should be flushed. 336 err = t.f1.Close() 337 t.f1 = nil 338 AssertEq(nil, err) 339 340 AssertThat(t.getFlushes(), ElementsAre("taco", "paco")) 341 AssertThat(t.getFsyncs(), ElementsAre()) 342 } 343 344 func (t *NoErrorsTest) Close_MultipleTimes_OverlappingFileHandles() { 345 var n int 346 var err error 347 348 // Open the file with two handles. 349 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 350 AssertEq(nil, err) 351 352 t.f2, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 353 AssertEq(nil, err) 354 355 // Write some contents with each handle. 356 n, err = t.f1.Write([]byte("taco")) 357 AssertEq(nil, err) 358 AssertEq(4, n) 359 360 n, err = t.f2.Write([]byte("p")) 361 AssertEq(nil, err) 362 AssertEq(1, n) 363 364 // At this point, no flushes or fsyncs should have happened. 365 AssertThat(t.getFlushes(), ElementsAre()) 366 AssertThat(t.getFsyncs(), ElementsAre()) 367 368 // Close one handle. The current contents should be flushed. 369 err = t.f1.Close() 370 t.f1 = nil 371 AssertEq(nil, err) 372 373 AssertThat(t.getFlushes(), ElementsAre("paco")) 374 AssertThat(t.getFsyncs(), ElementsAre()) 375 376 // Write some more contents via the other handle. Again, no further flushes. 377 n, err = t.f2.Write([]byte("orp")) 378 AssertEq(nil, err) 379 AssertEq(3, n) 380 381 AssertThat(t.getFlushes(), ElementsAre("paco")) 382 AssertThat(t.getFsyncs(), ElementsAre()) 383 384 // Close the handle. Now the new contents should be flushed. 385 err = t.f2.Close() 386 t.f2 = nil 387 AssertEq(nil, err) 388 389 AssertThat(t.getFlushes(), ElementsAre("paco", "porp")) 390 AssertThat(t.getFsyncs(), ElementsAre()) 391 } 392 393 func (t *NoErrorsTest) Fsync() { 394 var n int 395 var err error 396 397 // Open the file. 398 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 399 AssertEq(nil, err) 400 401 // Write some contents to the file. 402 n, err = t.f1.Write([]byte("taco")) 403 AssertEq(nil, err) 404 AssertEq(4, n) 405 406 AssertThat(t.getFlushes(), ElementsAre()) 407 AssertThat(t.getFsyncs(), ElementsAre()) 408 409 // Fsync. 410 err = t.f1.Sync() 411 AssertEq(nil, err) 412 413 AssertThat(t.getFlushes(), ElementsAre()) 414 AssertThat(t.getFsyncs(), ElementsAre("taco")) 415 416 // Write some more contents. 417 n, err = t.f1.Write([]byte("s")) 418 AssertEq(nil, err) 419 AssertEq(1, n) 420 421 AssertThat(t.getFlushes(), ElementsAre()) 422 AssertThat(t.getFsyncs(), ElementsAre("taco")) 423 424 // Fsync. 425 err = t.f1.Sync() 426 AssertEq(nil, err) 427 428 AssertThat(t.getFlushes(), ElementsAre()) 429 AssertThat(t.getFsyncs(), ElementsAre("taco", "tacos")) 430 } 431 432 func (t *NoErrorsTest) Fdatasync() { 433 var n int 434 var err error 435 436 if !fsutil.FdatasyncSupported { 437 return 438 } 439 440 // Open the file. 441 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 442 AssertEq(nil, err) 443 444 // Write some contents to the file. 445 n, err = t.f1.Write([]byte("taco")) 446 AssertEq(nil, err) 447 AssertEq(4, n) 448 449 AssertThat(t.getFlushes(), ElementsAre()) 450 AssertThat(t.getFsyncs(), ElementsAre()) 451 452 // Fdatasync. 453 err = fsutil.Fdatasync(t.f1) 454 AssertEq(nil, err) 455 456 AssertThat(t.getFlushes(), ElementsAre()) 457 AssertThat(t.getFsyncs(), ElementsAre("taco")) 458 459 // Write some more contents. 460 n, err = t.f1.Write([]byte("s")) 461 AssertEq(nil, err) 462 AssertEq(1, n) 463 464 AssertThat(t.getFlushes(), ElementsAre()) 465 AssertThat(t.getFsyncs(), ElementsAre("taco")) 466 467 // Fdatasync. 468 err = fsutil.Fdatasync(t.f1) 469 AssertEq(nil, err) 470 471 AssertThat(t.getFlushes(), ElementsAre()) 472 AssertThat(t.getFsyncs(), ElementsAre("taco", "tacos")) 473 } 474 475 func (t *NoErrorsTest) Dup() { 476 var n int 477 var err error 478 479 var expectedFlushes []interface{} 480 481 // Open the file. 482 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 483 AssertEq(nil, err) 484 485 fd1 := t.f1.Fd() 486 487 // Use dup(2) to get another copy. 488 fd2, err := syscall.Dup(int(fd1)) 489 AssertEq(nil, err) 490 491 t.f2 = os.NewFile(uintptr(fd2), t.f1.Name()) 492 493 // Write some contents with each handle. 494 n, err = t.f1.Write([]byte("taco")) 495 AssertEq(nil, err) 496 AssertEq(4, n) 497 498 n, err = t.f2.Write([]byte("s")) 499 AssertEq(nil, err) 500 AssertEq(1, n) 501 502 // At this point, no flushes or fsyncs should have happened. 503 AssertThat(t.getFlushes(), ElementsAre()) 504 AssertThat(t.getFsyncs(), ElementsAre()) 505 506 // Close one handle. On Linux the current contents should be flushed. On OS 507 // X, where the semantics of handles are different, they apparently are not. 508 // (Cf. https://github.com/osxfuse/osxfuse/issues/199) 509 err = t.f1.Close() 510 t.f1 = nil 511 AssertEq(nil, err) 512 513 if !isDarwin { 514 expectedFlushes = append(expectedFlushes, "tacos") 515 } 516 517 AssertThat(t.getFlushes(), ElementsAre(expectedFlushes...)) 518 AssertThat(t.getFsyncs(), ElementsAre()) 519 520 // Write some more contents via the other handle. Again, no further flushes. 521 n, err = t.f2.Write([]byte("!")) 522 AssertEq(nil, err) 523 AssertEq(1, n) 524 525 AssertThat(t.getFlushes(), ElementsAre(expectedFlushes...)) 526 AssertThat(t.getFsyncs(), ElementsAre()) 527 528 // Close the handle. Now the new contents should be flushed. 529 err = t.f2.Close() 530 t.f2 = nil 531 AssertEq(nil, err) 532 533 expectedFlushes = append(expectedFlushes, "tacos!") 534 ExpectThat(t.getFlushes(), ElementsAre(expectedFlushes...)) 535 ExpectThat(t.getFsyncs(), ElementsAre()) 536 } 537 538 func (t *NoErrorsTest) Dup2() { 539 var n int 540 var err error 541 542 // Open the file. 543 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 544 AssertEq(nil, err) 545 546 // Write some contents to the file. 547 n, err = t.f1.Write([]byte("taco")) 548 AssertEq(nil, err) 549 AssertEq(4, n) 550 551 // Create some anonymous temporary file. 552 t.f2, err = fsutil.AnonymousFile("") 553 AssertEq(nil, err) 554 555 // Duplicate the temporary file descriptor on top of the file from our file 556 // system. We should see a flush. 557 err = dup2(int(t.f2.Fd()), int(t.f1.Fd())) 558 ExpectEq(nil, err) 559 560 ExpectThat(t.getFlushes(), ElementsAre("taco")) 561 ExpectThat(t.getFsyncs(), ElementsAre()) 562 } 563 564 func (t *NoErrorsTest) Mmap_NoMsync_MunmapBeforeClose() { 565 var n int 566 var err error 567 568 // Open the file. 569 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) 570 AssertEq(nil, err) 571 572 // Write some contents to the file. 573 n, err = t.f1.Write([]byte("taco")) 574 AssertEq(nil, err) 575 AssertEq(4, n) 576 577 // mmap the file. 578 data, err := syscall.Mmap( 579 int(t.f1.Fd()), 0, 4, 580 syscall.PROT_READ|syscall.PROT_WRITE, 581 syscall.MAP_SHARED) 582 583 AssertEq(nil, err) 584 defer syscall.Munmap(data) 585 586 AssertEq("taco", string(data)) 587 588 // Modify the contents. 589 data[0] = 'p' 590 591 // Unmap. 592 err = syscall.Munmap(data) 593 AssertEq(nil, err) 594 595 // munmap does not cause a flush. 596 ExpectThat(t.getFlushes(), ElementsAre()) 597 ExpectThat(t.getFsyncs(), ElementsAre()) 598 599 // Close the file. We should see a flush with up to date contents. 600 err = t.f1.Close() 601 t.f1 = nil 602 AssertEq(nil, err) 603 604 ExpectThat(t.getFlushes(), ElementsAre("paco")) 605 ExpectThat(t.getFsyncs(), ElementsAre()) 606 } 607 608 func (t *NoErrorsTest) Mmap_NoMsync_CloseBeforeMunmap() { 609 var n int 610 var err error 611 612 // Open the file. 613 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) 614 AssertEq(nil, err) 615 616 // Write some contents to the file. 617 n, err = t.f1.Write([]byte("taco")) 618 AssertEq(nil, err) 619 AssertEq(4, n) 620 621 // mmap the file. 622 data, err := syscall.Mmap( 623 int(t.f1.Fd()), 0, 4, 624 syscall.PROT_READ|syscall.PROT_WRITE, 625 syscall.MAP_SHARED) 626 627 AssertEq(nil, err) 628 defer syscall.Munmap(data) 629 630 AssertEq("taco", string(data)) 631 632 // Close the file. We should see a flush. 633 err = t.f1.Close() 634 t.f1 = nil 635 AssertEq(nil, err) 636 637 AssertThat(t.getFlushes(), ElementsAre("taco")) 638 AssertThat(t.getFsyncs(), ElementsAre()) 639 640 // Modify the contents. 641 data[0] = 'p' 642 643 // Unmap. 644 err = syscall.Munmap(data) 645 AssertEq(nil, err) 646 647 // munmap does not cause a flush. 648 ExpectThat(t.getFlushes(), ElementsAre("taco")) 649 ExpectThat(t.getFsyncs(), ElementsAre()) 650 } 651 652 func (t *NoErrorsTest) Mmap_WithMsync_MunmapBeforeClose() { 653 var n int 654 var err error 655 656 var expectedFsyncs []interface{} 657 658 // Open the file. 659 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) 660 AssertEq(nil, err) 661 662 // Write some contents to the file. 663 n, err = t.f1.Write([]byte("taco")) 664 AssertEq(nil, err) 665 AssertEq(4, n) 666 667 // mmap the file. 668 data, err := syscall.Mmap( 669 int(t.f1.Fd()), 0, 4, 670 syscall.PROT_READ|syscall.PROT_WRITE, 671 syscall.MAP_SHARED) 672 673 AssertEq(nil, err) 674 defer syscall.Munmap(data) 675 676 AssertEq("taco", string(data)) 677 678 // Modify the contents. 679 data[0] = 'p' 680 681 // msync. This causes an fsync, except on OS X (cf. 682 // https://github.com/osxfuse/osxfuse/issues/202). 683 err = msync(data) 684 ExpectEq(nil, err) 685 686 if !isDarwin { 687 expectedFsyncs = append(expectedFsyncs, "paco") 688 } 689 690 ExpectThat(t.getFlushes(), ElementsAre()) 691 ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) 692 693 // Unmap. This does not cause anything. 694 err = syscall.Munmap(data) 695 AssertEq(nil, err) 696 697 ExpectThat(t.getFlushes(), ElementsAre()) 698 ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) 699 700 // Close the file. We should now see a flush with the modified contents, even 701 // on OS X. 702 err = t.f1.Close() 703 t.f1 = nil 704 AssertEq(nil, err) 705 706 ExpectThat(t.getFlushes(), ElementsAre("paco")) 707 ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) 708 } 709 710 func (t *NoErrorsTest) Mmap_WithMsync_CloseBeforeMunmap() { 711 var n int 712 var err error 713 714 var expectedFsyncs []interface{} 715 716 // Open the file. 717 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) 718 AssertEq(nil, err) 719 720 // Write some contents to the file. 721 n, err = t.f1.Write([]byte("taco")) 722 AssertEq(nil, err) 723 AssertEq(4, n) 724 725 // mmap the file. 726 data, err := syscall.Mmap( 727 int(t.f1.Fd()), 0, 4, 728 syscall.PROT_READ|syscall.PROT_WRITE, 729 syscall.MAP_SHARED) 730 731 AssertEq(nil, err) 732 defer syscall.Munmap(data) 733 734 AssertEq("taco", string(data)) 735 736 // Close the file. We should see a flush. 737 err = t.f1.Close() 738 t.f1 = nil 739 AssertEq(nil, err) 740 741 AssertThat(t.getFlushes(), ElementsAre("taco")) 742 AssertThat(t.getFsyncs(), ElementsAre()) 743 744 // Modify the contents. 745 data[0] = 'p' 746 747 // msync. This causes an fsync, except on OS X (cf. 748 // https://github.com/osxfuse/osxfuse/issues/202). 749 err = msync(data) 750 ExpectEq(nil, err) 751 752 if !isDarwin { 753 expectedFsyncs = append(expectedFsyncs, "paco") 754 } 755 756 ExpectThat(t.getFlushes(), ElementsAre("taco")) 757 ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) 758 759 // Unmap. Again, this does not cause a flush. 760 err = syscall.Munmap(data) 761 AssertEq(nil, err) 762 763 ExpectThat(t.getFlushes(), ElementsAre("taco")) 764 ExpectThat(t.getFsyncs(), ElementsAre(expectedFsyncs...)) 765 } 766 767 func (t *NoErrorsTest) Directory() { 768 var err error 769 770 // Open the directory. 771 t.f1, err = os.Open(path.Join(t.Dir, "bar")) 772 AssertEq(nil, err) 773 774 // Sanity check: stat it. 775 fi, err := t.f1.Stat() 776 AssertEq(nil, err) 777 AssertEq(0777|os.ModeDir, fi.Mode()) 778 779 // Sync it. 780 err = t.f1.Sync() 781 AssertEq(nil, err) 782 783 // Close it. 784 err = t.f1.Close() 785 t.f1 = nil 786 AssertEq(nil, err) 787 788 // No flushes or fsync requests should have been received. 789 ExpectThat(t.getFlushes(), ElementsAre()) 790 ExpectThat(t.getFsyncs(), ElementsAre()) 791 } 792 793 //////////////////////////////////////////////////////////////////////// 794 // Flush error 795 //////////////////////////////////////////////////////////////////////// 796 797 type FlushErrorTest struct { 798 flushFSTest 799 } 800 801 func init() { RegisterTestSuite(&FlushErrorTest{}) } 802 803 func (t *FlushErrorTest) SetUp(ti *TestInfo) { 804 const noErr = 0 805 t.flushFSTest.setUp(ti, syscall.ENOENT, noErr, false) 806 } 807 808 func (t *FlushErrorTest) Close() { 809 var err error 810 811 // Open the file. 812 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) 813 AssertEq(nil, err) 814 815 // Close the file. 816 err = t.f1.Close() 817 t.f1 = nil 818 819 ExpectThat(err, Error(HasSubstr("no such file"))) 820 } 821 822 func (t *FlushErrorTest) Dup() { 823 var err error 824 825 // Open the file. 826 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 827 AssertEq(nil, err) 828 829 fd1 := t.f1.Fd() 830 831 // Use dup(2) to get another copy. 832 fd2, err := syscall.Dup(int(fd1)) 833 AssertEq(nil, err) 834 835 t.f2 = os.NewFile(uintptr(fd2), t.f1.Name()) 836 837 // Close by the first handle. On OS X, where the semantics of file handles 838 // are different (cf. https://github.com/osxfuse/osxfuse/issues/199), this 839 // does not result in an error. 840 err = t.f1.Close() 841 t.f1 = nil 842 843 if isDarwin { 844 AssertEq(nil, err) 845 } else { 846 ExpectThat(err, Error(HasSubstr("no such file"))) 847 } 848 849 // Close by the second handle. 850 err = t.f2.Close() 851 t.f2 = nil 852 853 ExpectThat(err, Error(HasSubstr("no such file"))) 854 } 855 856 func (t *FlushErrorTest) Dup2() { 857 var err error 858 859 // Open the file. 860 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_WRONLY, 0) 861 AssertEq(nil, err) 862 863 // Create some anonymous temporary file. 864 t.f2, err = fsutil.AnonymousFile("") 865 AssertEq(nil, err) 866 867 // Duplicate the temporary file descriptor on top of the file from our file 868 // system. We shouldn't see the flush error. 869 err = dup2(int(t.f2.Fd()), int(t.f1.Fd())) 870 ExpectEq(nil, err) 871 } 872 873 //////////////////////////////////////////////////////////////////////// 874 // Fsync error 875 //////////////////////////////////////////////////////////////////////// 876 877 type FsyncErrorTest struct { 878 flushFSTest 879 } 880 881 func init() { RegisterTestSuite(&FsyncErrorTest{}) } 882 883 func (t *FsyncErrorTest) SetUp(ti *TestInfo) { 884 const noErr = 0 885 t.flushFSTest.setUp(ti, noErr, syscall.ENOENT, false) 886 } 887 888 func (t *FsyncErrorTest) Fsync() { 889 var err error 890 891 // Open the file. 892 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) 893 AssertEq(nil, err) 894 895 // Fsync. 896 err = t.f1.Sync() 897 898 ExpectThat(err, Error(HasSubstr("no such file"))) 899 } 900 901 func (t *FsyncErrorTest) Fdatasync() { 902 var err error 903 904 if !fsutil.FdatasyncSupported { 905 return 906 } 907 908 // Open the file. 909 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) 910 AssertEq(nil, err) 911 912 // Fdatasync. 913 err = fsutil.Fdatasync(t.f1) 914 915 ExpectThat(err, Error(HasSubstr("no such file"))) 916 } 917 918 func (t *FsyncErrorTest) Msync() { 919 var err error 920 921 // On OS X, msync does not cause SyncFile. 922 if isDarwin { 923 return 924 } 925 926 // Open the file. 927 t.f1, err = os.OpenFile(path.Join(t.Dir, "foo"), os.O_RDWR, 0) 928 AssertEq(nil, err) 929 930 // mmap the file. 931 data, err := syscall.Mmap( 932 int(t.f1.Fd()), 0, 4, 933 syscall.PROT_READ|syscall.PROT_WRITE, 934 syscall.MAP_SHARED) 935 936 AssertEq(nil, err) 937 defer syscall.Munmap(data) 938 939 // msync the mapping. 940 err = msync(data) 941 ExpectThat(err, Error(HasSubstr("no such file"))) 942 943 // Unmap. 944 err = syscall.Munmap(data) 945 AssertEq(nil, err) 946 } 947 948 //////////////////////////////////////////////////////////////////////// 949 // Read-only mount 950 //////////////////////////////////////////////////////////////////////// 951 952 type ReadOnlyTest struct { 953 flushFSTest 954 } 955 956 func init() { RegisterTestSuite(&ReadOnlyTest{}) } 957 958 func (t *ReadOnlyTest) SetUp(ti *TestInfo) { 959 const noErr = 0 960 t.flushFSTest.setUp(ti, noErr, noErr, true) 961 } 962 963 func (t *ReadOnlyTest) ReadRoot() { 964 var fi os.FileInfo 965 966 // Read. 967 entries, err := fusetesting.ReadDirPicky(t.Dir) 968 AssertEq(nil, err) 969 AssertEq(2, len(entries)) 970 971 // bar 972 fi = entries[0] 973 ExpectEq("bar", fi.Name()) 974 ExpectEq(os.FileMode(0777)|os.ModeDir, fi.Mode()) 975 976 // foo 977 fi = entries[1] 978 ExpectEq("foo", fi.Name()) 979 ExpectEq(os.FileMode(0777), fi.Mode()) 980 } 981 982 func (t *ReadOnlyTest) StatFiles() { 983 var fi os.FileInfo 984 var err error 985 986 // bar 987 fi, err = os.Stat(path.Join(t.Dir, "bar")) 988 AssertEq(nil, err) 989 990 ExpectEq("bar", fi.Name()) 991 ExpectEq(os.FileMode(0777)|os.ModeDir, fi.Mode()) 992 993 // foo 994 fi, err = os.Stat(path.Join(t.Dir, "foo")) 995 AssertEq(nil, err) 996 997 ExpectEq("foo", fi.Name()) 998 ExpectEq(os.FileMode(0777), fi.Mode()) 999 } 1000 1001 func (t *ReadOnlyTest) ReadFile() { 1002 _, err := ioutil.ReadFile(path.Join(t.Dir, "foo")) 1003 ExpectEq(nil, err) 1004 } 1005 1006 func (t *ReadOnlyTest) ReadDir() { 1007 _, err := fusetesting.ReadDirPicky(path.Join(t.Dir, "bar")) 1008 ExpectEq(nil, err) 1009 } 1010 1011 func (t *ReadOnlyTest) CreateFile() { 1012 err := ioutil.WriteFile(path.Join(t.Dir, "blah"), []byte{}, 0400) 1013 ExpectThat(err, Error(HasSubstr("read-only"))) 1014 } 1015 1016 func (t *ReadOnlyTest) Mkdir() { 1017 err := os.Mkdir(path.Join(t.Dir, "blah"), 0700) 1018 ExpectThat(err, Error(HasSubstr("read-only"))) 1019 } 1020 1021 func (t *ReadOnlyTest) OpenForWrite() { 1022 modes := []int{ 1023 os.O_WRONLY, 1024 os.O_RDWR, 1025 } 1026 1027 for _, mode := range modes { 1028 f, err := os.OpenFile(path.Join(t.Dir, "foo"), mode, 0700) 1029 f.Close() 1030 ExpectThat(err, Error(HasSubstr("read-only")), "mode: %v", mode) 1031 } 1032 } 1033 1034 func (t *ReadOnlyTest) Chtimes() { 1035 err := os.Chtimes(path.Join(t.Dir, "foo"), time.Now(), time.Now()) 1036 ExpectThat(err, Error(MatchesRegexp("read-only|not permitted|permission denied"))) 1037 } 1038 1039 func (t *ReadOnlyTest) Chmod() { 1040 err := os.Chmod(path.Join(t.Dir, "foo"), 0700) 1041 ExpectThat(err, Error(HasSubstr("read-only"))) 1042 }