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  }