feat: Add tests for symlink behaviour of Rename

This commit is contained in:
Felicitas Pojtinger
2022-01-22 16:09:34 +01:00
parent 4e5c22ed8a
commit cd03215610
3 changed files with 199 additions and 44 deletions

View File

@@ -720,10 +720,24 @@ func (f *STFS) Rename(oldname, newname string) error {
) )
if err != nil { if err != nil {
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
return os.ErrNotExist source, err = inventory.Stat(
} f.metadata,
return err oldname,
true,
f.onHeader,
)
if err != nil {
if err == sql.ErrNoRows {
return os.ErrNotExist
} else {
return err
}
}
} else {
return err
}
} }
if _, err := inventory.Stat( if _, err := inventory.Stat(

View File

@@ -2475,8 +2475,8 @@ var renameTests = []struct {
name string name string
args renameArgs args renameArgs
wantErr bool wantErr bool
prepare func(afero.Fs) error prepare func(symFs) error
check func(afero.Fs) error check func(symFs) error
checkAfterError bool checkAfterError bool
withCache bool withCache bool
withOsFs bool withOsFs bool
@@ -2485,8 +2485,8 @@ var renameTests = []struct {
"Can not rename / to /mydir", "Can not rename / to /mydir",
renameArgs{"/", "/mydri"}, renameArgs{"/", "/mydri"},
true, true,
func(f afero.Fs) error { return nil }, func(f symFs) error { return nil },
func(f afero.Fs) error { return nil }, func(f symFs) error { return nil },
false, false,
true, true,
true, true,
@@ -2495,8 +2495,8 @@ var renameTests = []struct {
"Can not rename / to /", "Can not rename / to /",
renameArgs{"/", "/"}, renameArgs{"/", "/"},
true, true,
func(f afero.Fs) error { return nil }, func(f symFs) error { return nil },
func(f afero.Fs) error { return nil }, func(f symFs) error { return nil },
false, false,
true, true,
true, true,
@@ -2505,8 +2505,8 @@ var renameTests = []struct {
"Can not rename '' to ''", "Can not rename '' to ''",
renameArgs{"", ""}, renameArgs{"", ""},
true, true,
func(f afero.Fs) error { return nil }, func(f symFs) error { return nil },
func(f afero.Fs) error { return nil }, func(f symFs) error { return nil },
false, false,
true, true,
true, true,
@@ -2515,8 +2515,8 @@ var renameTests = []struct {
"Can not rename remove ' ' to ' '", "Can not rename remove ' ' to ' '",
renameArgs{" ", " "}, renameArgs{" ", " "},
true, true,
func(f afero.Fs) error { return nil }, func(f symFs) error { return nil },
func(f afero.Fs) error { return nil }, func(f symFs) error { return nil },
false, false,
true, true,
true, true,
@@ -2525,14 +2525,14 @@ var renameTests = []struct {
"Can rename /test.txt to /new.txt if does exist", "Can rename /test.txt to /new.txt if does exist",
renameArgs{"/test.txt", "/new.txt"}, renameArgs{"/test.txt", "/new.txt"},
false, false,
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Create("/test.txt"); err != nil { if _, err := f.Create("/test.txt"); err != nil {
return err return err
} }
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) { if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) {
return err return err
} }
@@ -2559,10 +2559,10 @@ var renameTests = []struct {
"Can not rename /test.txt to /new.txt if does exist", "Can not rename /test.txt to /new.txt if does exist",
renameArgs{"/test.txt", "/new.txt"}, renameArgs{"/test.txt", "/new.txt"},
true, true,
func(f afero.Fs) error { func(f symFs) error {
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Stat("/new.txt"); !errors.Is(err, os.ErrNotExist) { if _, err := f.Stat("/new.txt"); !errors.Is(err, os.ErrNotExist) {
return err return err
} }
@@ -2577,14 +2577,14 @@ var renameTests = []struct {
"Can move empty directory /myolddir to /mydir", "Can move empty directory /myolddir to /mydir",
renameArgs{"/myolddir", "/mydir"}, renameArgs{"/myolddir", "/mydir"},
false, false,
func(f afero.Fs) error { func(f symFs) error {
if err := f.Mkdir("/myolddir", os.ModePerm); err != nil { if err := f.Mkdir("/myolddir", os.ModePerm); err != nil {
return err return err
} }
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Stat("/mydir"); !errors.Is(err, os.ErrNotExist) { if _, err := f.Stat("/mydir"); !errors.Is(err, os.ErrNotExist) {
return err return err
} }
@@ -2599,7 +2599,7 @@ var renameTests = []struct {
"Can move non-empty directory /myolddir to /mydir", "Can move non-empty directory /myolddir to /mydir",
renameArgs{"/myolddir", "/mydir"}, renameArgs{"/myolddir", "/mydir"},
false, false,
func(f afero.Fs) error { func(f symFs) error {
if err := f.Mkdir("/myolddir", os.ModePerm); err != nil { if err := f.Mkdir("/myolddir", os.ModePerm); err != nil {
return err return err
} }
@@ -2610,7 +2610,7 @@ var renameTests = []struct {
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Stat("/mydir"); !errors.Is(err, os.ErrNotExist) { if _, err := f.Stat("/mydir"); !errors.Is(err, os.ErrNotExist) {
return err return err
} }
@@ -2625,14 +2625,14 @@ var renameTests = []struct {
"Can not rename /test.txt to /mydir/new.txt if new parent drectory does not exist", "Can not rename /test.txt to /mydir/new.txt if new parent drectory does not exist",
renameArgs{"/test.txt", "/mydir/new.txt"}, renameArgs{"/test.txt", "/mydir/new.txt"},
true, true,
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Create("/test.txt"); err != nil { if _, err := f.Create("/test.txt"); err != nil {
return err return err
} }
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Stat("/mydir/new.txt"); !errors.Is(err, os.ErrNotExist) { if _, err := f.Stat("/mydir/new.txt"); !errors.Is(err, os.ErrNotExist) {
return err return err
} }
@@ -2647,7 +2647,7 @@ var renameTests = []struct {
"Can rename /test.txt to /mydir/new.txt if new parent drectory does exist", "Can rename /test.txt to /mydir/new.txt if new parent drectory does exist",
renameArgs{"/test.txt", "/mydir/new.txt"}, renameArgs{"/test.txt", "/mydir/new.txt"},
false, false,
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Create("/test.txt"); err != nil { if _, err := f.Create("/test.txt"); err != nil {
return err return err
} }
@@ -2658,7 +2658,7 @@ var renameTests = []struct {
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) { if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) {
return err return err
} }
@@ -2685,14 +2685,14 @@ var renameTests = []struct {
"Can rename /test.txt to /test.txt if does exist", "Can rename /test.txt to /test.txt if does exist",
renameArgs{"/test.txt", "/test.txt"}, renameArgs{"/test.txt", "/test.txt"},
false, false,
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Create("/test.txt"); err != nil { if _, err := f.Create("/test.txt"); err != nil {
return err return err
} }
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) { if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) {
return err return err
} }
@@ -2707,10 +2707,10 @@ var renameTests = []struct {
"Can not rename move /test.txt to /test.txt if does not exist", "Can not rename move /test.txt to /test.txt if does not exist",
renameArgs{"/test.txt", "/test.txt"}, renameArgs{"/test.txt", "/test.txt"},
true, true,
func(f afero.Fs) error { func(f symFs) error {
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) { if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) {
return err return err
} }
@@ -2725,7 +2725,7 @@ var renameTests = []struct {
"Can rename /test.txt to /existing.txt if source and target both exist", "Can rename /test.txt to /existing.txt if source and target both exist",
renameArgs{"/test.txt", "/existing.txt"}, renameArgs{"/test.txt", "/existing.txt"},
false, false,
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Create("/test.txt"); err != nil { if _, err := f.Create("/test.txt"); err != nil {
return err return err
} }
@@ -2736,7 +2736,7 @@ var renameTests = []struct {
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) { if _, err := f.Stat("/test.txt"); !errors.Is(err, os.ErrNotExist) {
return err return err
} }
@@ -2755,7 +2755,7 @@ var renameTests = []struct {
"Can not rename /test.txt to /mydir if source is file and target is directory", "Can not rename /test.txt to /mydir if source is file and target is directory",
renameArgs{"/test.txt", "/mydir"}, renameArgs{"/test.txt", "/mydir"},
true, true,
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Create("/test.txt"); err != nil { if _, err := f.Create("/test.txt"); err != nil {
return err return err
} }
@@ -2766,7 +2766,7 @@ var renameTests = []struct {
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
return nil return nil
}, },
false, false,
@@ -2777,7 +2777,7 @@ var renameTests = []struct {
"Can not rename /mydir to /test.txt if source is directory and target is file", "Can not rename /mydir to /test.txt if source is directory and target is file",
renameArgs{"/mydir", "/test.txt"}, renameArgs{"/mydir", "/test.txt"},
true, true,
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Create("/test.txt"); err != nil { if _, err := f.Create("/test.txt"); err != nil {
return err return err
} }
@@ -2788,7 +2788,7 @@ var renameTests = []struct {
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
return nil return nil
}, },
false, false,
@@ -2799,14 +2799,142 @@ var renameTests = []struct {
"Can rename /test.txt to /test.txt/", "Can rename /test.txt to /test.txt/",
renameArgs{"/test.txt", "/test.txt/"}, renameArgs{"/test.txt", "/test.txt/"},
false, false,
func(f afero.Fs) error { func(f symFs) error {
if _, err := f.Create("/test.txt"); err != nil { if _, err := f.Create("/test.txt"); err != nil {
return err return err
} }
return nil return nil
}, },
func(f afero.Fs) error { func(f symFs) error {
return nil
},
false,
true,
true,
},
{
"Can rename symlink /existingsymlink to root to /newexistingsymlink",
renameArgs{"/existingsymlink", "/newexistingsymlink"},
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
}
if _, _, err := f.LstatIfPossible("/newexistingsymlink"); err != nil {
return err
}
return nil
},
false,
true,
true,
},
{
"Can rename broken symlink /brokensymlink to /test.txt to /newbrokensymlink",
renameArgs{"/brokensymlink", "/newbrokensymlink"},
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
}
if _, _, err := f.LstatIfPossible("/newbrokensymlink"); err != nil {
return err
}
return nil
},
false,
true,
true,
},
{
"Can rename symlink /existingsymlink to directory to /newexistingsymlink without removing the link's target",
renameArgs{"/existingsymlink", "/newexistingsymlink"},
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
}
if _, _, err := f.LstatIfPossible("/newexistingsymlink"); err != nil {
return err
}
return nil
},
false,
true,
true,
},
{
"Can rename symlink /existingsymlink to file to /newexistingsymlink without removing the link's target",
renameArgs{"/existingsymlink", "/newexistingsymlink"},
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
}
if _, _, err := f.LstatIfPossible("/newexistingsymlink"); err != nil {
return err
}
return nil return nil
}, },
false, false,
@@ -2820,22 +2948,27 @@ func TestSTFS_Rename(t *testing.T) {
tt := tt tt := tt
runTestForAllFss(t, tt.name, true, tt.withCache, tt.withOsFs, func(t *testing.T, fs fsConfig) { runTestForAllFss(t, tt.name, true, tt.withCache, tt.withOsFs, func(t *testing.T, fs fsConfig) {
if err := tt.prepare(fs.fs); err != nil { symFs, ok := fs.fs.(symFs)
t.Errorf("%v prepare() error = %v", fs.fs.Name(), err) if !ok {
return
}
if err := tt.prepare(symFs); err != nil {
t.Errorf("%v prepare() error = %v", symFs.Name(), err)
return return
} }
if err := fs.fs.Rename(tt.args.oldname, tt.args.newname); (err != nil) != tt.wantErr { if err := symFs.Rename(tt.args.oldname, tt.args.newname); (err != nil) != tt.wantErr {
if !tt.checkAfterError { if !tt.checkAfterError {
t.Errorf("%v.Rename() error = %v, wantErr %v", fs.fs.Name(), err, tt.wantErr) t.Errorf("%v.Rename() error = %v, wantErr %v", symFs.Name(), err, tt.wantErr)
return return
} }
} }
if err := tt.check(fs.fs); err != nil { if err := tt.check(symFs); err != nil {
t.Errorf("%v check() error = %v", fs.fs.Name(), err) t.Errorf("%v check() error = %v", symFs.Name(), err)
return return
} }

View File

@@ -3,6 +3,7 @@ package operations
import ( import (
"archive/tar" "archive/tar"
"context" "context"
"database/sql"
"path" "path"
"path/filepath" "path/filepath"
"strings" "strings"
@@ -46,7 +47,14 @@ func (o *Operations) Move(from string, to string) error {
headersToMove := []*config.Header{} headersToMove := []*config.Header{}
dbhdr, err := o.metadata.Metadata.GetHeader(context.Background(), from) dbhdr, err := o.metadata.Metadata.GetHeader(context.Background(), from)
if err != nil { if err != nil {
return err if err == sql.ErrNoRows {
dbhdr, err = o.metadata.Metadata.GetHeaderByLinkname(context.Background(), from)
if err != nil {
return err
}
} else {
return err
}
} }
headersToMove = append(headersToMove, dbhdr) headersToMove = append(headersToMove, dbhdr)