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 }