From 4e5c22ed8a943ea44fbe9efbe96975b2065f6f51 Mon Sep 17 00:00:00 2001 From: Felicitas Pojtinger Date: Sat, 22 Jan 2022 15:47:19 +0100 Subject: [PATCH] feat; Add tests for symlink behaviour of `RemoveAll` --- pkg/fs/filesystem_test.go | 173 +++++++++++++++++++++++++++++++------- 1 file changed, 141 insertions(+), 32 deletions(-) diff --git a/pkg/fs/filesystem_test.go b/pkg/fs/filesystem_test.go index 4003149..9066446 100644 --- a/pkg/fs/filesystem_test.go +++ b/pkg/fs/filesystem_test.go @@ -2137,54 +2137,54 @@ var removeAllTests = []struct { name string args removeAllArgs wantErr bool - prepare func(afero.Fs) error - check func(afero.Fs) error + prepare func(symFs) error + check func(symFs) error checkAfterError bool }{ { "Can remove /", removeAllArgs{"/"}, false, - func(f afero.Fs) error { return nil }, - func(f afero.Fs) error { return nil }, + func(f symFs) error { return nil }, + func(f symFs) error { return nil }, false, }, { "Can remove ''", removeAllArgs{""}, false, - func(f afero.Fs) error { return nil }, - func(f afero.Fs) error { return nil }, + func(f symFs) error { return nil }, + func(f symFs) error { return nil }, false, }, { "Can not remove ' '", removeAllArgs{" "}, false, - func(f afero.Fs) error { return nil }, - func(f afero.Fs) error { return nil }, + func(f symFs) error { return nil }, + func(f symFs) error { return nil }, false, }, { "Can not remove /test.txt if does not exist", removeAllArgs{"/test.txt"}, false, - func(f afero.Fs) error { return nil }, - func(f afero.Fs) error { return nil }, + func(f symFs) error { return nil }, + func(f symFs) error { return nil }, false, }, { "Can remove /test.txt if does exist", removeAllArgs{"/test.txt"}, false, - func(f afero.Fs) error { + func(f symFs) error { if _, err := f.Create("/test.txt"); err != nil { return err } return nil }, - func(f afero.Fs) error { + func(f symFs) error { if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) { return err } @@ -2197,25 +2197,25 @@ var removeAllTests = []struct { "Can not remove /mydir/test.txt if does not exist", removeAllArgs{"/mydir/test.txt"}, false, - func(f afero.Fs) error { return nil }, - func(f afero.Fs) error { return nil }, + func(f symFs) error { return nil }, + func(f symFs) error { return nil }, false, }, { "Can not remove /mydir/test.txt if does not exist, but the parent exists", removeAllArgs{"/mydir/test.txt"}, false, - func(f afero.Fs) error { + func(f symFs) error { return f.Mkdir("/mydir", os.ModePerm) }, - func(f afero.Fs) error { return nil }, + func(f symFs) error { return nil }, false, }, { "Can remove /mydir/test.txt if does exist", removeAllArgs{"/mydir/test.txt"}, false, - func(f afero.Fs) error { + func(f symFs) error { if err := f.Mkdir("/mydir", os.ModePerm); err != nil { return err } @@ -2226,7 +2226,7 @@ var removeAllTests = []struct { return nil }, - func(f afero.Fs) error { + func(f symFs) error { if _, err := f.Stat("/mydir/test.txt"); !errors.Is(err, os.ErrNotExist) { return err } @@ -2239,14 +2239,14 @@ var removeAllTests = []struct { "Can remove /mydir if it is a directory and empty", removeAllArgs{"/mydir"}, false, - func(f afero.Fs) error { + func(f symFs) error { if err := f.Mkdir("/mydir", os.ModePerm); err != nil { return err } return nil }, - func(f afero.Fs) error { + func(f symFs) error { return nil }, false, @@ -2255,7 +2255,7 @@ var removeAllTests = []struct { "Can not remove /mydir if it is a directory and not empty", removeAllArgs{"/mydir"}, false, - func(f afero.Fs) error { + func(f symFs) error { if err := f.Mkdir("/mydir", os.ModePerm); err != nil { return err } @@ -2266,7 +2266,7 @@ var removeAllTests = []struct { return nil }, - func(f afero.Fs) error { + func(f symFs) error { return nil }, false, @@ -2275,7 +2275,7 @@ var removeAllTests = []struct { "Can not remove /mydir/subdir if it is a directory and not empty", removeAllArgs{"/mydir/subdir"}, false, - func(f afero.Fs) error { + func(f symFs) error { if err := f.Mkdir("/mydir", os.ModePerm); err != nil { return err } @@ -2290,7 +2290,7 @@ var removeAllTests = []struct { return nil }, - func(f afero.Fs) error { + func(f symFs) error { if _, err := f.Stat("/mydir/subdir/test.txt"); !errors.Is(err, os.ErrNotExist) { return err } @@ -2307,7 +2307,7 @@ var removeAllTests = []struct { "Can remove /mydir/subdir if it is a directory and empty", removeAllArgs{"/mydir/subdir"}, false, - func(f afero.Fs) error { + func(f symFs) error { if err := f.Mkdir("/mydir", os.ModePerm); err != nil { return err } @@ -2318,7 +2318,7 @@ var removeAllTests = []struct { return nil }, - func(f afero.Fs) error { + func(f symFs) error { if _, err := f.Stat("/mydir/subdir"); !errors.Is(err, os.ErrNotExist) { return err } @@ -2327,6 +2327,110 @@ var removeAllTests = []struct { }, false, }, + { + "Can remove symlink to root", + removeAllArgs{"/existingsymlink"}, + false, + func(sf symFs) error { + if err := sf.SymlinkIfPossible("/", "/existingsymlink"); err != nil { + return nil + } + + return nil + }, + func(f symFs) error { + if _, _, err := f.LstatIfPossible("/existingsymlink"); !errors.Is(err, os.ErrNotExist) { + return err + } + + if _, err := f.Stat("/"); err != nil { + return err + } + + return nil + }, + false, + }, + { + "Can remove broken symlink to /test.txt", + removeAllArgs{"/brokensymlink"}, + false, + func(sf symFs) error { + if err := sf.SymlinkIfPossible("/test.txt", "/brokensymlink"); err != nil { + return nil + } + + return nil + }, + func(f symFs) error { + if _, _, err := f.LstatIfPossible("/brokensymlink"); !errors.Is(err, os.ErrNotExist) { + return err + } + + return nil + }, + false, + }, + { + "Can remove symlink /existingsymlink to directory without removing the link's target", + removeAllArgs{"/existingsymlink"}, + false, + func(sf symFs) error { + if err := sf.Mkdir("/mydir", os.ModePerm); err != nil { + return err + } + + if err := sf.SymlinkIfPossible("/mydir", "/existingsymlink"); err != nil { + return nil + } + + return nil + }, + func(f symFs) error { + if _, _, err := f.LstatIfPossible("/existingsymlink"); !errors.Is(err, os.ErrNotExist) { + return err + } + + if _, err := f.Stat("/mydir"); err != nil { + return err + } + + return nil + }, + false, + }, + { + "Can remove symlink /existingsymlink to file without removing the link's target", + removeAllArgs{"/existingsymlink"}, + false, + func(sf symFs) error { + file, err := sf.Create("/test.txt") + if err != nil { + return err + } + if err := file.Close(); err != nil { + return err + } + + if err := sf.SymlinkIfPossible("/test.txt", "/existingsymlink"); err != nil { + return nil + } + + return nil + }, + func(f symFs) error { + if _, _, err := f.LstatIfPossible("/existingsymlink"); !errors.Is(err, os.ErrNotExist) { + return err + } + + if _, err := f.Stat("/test.txt"); err != nil { + return err + } + + return nil + }, + false, + }, } func TestSTFS_RemoveAll(t *testing.T) { @@ -2334,22 +2438,27 @@ func TestSTFS_RemoveAll(t *testing.T) { tt := tt runTestForAllFss(t, tt.name, true, true, true, func(t *testing.T, fs fsConfig) { - if err := tt.prepare(fs.fs); err != nil { - t.Errorf("%v prepare() error = %v", fs.fs.Name(), err) + symFs, ok := fs.fs.(symFs) + if !ok { + return + } + + if err := tt.prepare(symFs); err != nil { + t.Errorf("%v prepare() error = %v", symFs.Name(), err) return } - if err := fs.fs.RemoveAll(tt.args.name); (err != nil) != tt.wantErr { + if err := symFs.RemoveAll(tt.args.name); (err != nil) != tt.wantErr { if !tt.checkAfterError { - t.Errorf("%v.RemoveAll() error = %v, wantErr %v", fs.fs.Name(), err, tt.wantErr) + t.Errorf("%v.RemoveAll() error = %v, wantErr %v", symFs.Name(), err, tt.wantErr) return } } - if err := tt.check(fs.fs); err != nil { - t.Errorf("%v check() error = %v", fs.fs.Name(), err) + if err := tt.check(symFs); err != nil { + t.Errorf("%v check() error = %v", symFs.Name(), err) return }