github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/fileutil/io_test.go (about)

     1  package fileutil_test
     2  
     3  import (
     4  	"io/fs"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/require"
    11  	"github.com/treeverse/lakefs/pkg/fileutil"
    12  )
    13  
    14  func TestFindInParents(t *testing.T) {
    15  	root := t.TempDir()
    16  	dirTree := filepath.Join(root, "foo", "bar", "baz", "taz")
    17  	require.NoError(t, os.MkdirAll(dirTree, fileutil.DefaultDirectoryMask))
    18  	t.Run("dir does not exist", func(t *testing.T) {
    19  		found, err := fileutil.FindInParents(filepath.Join(root, "no_dir"), "file")
    20  		require.ErrorIs(t, err, fs.ErrNotExist)
    21  		if found != "" {
    22  			t.Errorf("expected found to be empty, got %v", found)
    23  		}
    24  	})
    25  
    26  	tests := []struct {
    27  		name     string
    28  		deep     string
    29  		filename string
    30  		filepath string
    31  		find     bool
    32  	}{
    33  		{
    34  			name:     "find_at_leaf",
    35  			deep:     filepath.Join(root, "foo", "bar", "baz"),
    36  			filename: "some_file0",
    37  			filepath: filepath.Join(root, "foo", "bar", "baz", "some_file0"),
    38  			find:     true,
    39  		},
    40  		{
    41  			name:     "find_at_root",
    42  			deep:     filepath.Join(root, "foo", "bar", "baz"),
    43  			filename: "some_file1",
    44  			filepath: filepath.Join(root, "some_file1"),
    45  			find:     true,
    46  		},
    47  		{
    48  			name:     "find_at_subpath",
    49  			deep:     filepath.Join(root, "foo", "bar", "baz", "taz"),
    50  			filename: "some_file2",
    51  			filepath: filepath.Join(root, "foo", "some_file2"),
    52  			find:     true,
    53  		},
    54  		{
    55  			name:     "not_found_above",
    56  			deep:     filepath.Join(root, "foo", "bar", "baz"),
    57  			filename: "some_file3",
    58  			filepath: filepath.Join(root, "foo", "bar", "baz", "taz", "some_file3"),
    59  			find:     false,
    60  		},
    61  		{
    62  			name:     "doesnt_exist",
    63  			deep:     filepath.Join(root, "foo", "bar", "baz"),
    64  			filename: ".doesnotexist21348329043289",
    65  			filepath: filepath.Join(root, "foo", "bar", "some_file4"),
    66  			find:     false,
    67  		},
    68  	}
    69  
    70  	for _, tt := range tests {
    71  		t.Run(tt.name, func(t *testing.T) {
    72  			f, err := os.Create(tt.filepath)
    73  			require.NoError(t, err)
    74  			require.NoError(t, f.Close())
    75  
    76  			found, err := fileutil.FindInParents(tt.deep, tt.filename)
    77  			require.NoError(t, err)
    78  			if tt.find {
    79  				require.Equal(t, tt.filepath, found)
    80  			} else {
    81  				require.Equal(t, "", found)
    82  			}
    83  		})
    84  	}
    85  }
    86  
    87  func TestPruneEmptyDirectories(t *testing.T) {
    88  	root := t.TempDir()
    89  
    90  	cases := []struct {
    91  		name     string
    92  		paths    []string
    93  		expected []string
    94  	}{
    95  		{
    96  			name: "prune_deep",
    97  			paths: []string{
    98  				"a/b/",
    99  				"a/b/c.txt",
   100  				"a/d/",
   101  				"a/e/a/b/",
   102  			},
   103  			expected: []string{
   104  				"a/d",
   105  				"a/e",
   106  				"a/e/a",
   107  				"a/e/a/b",
   108  			},
   109  		},
   110  		{
   111  			name: "prune_deep_keep_neighbor",
   112  			paths: []string{
   113  				"a/b/",
   114  				"a/b/c.txt",
   115  				"a/d/",
   116  				"a/e/a/b/",
   117  				"b.txt",
   118  				"c/",
   119  				"c/b.txt",
   120  				"d/a/b/",
   121  			},
   122  			expected: []string{
   123  				"a/d",
   124  				"a/e",
   125  				"a/e/a",
   126  				"a/e/a/b",
   127  				"d",
   128  				"d/a",
   129  				"d/a/b",
   130  			},
   131  		},
   132  		{
   133  			name:     "prune_keep_root",
   134  			paths:    []string{},
   135  			expected: []string{},
   136  		},
   137  		{
   138  			name: "prune_all",
   139  			paths: []string{
   140  				"a/",
   141  				"a/b/",
   142  				"a/b/c/",
   143  				"a/d/",
   144  				"a/e/",
   145  				"a/e/a/",
   146  				"a/e/a/b/",
   147  			},
   148  			expected: []string{
   149  				"a",
   150  				"a/b",
   151  				"a/b/c",
   152  				"a/d",
   153  				"a/e",
   154  				"a/e/a",
   155  				"a/e/a/b",
   156  			},
   157  		},
   158  		{
   159  			name: "nothing_to_prune",
   160  			paths: []string{
   161  				"a/b/",
   162  				"a/b/c.txt",
   163  				"d.txt",
   164  			},
   165  			expected: []string{},
   166  		},
   167  	}
   168  
   169  	for _, tt := range cases {
   170  		t.Run(tt.name, func(t *testing.T) {
   171  			var files []string
   172  
   173  			currentRoot := filepath.Join(root, tt.name)
   174  			require.NoError(t, os.Mkdir(currentRoot, fileutil.DefaultDirectoryMask))
   175  
   176  			// create directory tree
   177  			for _, entry := range tt.paths {
   178  				fullPath := filepath.Join(currentRoot, entry)
   179  				if strings.HasSuffix(entry, string(os.PathSeparator)) {
   180  					// create dir
   181  					require.NoError(t, os.MkdirAll(fullPath, fileutil.DefaultDirectoryMask))
   182  				} else {
   183  					// create file
   184  					f, err := os.Create(fullPath)
   185  					require.NoError(t, err)
   186  					require.NoError(t, f.Close())
   187  					files = append(files, f.Name())
   188  				}
   189  			}
   190  
   191  			// prune
   192  			removedDirs, err := fileutil.PruneEmptyDirectories(currentRoot)
   193  			require.NoError(t, err)
   194  
   195  			// make relative
   196  			removedDirsRel := make([]string, len(removedDirs))
   197  			for i, d := range removedDirs {
   198  				relPath, _ := filepath.Rel(currentRoot, d)
   199  				removedDirsRel[i] = relPath
   200  			}
   201  
   202  			// Verify root
   203  			_, err = fileutil.IsDir(currentRoot)
   204  			require.NoError(t, err)
   205  
   206  			// Compare pruned list
   207  			require.ElementsMatch(t, tt.expected, removedDirsRel)
   208  
   209  			// Verify files
   210  			for _, f := range files {
   211  				_, err = os.ReadFile(f)
   212  				require.NoError(t, err)
   213  			}
   214  		})
   215  	}
   216  }