github.com/prysmaticlabs/prysm@v1.4.4/shared/fileutil/fileutil_test.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  package fileutil_test
    17  
    18  import (
    19  	"bufio"
    20  	"bytes"
    21  	"io/ioutil"
    22  	"os"
    23  	"os/user"
    24  	"path/filepath"
    25  	"sort"
    26  	"testing"
    27  
    28  	"github.com/prysmaticlabs/prysm/shared/fileutil"
    29  	"github.com/prysmaticlabs/prysm/shared/params"
    30  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    31  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    32  )
    33  
    34  func TestPathExpansion(t *testing.T) {
    35  	user, err := user.Current()
    36  	require.NoError(t, err)
    37  	tests := map[string]string{
    38  		"/home/someuser/tmp": "/home/someuser/tmp",
    39  		"~/tmp":              user.HomeDir + "/tmp",
    40  		"$DDDXXX/a/b":        "/tmp/a/b",
    41  		"/a/b/":              "/a/b",
    42  	}
    43  	require.NoError(t, os.Setenv("DDDXXX", "/tmp"))
    44  	for test, expected := range tests {
    45  		expanded, err := fileutil.ExpandPath(test)
    46  		require.NoError(t, err)
    47  		assert.Equal(t, expected, expanded)
    48  	}
    49  }
    50  
    51  func TestMkdirAll_AlreadyExists_WrongPermissions(t *testing.T) {
    52  	dirName := t.TempDir() + "somedir"
    53  	err := os.MkdirAll(dirName, os.ModePerm)
    54  	require.NoError(t, err)
    55  	err = fileutil.MkdirAll(dirName)
    56  	assert.ErrorContains(t, "already exists without proper 0700 permissions", err)
    57  }
    58  
    59  func TestMkdirAll_AlreadyExists_Override(t *testing.T) {
    60  	dirName := t.TempDir() + "somedir"
    61  	err := os.MkdirAll(dirName, params.BeaconIoConfig().ReadWriteExecutePermissions)
    62  	require.NoError(t, err)
    63  	assert.NoError(t, fileutil.MkdirAll(dirName))
    64  }
    65  
    66  func TestHandleBackupDir_AlreadyExists_Override(t *testing.T) {
    67  	dirName := t.TempDir() + "somedir"
    68  	err := os.MkdirAll(dirName, os.ModePerm)
    69  	require.NoError(t, err)
    70  	info, err := os.Stat(dirName)
    71  	require.NoError(t, err)
    72  	assert.Equal(t, "drwxr-xr-x", info.Mode().String())
    73  	assert.NoError(t, fileutil.HandleBackupDir(dirName, true))
    74  	info, err = os.Stat(dirName)
    75  	require.NoError(t, err)
    76  	assert.Equal(t, "drwx------", info.Mode().String())
    77  }
    78  
    79  func TestHandleBackupDir_AlreadyExists_No_Override(t *testing.T) {
    80  	dirName := t.TempDir() + "somedir"
    81  	err := os.MkdirAll(dirName, os.ModePerm)
    82  	require.NoError(t, err)
    83  	info, err := os.Stat(dirName)
    84  	require.NoError(t, err)
    85  	assert.Equal(t, "drwxr-xr-x", info.Mode().String())
    86  	err = fileutil.HandleBackupDir(dirName, false)
    87  	assert.ErrorContains(t, "dir already exists without proper 0700 permissions", err)
    88  	info, err = os.Stat(dirName)
    89  	require.NoError(t, err)
    90  	assert.Equal(t, "drwxr-xr-x", info.Mode().String())
    91  }
    92  
    93  func TestHandleBackupDir_NewDir(t *testing.T) {
    94  	dirName := t.TempDir() + "somedir"
    95  	require.NoError(t, fileutil.HandleBackupDir(dirName, true))
    96  	info, err := os.Stat(dirName)
    97  	require.NoError(t, err)
    98  	assert.Equal(t, "drwx------", info.Mode().String())
    99  }
   100  
   101  func TestMkdirAll_OK(t *testing.T) {
   102  	dirName := t.TempDir() + "somedir"
   103  	err := fileutil.MkdirAll(dirName)
   104  	assert.NoError(t, err)
   105  	exists, err := fileutil.HasDir(dirName)
   106  	require.NoError(t, err)
   107  	assert.Equal(t, true, exists)
   108  }
   109  
   110  func TestWriteFile_AlreadyExists_WrongPermissions(t *testing.T) {
   111  	dirName := t.TempDir() + "somedir"
   112  	err := os.MkdirAll(dirName, os.ModePerm)
   113  	require.NoError(t, err)
   114  	someFileName := filepath.Join(dirName, "somefile.txt")
   115  	require.NoError(t, ioutil.WriteFile(someFileName, []byte("hi"), os.ModePerm))
   116  	err = fileutil.WriteFile(someFileName, []byte("hi"))
   117  	assert.ErrorContains(t, "already exists without proper 0600 permissions", err)
   118  }
   119  
   120  func TestWriteFile_AlreadyExists_OK(t *testing.T) {
   121  	dirName := t.TempDir() + "somedir"
   122  	err := os.MkdirAll(dirName, os.ModePerm)
   123  	require.NoError(t, err)
   124  	someFileName := filepath.Join(dirName, "somefile.txt")
   125  	require.NoError(t, ioutil.WriteFile(someFileName, []byte("hi"), params.BeaconIoConfig().ReadWritePermissions))
   126  	assert.NoError(t, fileutil.WriteFile(someFileName, []byte("hi")))
   127  }
   128  
   129  func TestWriteFile_OK(t *testing.T) {
   130  	dirName := t.TempDir() + "somedir"
   131  	err := os.MkdirAll(dirName, os.ModePerm)
   132  	require.NoError(t, err)
   133  	someFileName := filepath.Join(dirName, "somefile.txt")
   134  	require.NoError(t, fileutil.WriteFile(someFileName, []byte("hi")))
   135  	exists := fileutil.FileExists(someFileName)
   136  	assert.Equal(t, true, exists)
   137  }
   138  
   139  func TestCopyFile(t *testing.T) {
   140  	fName := t.TempDir() + "testfile"
   141  	err := ioutil.WriteFile(fName, []byte{1, 2, 3}, params.BeaconIoConfig().ReadWritePermissions)
   142  	require.NoError(t, err)
   143  
   144  	err = fileutil.CopyFile(fName, fName+"copy")
   145  	assert.NoError(t, err)
   146  	defer func() {
   147  		assert.NoError(t, os.Remove(fName+"copy"))
   148  	}()
   149  
   150  	assert.Equal(t, true, deepCompare(t, fName, fName+"copy"))
   151  }
   152  
   153  func TestCopyDir(t *testing.T) {
   154  	tmpDir1 := t.TempDir()
   155  	tmpDir2 := filepath.Join(t.TempDir(), "copyfolder")
   156  	type fileDesc struct {
   157  		path    string
   158  		content []byte
   159  	}
   160  	fds := []fileDesc{
   161  		{
   162  			path:    "testfile1",
   163  			content: []byte{1, 2, 3},
   164  		},
   165  		{
   166  			path:    "subfolder1/testfile1",
   167  			content: []byte{4, 5, 6},
   168  		},
   169  		{
   170  			path:    "subfolder1/testfile2",
   171  			content: []byte{7, 8, 9},
   172  		},
   173  		{
   174  			path:    "subfolder2/testfile1",
   175  			content: []byte{10, 11, 12},
   176  		},
   177  		{
   178  			path:    "testfile2",
   179  			content: []byte{13, 14, 15},
   180  		},
   181  	}
   182  	require.NoError(t, os.MkdirAll(filepath.Join(tmpDir1, "subfolder1"), 0777))
   183  	require.NoError(t, os.MkdirAll(filepath.Join(tmpDir1, "subfolder2"), 0777))
   184  	for _, fd := range fds {
   185  		require.NoError(t, fileutil.WriteFile(filepath.Join(tmpDir1, fd.path), fd.content))
   186  		assert.Equal(t, true, fileutil.FileExists(filepath.Join(tmpDir1, fd.path)))
   187  		assert.Equal(t, false, fileutil.FileExists(filepath.Join(tmpDir2, fd.path)))
   188  	}
   189  
   190  	// Make sure that files are copied into non-existent directory only. If directory exists function exits.
   191  	assert.ErrorContains(t, "destination directory already exists", fileutil.CopyDir(tmpDir1, t.TempDir()))
   192  	require.NoError(t, fileutil.CopyDir(tmpDir1, tmpDir2))
   193  
   194  	// Now, all files should have been copied.
   195  	for _, fd := range fds {
   196  		assert.Equal(t, true, fileutil.FileExists(filepath.Join(tmpDir2, fd.path)))
   197  		assert.Equal(t, true, deepCompare(t, filepath.Join(tmpDir1, fd.path), filepath.Join(tmpDir2, fd.path)))
   198  	}
   199  	assert.Equal(t, true, fileutil.DirsEqual(tmpDir1, tmpDir2))
   200  }
   201  
   202  func TestDirsEqual(t *testing.T) {
   203  	t.Run("non-existent source directory", func(t *testing.T) {
   204  		assert.Equal(t, false, fileutil.DirsEqual(filepath.Join(t.TempDir(), "nonexistent"), t.TempDir()))
   205  	})
   206  
   207  	t.Run("non-existent dest directory", func(t *testing.T) {
   208  		assert.Equal(t, false, fileutil.DirsEqual(t.TempDir(), filepath.Join(t.TempDir(), "nonexistent")))
   209  	})
   210  
   211  	t.Run("non-empty directory", func(t *testing.T) {
   212  		// Start with directories that do not have the same contents.
   213  		tmpDir1, tmpFileNames := tmpDirWithContents(t)
   214  		tmpDir2 := filepath.Join(t.TempDir(), "newfolder")
   215  		assert.Equal(t, false, fileutil.DirsEqual(tmpDir1, tmpDir2))
   216  
   217  		// Copy dir, and retest (hashes should match now).
   218  		require.NoError(t, fileutil.CopyDir(tmpDir1, tmpDir2))
   219  		assert.Equal(t, true, fileutil.DirsEqual(tmpDir1, tmpDir2))
   220  
   221  		// Tamper the data, make sure that hashes do not match anymore.
   222  		require.NoError(t, os.Remove(filepath.Join(tmpDir1, tmpFileNames[2])))
   223  		assert.Equal(t, false, fileutil.DirsEqual(tmpDir1, tmpDir2))
   224  	})
   225  }
   226  
   227  func TestHashDir(t *testing.T) {
   228  	t.Run("non-existent directory", func(t *testing.T) {
   229  		hash, err := fileutil.HashDir(filepath.Join(t.TempDir(), "nonexistent"))
   230  		assert.ErrorContains(t, "no such file or directory", err)
   231  		assert.Equal(t, "", hash)
   232  	})
   233  
   234  	t.Run("empty directory", func(t *testing.T) {
   235  		hash, err := fileutil.HashDir(t.TempDir())
   236  		assert.NoError(t, err)
   237  		assert.Equal(t, "hashdir:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=", hash)
   238  	})
   239  
   240  	t.Run("non-empty directory", func(t *testing.T) {
   241  		tmpDir, _ := tmpDirWithContents(t)
   242  		hash, err := fileutil.HashDir(tmpDir)
   243  		assert.NoError(t, err)
   244  		assert.Equal(t, "hashdir:oSp9wRacwTIrnbgJWcwTvihHfv4B2zRbLYa0GZ7DDk0=", hash)
   245  	})
   246  }
   247  
   248  func TestDirFiles(t *testing.T) {
   249  	tmpDir, tmpDirFnames := tmpDirWithContents(t)
   250  	tests := []struct {
   251  		name     string
   252  		path     string
   253  		outFiles []string
   254  	}{
   255  		{
   256  			name:     "dot path",
   257  			path:     filepath.Join(tmpDir, "/./"),
   258  			outFiles: tmpDirFnames,
   259  		},
   260  		{
   261  			name:     "non-empty folder",
   262  			path:     tmpDir,
   263  			outFiles: tmpDirFnames,
   264  		},
   265  	}
   266  
   267  	for _, tt := range tests {
   268  		t.Run(tt.name, func(t *testing.T) {
   269  			outFiles, err := fileutil.DirFiles(tt.path)
   270  			require.NoError(t, err)
   271  
   272  			sort.Strings(outFiles)
   273  			assert.DeepEqual(t, tt.outFiles, outFiles)
   274  		})
   275  	}
   276  }
   277  
   278  func TestRecursiveFileFind(t *testing.T) {
   279  	tmpDir, _ := tmpDirWithContentsForRecursiveFind(t)
   280  	tests := []struct {
   281  		name  string
   282  		root  string
   283  		path  string
   284  		found bool
   285  	}{
   286  		{
   287  			name:  "file1",
   288  			root:  tmpDir,
   289  			path:  "subfolder1/subfolder11/file1",
   290  			found: true,
   291  		},
   292  		{
   293  			name:  "file2",
   294  			root:  tmpDir,
   295  			path:  "subfolder2/file2",
   296  			found: true,
   297  		},
   298  		{
   299  			name:  "file1",
   300  			root:  tmpDir + "/subfolder1",
   301  			path:  "subfolder11/file1",
   302  			found: true,
   303  		},
   304  		{
   305  			name:  "file3",
   306  			root:  tmpDir,
   307  			path:  "file3",
   308  			found: true,
   309  		},
   310  		{
   311  			name:  "file4",
   312  			root:  tmpDir,
   313  			path:  "",
   314  			found: false,
   315  		},
   316  	}
   317  
   318  	for _, tt := range tests {
   319  		t.Run(tt.name, func(t *testing.T) {
   320  			found, _, err := fileutil.RecursiveFileFind(tt.name, tt.root)
   321  			require.NoError(t, err)
   322  
   323  			assert.DeepEqual(t, tt.found, found)
   324  		})
   325  	}
   326  }
   327  
   328  func deepCompare(t *testing.T, file1, file2 string) bool {
   329  	sf, err := os.Open(file1)
   330  	assert.NoError(t, err)
   331  	df, err := os.Open(file2)
   332  	assert.NoError(t, err)
   333  	sscan := bufio.NewScanner(sf)
   334  	dscan := bufio.NewScanner(df)
   335  
   336  	for sscan.Scan() && dscan.Scan() {
   337  		if !bytes.Equal(sscan.Bytes(), dscan.Bytes()) {
   338  			return false
   339  		}
   340  	}
   341  	return true
   342  }
   343  
   344  // tmpDirWithContents returns path to temporary directory having some folders/files in it.
   345  // Directory is automatically removed by internal testing cleanup methods.
   346  func tmpDirWithContents(t *testing.T) (string, []string) {
   347  	dir := t.TempDir()
   348  	fnames := []string{
   349  		"file1",
   350  		"file2",
   351  		"subfolder1/file1",
   352  		"subfolder1/file2",
   353  		"subfolder1/subfolder11/file1",
   354  		"subfolder1/subfolder11/file2",
   355  		"subfolder1/subfolder12/file1",
   356  		"subfolder1/subfolder12/file2",
   357  		"subfolder2/file1",
   358  	}
   359  	require.NoError(t, os.MkdirAll(filepath.Join(dir, "subfolder1", "subfolder11"), 0777))
   360  	require.NoError(t, os.MkdirAll(filepath.Join(dir, "subfolder1", "subfolder12"), 0777))
   361  	require.NoError(t, os.MkdirAll(filepath.Join(dir, "subfolder2"), 0777))
   362  	for _, fname := range fnames {
   363  		require.NoError(t, ioutil.WriteFile(filepath.Join(dir, fname), []byte(fname), 0777))
   364  	}
   365  	sort.Strings(fnames)
   366  	return dir, fnames
   367  }
   368  
   369  // tmpDirWithContentsForRecursiveFind returns path to temporary directory having some folders/files in it.
   370  // Directory is automatically removed by internal testing cleanup methods.
   371  func tmpDirWithContentsForRecursiveFind(t *testing.T) (string, []string) {
   372  	dir := t.TempDir()
   373  	fnames := []string{
   374  		"subfolder1/subfolder11/file1",
   375  		"subfolder2/file2",
   376  		"file3",
   377  	}
   378  	require.NoError(t, os.MkdirAll(filepath.Join(dir, "subfolder1", "subfolder11"), 0777))
   379  	require.NoError(t, os.MkdirAll(filepath.Join(dir, "subfolder2"), 0777))
   380  	for _, fname := range fnames {
   381  		require.NoError(t, ioutil.WriteFile(filepath.Join(dir, fname), []byte(fname), 0777))
   382  	}
   383  	sort.Strings(fnames)
   384  	return dir, fnames
   385  }
   386  
   387  func TestHasReadWritePermissions(t *testing.T) {
   388  	type args struct {
   389  		itemPath string
   390  		perms    os.FileMode
   391  	}
   392  	tests := []struct {
   393  		name    string
   394  		args    args
   395  		want    bool
   396  		wantErr bool
   397  	}{
   398  		{
   399  			name: "0600 permissions returns true",
   400  			args: args{
   401  				itemPath: "somefile",
   402  				perms:    params.BeaconIoConfig().ReadWritePermissions,
   403  			},
   404  			want: true,
   405  		},
   406  		{
   407  			name: "other permissions returns false",
   408  			args: args{
   409  				itemPath: "somefile2",
   410  				perms:    params.BeaconIoConfig().ReadWriteExecutePermissions,
   411  			},
   412  			want: false,
   413  		},
   414  	}
   415  	for _, tt := range tests {
   416  		t.Run(tt.name, func(t *testing.T) {
   417  			fullPath := filepath.Join(os.TempDir(), tt.args.itemPath)
   418  			require.NoError(t, ioutil.WriteFile(fullPath, []byte("foo"), tt.args.perms))
   419  			t.Cleanup(func() {
   420  				if err := os.RemoveAll(fullPath); err != nil {
   421  					t.Fatalf("Could not delete temp dir: %v", err)
   422  				}
   423  			})
   424  			got, err := fileutil.HasReadWritePermissions(fullPath)
   425  			if (err != nil) != tt.wantErr {
   426  				t.Errorf("HasReadWritePermissions() error = %v, wantErr %v", err, tt.wantErr)
   427  				return
   428  			}
   429  			if got != tt.want {
   430  				t.Errorf("HasReadWritePermissions() got = %v, want %v", got, tt.want)
   431  			}
   432  		})
   433  	}
   434  }