github.com/LandonTClipp/afero@v1.3.6-0.20200907052150-97f9d166c7a3/memmap_test.go (about)

     1  package afero
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"os"
     7  	"path/filepath"
     8  	"runtime"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestNormalizePath(t *testing.T) {
    17  	type test struct {
    18  		input    string
    19  		expected string
    20  	}
    21  
    22  	data := []test{
    23  		{".", FilePathSeparator},
    24  		{"./", FilePathSeparator},
    25  		{"..", FilePathSeparator},
    26  		{"../", FilePathSeparator},
    27  		{"./..", FilePathSeparator},
    28  		{"./../", FilePathSeparator},
    29  	}
    30  
    31  	for i, d := range data {
    32  		cpath := normalizePath(d.input)
    33  		if d.expected != cpath {
    34  			t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, cpath)
    35  		}
    36  	}
    37  }
    38  
    39  func TestPathErrors(t *testing.T) {
    40  	path := filepath.Join(".", "some", "path")
    41  	path2 := filepath.Join(".", "different", "path")
    42  	fs := NewMemMapFs()
    43  	perm := os.FileMode(0755)
    44  
    45  	// relevant functions:
    46  	// func (m *MemMapFs) Chmod(name string, mode os.FileMode) error
    47  	// func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error
    48  	// func (m *MemMapFs) Create(name string) (File, error)
    49  	// func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error
    50  	// func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error
    51  	// func (m *MemMapFs) Open(name string) (File, error)
    52  	// func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error)
    53  	// func (m *MemMapFs) Remove(name string) error
    54  	// func (m *MemMapFs) Rename(oldname, newname string) error
    55  	// func (m *MemMapFs) Stat(name string) (os.FileInfo, error)
    56  
    57  	err := fs.Chmod(path, perm)
    58  	checkPathError(t, err, "Chmod")
    59  
    60  	err = fs.Chtimes(path, time.Now(), time.Now())
    61  	checkPathError(t, err, "Chtimes")
    62  
    63  	// fs.Create doesn't return an error
    64  
    65  	err = fs.Mkdir(path2, perm)
    66  	if err != nil {
    67  		t.Error(err)
    68  	}
    69  	err = fs.Mkdir(path2, perm)
    70  	checkPathError(t, err, "Mkdir")
    71  
    72  	err = fs.MkdirAll(path2, perm)
    73  	if err != nil {
    74  		t.Error("MkdirAll:", err)
    75  	}
    76  
    77  	_, err = fs.Open(path)
    78  	checkPathError(t, err, "Open")
    79  
    80  	_, err = fs.OpenFile(path, os.O_RDWR, perm)
    81  	checkPathError(t, err, "OpenFile")
    82  
    83  	err = fs.Remove(path)
    84  	checkPathError(t, err, "Remove")
    85  
    86  	err = fs.RemoveAll(path)
    87  	if err != nil {
    88  		t.Error("RemoveAll:", err)
    89  	}
    90  
    91  	err = fs.Rename(path, path2)
    92  	checkPathError(t, err, "Rename")
    93  
    94  	_, err = fs.Stat(path)
    95  	checkPathError(t, err, "Stat")
    96  }
    97  
    98  func checkPathError(t *testing.T, err error, op string) {
    99  	pathErr, ok := err.(*os.PathError)
   100  	if !ok {
   101  		t.Error(op+":", err, "is not a os.PathError")
   102  		return
   103  	}
   104  	_, ok = pathErr.Err.(*os.PathError)
   105  	if ok {
   106  		t.Error(op+":", err, "contains another os.PathError")
   107  	}
   108  }
   109  
   110  // Ensure os.O_EXCL is correctly handled.
   111  func TestOpenFileExcl(t *testing.T) {
   112  	const fileName = "/myFileTest"
   113  	const fileMode = os.FileMode(0765)
   114  
   115  	fs := NewMemMapFs()
   116  
   117  	// First creation should succeed.
   118  	f, err := fs.OpenFile(fileName, os.O_CREATE|os.O_EXCL, fileMode)
   119  	if err != nil {
   120  		t.Errorf("OpenFile Create Excl failed: %s", err)
   121  		return
   122  	}
   123  	f.Close()
   124  
   125  	// Second creation should fail.
   126  	_, err = fs.OpenFile(fileName, os.O_CREATE|os.O_EXCL, fileMode)
   127  	if err == nil {
   128  		t.Errorf("OpenFile Create Excl should have failed, but it didn't")
   129  	}
   130  	checkPathError(t, err, "Open")
   131  }
   132  
   133  // Ensure Permissions are set on OpenFile/Mkdir/MkdirAll
   134  func TestPermSet(t *testing.T) {
   135  	const fileName = "/myFileTest"
   136  	const dirPath = "/myDirTest"
   137  	const dirPathAll = "/my/path/to/dir"
   138  
   139  	const fileMode = os.FileMode(0765)
   140  	// directories will also have the directory bit set
   141  	const dirMode = fileMode | os.ModeDir
   142  
   143  	fs := NewMemMapFs()
   144  
   145  	// Test Openfile
   146  	f, err := fs.OpenFile(fileName, os.O_CREATE, fileMode)
   147  	if err != nil {
   148  		t.Errorf("OpenFile Create failed: %s", err)
   149  		return
   150  	}
   151  	f.Close()
   152  
   153  	s, err := fs.Stat(fileName)
   154  	if err != nil {
   155  		t.Errorf("Stat failed: %s", err)
   156  		return
   157  	}
   158  	if s.Mode().String() != fileMode.String() {
   159  		t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), fileMode.String())
   160  		return
   161  	}
   162  
   163  	// Test Mkdir
   164  	err = fs.Mkdir(dirPath, dirMode)
   165  	if err != nil {
   166  		t.Errorf("MkDir Create failed: %s", err)
   167  		return
   168  	}
   169  	s, err = fs.Stat(dirPath)
   170  	if err != nil {
   171  		t.Errorf("Stat failed: %s", err)
   172  		return
   173  	}
   174  	// sets File
   175  	if s.Mode().String() != dirMode.String() {
   176  		t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
   177  		return
   178  	}
   179  
   180  	// Test MkdirAll
   181  	err = fs.MkdirAll(dirPathAll, dirMode)
   182  	if err != nil {
   183  		t.Errorf("MkDir Create failed: %s", err)
   184  		return
   185  	}
   186  	s, err = fs.Stat(dirPathAll)
   187  	if err != nil {
   188  		t.Errorf("Stat failed: %s", err)
   189  		return
   190  	}
   191  	if s.Mode().String() != dirMode.String() {
   192  		t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
   193  		return
   194  	}
   195  }
   196  
   197  // Fails if multiple file objects use the same file.at counter in MemMapFs
   198  func TestMultipleOpenFiles(t *testing.T) {
   199  	defer removeAllTestFiles(t)
   200  	const fileName = "afero-demo2.txt"
   201  
   202  	var data = make([][]byte, len(Fss))
   203  
   204  	for i, fs := range Fss {
   205  		dir := testDir(fs)
   206  		path := filepath.Join(dir, fileName)
   207  		fh1, err := fs.Create(path)
   208  		if err != nil {
   209  			t.Error("fs.Create failed: " + err.Error())
   210  		}
   211  		_, err = fh1.Write([]byte("test"))
   212  		if err != nil {
   213  			t.Error("fh.Write failed: " + err.Error())
   214  		}
   215  		_, err = fh1.Seek(0, os.SEEK_SET)
   216  		if err != nil {
   217  			t.Error(err)
   218  		}
   219  
   220  		fh2, err := fs.OpenFile(path, os.O_RDWR, 0777)
   221  		if err != nil {
   222  			t.Error("fs.OpenFile failed: " + err.Error())
   223  		}
   224  		_, err = fh2.Seek(0, os.SEEK_END)
   225  		if err != nil {
   226  			t.Error(err)
   227  		}
   228  		_, err = fh2.Write([]byte("data"))
   229  		if err != nil {
   230  			t.Error(err)
   231  		}
   232  		err = fh2.Close()
   233  		if err != nil {
   234  			t.Error(err)
   235  		}
   236  
   237  		_, err = fh1.Write([]byte("data"))
   238  		if err != nil {
   239  			t.Error(err)
   240  		}
   241  		err = fh1.Close()
   242  		if err != nil {
   243  			t.Error(err)
   244  		}
   245  		// the file now should contain "datadata"
   246  		data[i], err = ReadFile(fs, path)
   247  		if err != nil {
   248  			t.Error(err)
   249  		}
   250  	}
   251  
   252  	for i, fs := range Fss {
   253  		if i == 0 {
   254  			continue
   255  		}
   256  		if string(data[0]) != string(data[i]) {
   257  			t.Errorf("%s and %s don't behave the same\n"+
   258  				"%s: \"%s\"\n%s: \"%s\"\n",
   259  				Fss[0].Name(), fs.Name(), Fss[0].Name(), data[0], fs.Name(), data[i])
   260  		}
   261  	}
   262  }
   263  
   264  // Test if file.Write() fails when opened as read only
   265  func TestReadOnly(t *testing.T) {
   266  	defer removeAllTestFiles(t)
   267  	const fileName = "afero-demo.txt"
   268  
   269  	for _, fs := range Fss {
   270  		dir := testDir(fs)
   271  		path := filepath.Join(dir, fileName)
   272  
   273  		f, err := fs.Create(path)
   274  		if err != nil {
   275  			t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
   276  		}
   277  		_, err = f.Write([]byte("test"))
   278  		if err != nil {
   279  			t.Error(fs.Name()+":", "Write failed: "+err.Error())
   280  		}
   281  		f.Close()
   282  
   283  		f, err = fs.Open(path)
   284  		if err != nil {
   285  			t.Error("fs.Open failed: " + err.Error())
   286  		}
   287  		_, err = f.Write([]byte("data"))
   288  		if err == nil {
   289  			t.Error(fs.Name()+":", "No write error")
   290  		}
   291  		f.Close()
   292  
   293  		f, err = fs.OpenFile(path, os.O_RDONLY, 0644)
   294  		if err != nil {
   295  			t.Error("fs.Open failed: " + err.Error())
   296  		}
   297  		_, err = f.Write([]byte("data"))
   298  		if err == nil {
   299  			t.Error(fs.Name()+":", "No write error")
   300  		}
   301  		f.Close()
   302  	}
   303  }
   304  
   305  func TestWriteCloseTime(t *testing.T) {
   306  	defer removeAllTestFiles(t)
   307  	const fileName = "afero-demo.txt"
   308  
   309  	for _, fs := range Fss {
   310  		dir := testDir(fs)
   311  		path := filepath.Join(dir, fileName)
   312  
   313  		f, err := fs.Create(path)
   314  		if err != nil {
   315  			t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
   316  		}
   317  		f.Close()
   318  
   319  		f, err = fs.Create(path)
   320  		if err != nil {
   321  			t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
   322  		}
   323  		fi, err := f.Stat()
   324  		if err != nil {
   325  			t.Error(fs.Name()+":", "Stat failed: "+err.Error())
   326  		}
   327  		timeBefore := fi.ModTime()
   328  
   329  		// sorry for the delay, but we have to make sure time advances,
   330  		// also on non Un*x systems...
   331  		switch runtime.GOOS {
   332  		case "windows":
   333  			time.Sleep(2 * time.Second)
   334  		case "darwin":
   335  			time.Sleep(1 * time.Second)
   336  		default: // depending on the FS, this may work with < 1 second, on my old ext3 it does not
   337  			time.Sleep(1 * time.Second)
   338  		}
   339  
   340  		_, err = f.Write([]byte("test"))
   341  		if err != nil {
   342  			t.Error(fs.Name()+":", "Write failed: "+err.Error())
   343  		}
   344  		f.Close()
   345  		fi, err = fs.Stat(path)
   346  		if err != nil {
   347  			t.Error(fs.Name()+":", "fs.Stat failed: "+err.Error())
   348  		}
   349  		if fi.ModTime().Equal(timeBefore) {
   350  			t.Error(fs.Name()+":", "ModTime was not set on Close()")
   351  		}
   352  	}
   353  }
   354  
   355  // This test should be run with the race detector on:
   356  // go test -race -v -timeout 10s -run TestRacingDeleteAndClose
   357  func TestRacingDeleteAndClose(t *testing.T) {
   358  	fs := NewMemMapFs()
   359  	pathname := "testfile"
   360  	f, err := fs.Create(pathname)
   361  	if err != nil {
   362  		t.Fatal(err)
   363  	}
   364  
   365  	in := make(chan bool)
   366  
   367  	go func() {
   368  		<-in
   369  		f.Close()
   370  	}()
   371  	go func() {
   372  		<-in
   373  		fs.Remove(pathname)
   374  	}()
   375  	close(in)
   376  }
   377  
   378  // This test should be run with the race detector on:
   379  // go test -run TestMemFsDataRace -race
   380  func TestMemFsDataRace(t *testing.T) {
   381  	const dir = "test_dir"
   382  	fs := NewMemMapFs()
   383  
   384  	if err := fs.MkdirAll(dir, 0777); err != nil {
   385  		t.Fatal(err)
   386  	}
   387  
   388  	const n = 1000
   389  	done := make(chan struct{})
   390  
   391  	go func() {
   392  		defer close(done)
   393  		for i := 0; i < n; i++ {
   394  			fname := filepath.Join(dir, fmt.Sprintf("%d.txt", i))
   395  			if err := WriteFile(fs, fname, []byte(""), 0777); err != nil {
   396  				panic(err)
   397  			}
   398  			if err := fs.Remove(fname); err != nil {
   399  				panic(err)
   400  			}
   401  		}
   402  	}()
   403  
   404  loop:
   405  	for {
   406  		select {
   407  		case <-done:
   408  			break loop
   409  		default:
   410  			_, err := ReadDir(fs, dir)
   411  			if err != nil {
   412  				t.Fatal(err)
   413  			}
   414  		}
   415  	}
   416  }
   417  
   418  // root is a directory
   419  func TestMemFsRootDirMode(t *testing.T) {
   420  	t.Parallel()
   421  
   422  	fs := NewMemMapFs()
   423  	info, err := fs.Stat("/")
   424  	if err != nil {
   425  		t.Fatal(err)
   426  	}
   427  	if !info.IsDir() {
   428  		t.Error("should be a directory")
   429  	}
   430  	if !info.Mode().IsDir() {
   431  		t.Errorf("FileMode is not directory, is %s", info.Mode().String())
   432  	}
   433  }
   434  
   435  // MkdirAll creates intermediate directories with correct mode
   436  func TestMemFsMkdirAllMode(t *testing.T) {
   437  	t.Parallel()
   438  
   439  	fs := NewMemMapFs()
   440  	err := fs.MkdirAll("/a/b/c", 0755)
   441  	if err != nil {
   442  		t.Fatal(err)
   443  	}
   444  	info, err := fs.Stat("/a")
   445  	if err != nil {
   446  		t.Fatal(err)
   447  	}
   448  	if !info.Mode().IsDir() {
   449  		t.Error("/a: mode is not directory")
   450  	}
   451  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   452  		t.Errorf("/a: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   453  	}
   454  	info, err = fs.Stat("/a/b")
   455  	if err != nil {
   456  		t.Fatal(err)
   457  	}
   458  	if !info.Mode().IsDir() {
   459  		t.Error("/a/b: mode is not directory")
   460  	}
   461  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   462  		t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   463  	}
   464  	info, err = fs.Stat("/a/b/c")
   465  	if err != nil {
   466  		t.Fatal(err)
   467  	}
   468  	if !info.Mode().IsDir() {
   469  		t.Error("/a/b/c: mode is not directory")
   470  	}
   471  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   472  		t.Errorf("/a/b/c: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   473  	}
   474  }
   475  
   476  // MkdirAll does not change permissions of already-existing directories
   477  func TestMemFsMkdirAllNoClobber(t *testing.T) {
   478  	t.Parallel()
   479  
   480  	fs := NewMemMapFs()
   481  	err := fs.MkdirAll("/a/b/c", 0755)
   482  	if err != nil {
   483  		t.Fatal(err)
   484  	}
   485  	info, err := fs.Stat("/a/b")
   486  	if err != nil {
   487  		t.Fatal(err)
   488  	}
   489  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   490  		t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   491  	}
   492  	err = fs.MkdirAll("/a/b/c/d/e/f", 0710)
   493  	// '/a/b' is unchanged
   494  	if err != nil {
   495  		t.Fatal(err)
   496  	}
   497  	info, err = fs.Stat("/a/b")
   498  	if err != nil {
   499  		t.Fatal(err)
   500  	}
   501  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   502  		t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   503  	}
   504  	// new directories created with proper permissions
   505  	info, err = fs.Stat("/a/b/c/d")
   506  	if err != nil {
   507  		t.Fatal(err)
   508  	}
   509  	if info.Mode() != os.FileMode(os.ModeDir|0710) {
   510  		t.Errorf("/a/b/c/d: wrong permissions, expected drwx--x---, got %s", info.Mode())
   511  	}
   512  	info, err = fs.Stat("/a/b/c/d/e")
   513  	if err != nil {
   514  		t.Fatal(err)
   515  	}
   516  	if info.Mode() != os.FileMode(os.ModeDir|0710) {
   517  		t.Errorf("/a/b/c/d/e: wrong permissions, expected drwx--x---, got %s", info.Mode())
   518  	}
   519  	info, err = fs.Stat("/a/b/c/d/e/f")
   520  	if err != nil {
   521  		t.Fatal(err)
   522  	}
   523  	if info.Mode() != os.FileMode(os.ModeDir|0710) {
   524  		t.Errorf("/a/b/c/d/e/f: wrong permissions, expected drwx--x---, got %s", info.Mode())
   525  	}
   526  }
   527  
   528  func TestMemFsDirMode(t *testing.T) {
   529  	fs := NewMemMapFs()
   530  	err := fs.Mkdir("/testDir1", 0644)
   531  	if err != nil {
   532  		t.Error(err)
   533  	}
   534  	err = fs.MkdirAll("/sub/testDir2", 0644)
   535  	if err != nil {
   536  		t.Error(err)
   537  	}
   538  	info, err := fs.Stat("/testDir1")
   539  	if err != nil {
   540  		t.Error(err)
   541  	}
   542  	if !info.IsDir() {
   543  		t.Error("should be a directory")
   544  	}
   545  	if !info.Mode().IsDir() {
   546  		t.Error("FileMode is not directory")
   547  	}
   548  	info, err = fs.Stat("/sub/testDir2")
   549  	if err != nil {
   550  		t.Error(err)
   551  	}
   552  	if !info.IsDir() {
   553  		t.Error("should be a directory")
   554  	}
   555  	if !info.Mode().IsDir() {
   556  		t.Error("FileMode is not directory")
   557  	}
   558  }
   559  
   560  func TestMemFsUnexpectedEOF(t *testing.T) {
   561  	t.Parallel()
   562  
   563  	fs := NewMemMapFs()
   564  
   565  	if err := WriteFile(fs, "file.txt", []byte("abc"), 0777); err != nil {
   566  		t.Fatal(err)
   567  	}
   568  
   569  	f, err := fs.Open("file.txt")
   570  	if err != nil {
   571  		t.Fatal(err)
   572  	}
   573  	defer f.Close()
   574  
   575  	// Seek beyond the end.
   576  	_, err = f.Seek(512, 0)
   577  	if err != nil {
   578  		t.Fatal(err)
   579  	}
   580  
   581  	buff := make([]byte, 256)
   582  	_, err = io.ReadAtLeast(f, buff, 256)
   583  
   584  	if err != io.ErrUnexpectedEOF {
   585  		t.Fatal("Expected ErrUnexpectedEOF")
   586  	}
   587  }
   588  
   589  func TestMemFsChmod(t *testing.T) {
   590  	t.Parallel()
   591  
   592  	fs := NewMemMapFs()
   593  	const file = "hello"
   594  	if err := fs.Mkdir(file, 0700); err != nil {
   595  		t.Fatal(err)
   596  	}
   597  
   598  	info, err := fs.Stat(file)
   599  	if err != nil {
   600  		t.Fatal(err)
   601  	}
   602  	if info.Mode().String() != "drwx------" {
   603  		t.Fatal("mkdir failed to create a directory: mode =", info.Mode())
   604  	}
   605  
   606  	err = fs.Chmod(file, 0)
   607  	if err != nil {
   608  		t.Error("Failed to run chmod:", err)
   609  	}
   610  
   611  	info, err = fs.Stat(file)
   612  	if err != nil {
   613  		t.Fatal(err)
   614  	}
   615  	if info.Mode().String() != "d---------" {
   616  		t.Error("chmod should not change file type. New mode =", info.Mode())
   617  	}
   618  }
   619  
   620  // can't use Mkdir to get around which permissions we're allowed to set
   621  func TestMemFsMkdirModeIllegal(t *testing.T) {
   622  	t.Parallel()
   623  
   624  	fs := NewMemMapFs()
   625  	err := fs.Mkdir("/a", os.ModeSocket|0755)
   626  	if err != nil {
   627  		t.Fatal(err)
   628  	}
   629  	info, err := fs.Stat("/a")
   630  	if err != nil {
   631  		t.Fatal(err)
   632  	}
   633  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   634  		t.Fatalf("should not be able to use Mkdir to set illegal mode: %s", info.Mode().String())
   635  	}
   636  }
   637  
   638  // can't use OpenFile to get around which permissions we're allowed to set
   639  func TestMemFsOpenFileModeIllegal(t *testing.T) {
   640  	t.Parallel()
   641  
   642  	fs := NewMemMapFs()
   643  	file, err := fs.OpenFile("/a", os.O_CREATE, os.ModeSymlink|0644)
   644  	if err != nil {
   645  		t.Fatal(err)
   646  	}
   647  	defer file.Close()
   648  	info, err := fs.Stat("/a")
   649  	if err != nil {
   650  		t.Fatal(err)
   651  	}
   652  	if info.Mode() != os.FileMode(0644) {
   653  		t.Fatalf("should not be able to use OpenFile to set illegal mode: %s", info.Mode().String())
   654  	}
   655  }
   656  
   657  // LstatIfPossible should always return false, since MemMapFs does not
   658  // support symlinks.
   659  func TestMemFsLstatIfPossible(t *testing.T) {
   660  	t.Parallel()
   661  
   662  	fs := NewMemMapFs()
   663  
   664  	// We assert that fs implements Lstater
   665  	fsAsserted, ok := fs.(Lstater)
   666  	require.True(t, ok, "The filesytem does not implement Lstater")
   667  
   668  	file, err := fs.OpenFile("/a.txt", os.O_CREATE, 0o644)
   669  	require.NoError(t, err)
   670  	defer file.Close()
   671  
   672  	_, lstatCalled, err := fsAsserted.LstatIfPossible("/a.txt")
   673  	assert.NoError(t, err)
   674  	assert.False(t, lstatCalled)
   675  }