Add more tests for List() and fix resulting problems
This commit is contained in:
parent
68ec6a9f5b
commit
c2d0e86431
19 changed files with 369 additions and 137 deletions
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
53
b2/b2.go
53
b2/b2.go
|
@ -329,6 +329,34 @@ func (f *Fs) NewFsObject(remote string) fs.Object {
|
||||||
return f.newFsObjectWithInfo(remote, nil)
|
return f.newFsObjectWithInfo(remote, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendDir works out given a lastDir and a remote which directories should be sent
|
||||||
|
func sendDir(lastDir string, remote string, level int) (dirNames []string, newLastDir string) {
|
||||||
|
dir := path.Dir(remote)
|
||||||
|
if dir == "." {
|
||||||
|
// No slashes - nothing to do!
|
||||||
|
return nil, lastDir
|
||||||
|
}
|
||||||
|
if dir == lastDir {
|
||||||
|
// Still in same directory
|
||||||
|
return nil, lastDir
|
||||||
|
}
|
||||||
|
newLastDir = lastDir
|
||||||
|
for {
|
||||||
|
slashes := strings.Count(dir, "/")
|
||||||
|
if !strings.HasPrefix(lastDir, dir) && slashes < level {
|
||||||
|
dirNames = append([]string{dir}, dirNames...)
|
||||||
|
}
|
||||||
|
if newLastDir == lastDir {
|
||||||
|
newLastDir = dir
|
||||||
|
}
|
||||||
|
dir = path.Dir(dir)
|
||||||
|
if dir == "." {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dirNames, newLastDir
|
||||||
|
}
|
||||||
|
|
||||||
// listFn is called from list to handle an object
|
// listFn is called from list to handle an object
|
||||||
type listFn func(remote string, object *api.File, isDirectory bool) error
|
type listFn func(remote string, object *api.File, isDirectory bool) error
|
||||||
|
|
||||||
|
@ -377,7 +405,7 @@ func (f *Fs) list(dir string, level int, prefix string, limit int, hidden bool,
|
||||||
if hidden {
|
if hidden {
|
||||||
opts.Path = "/b2_list_file_versions"
|
opts.Path = "/b2_list_file_versions"
|
||||||
}
|
}
|
||||||
lastDir := ""
|
lastDir := dir
|
||||||
for {
|
for {
|
||||||
err := f.pacer.Call(func() (bool, error) {
|
err := f.pacer.Call(func() (bool, error) {
|
||||||
resp, err := f.srv.CallJSON(&opts, &request, &response)
|
resp, err := f.srv.CallJSON(&opts, &request, &response)
|
||||||
|
@ -395,24 +423,21 @@ func (f *Fs) list(dir string, level int, prefix string, limit int, hidden bool,
|
||||||
remote := file.Name[len(f.root):]
|
remote := file.Name[len(f.root):]
|
||||||
slashes := strings.Count(remote, "/")
|
slashes := strings.Count(remote, "/")
|
||||||
|
|
||||||
// Check if this file makes a new directory
|
// Check if this file makes a new directories
|
||||||
if slash := strings.IndexRune(remote, '/'); slash >= 0 {
|
var dirNames []string
|
||||||
if dir := remote[:slash]; dir != lastDir {
|
dirNames, lastDir = sendDir(lastDir, remote, level)
|
||||||
if slashes-1 < fs.MaxLevel {
|
for _, dirName := range dirNames {
|
||||||
err = fn(dir, nil, true)
|
err = fn(dirName, nil, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errEndList {
|
if err == errEndList {
|
||||||
return nil
|
return nil
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
lastDir = dir
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the file
|
// Send the file
|
||||||
if slashes < fs.MaxLevel {
|
if slashes < level {
|
||||||
err = fn(remote, file, false)
|
err = fn(remote, file, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errEndList {
|
if err == errEndList {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ncw/rclone/fstest"
|
"github.com/ncw/rclone/fstest"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Test b2 string encoding
|
// Test b2 string encoding
|
||||||
|
@ -168,3 +169,116 @@ func TestParseTimeString(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSendDir(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
lastDir string
|
||||||
|
remote string
|
||||||
|
level int
|
||||||
|
dirNames []string
|
||||||
|
newLastDir string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
lastDir: "",
|
||||||
|
remote: "test.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: nil,
|
||||||
|
newLastDir: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "",
|
||||||
|
remote: "potato/test.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: []string{"potato"},
|
||||||
|
newLastDir: "potato",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "potato",
|
||||||
|
remote: "potato/test.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: nil,
|
||||||
|
newLastDir: "potato",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "",
|
||||||
|
remote: "potato/sausage/test.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: []string{"potato", "potato/sausage"},
|
||||||
|
newLastDir: "potato/sausage",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "potato",
|
||||||
|
remote: "potato/sausage/test.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: []string{"potato/sausage"},
|
||||||
|
newLastDir: "potato/sausage",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "potato/sausage",
|
||||||
|
remote: "potato/sausage/test.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: nil,
|
||||||
|
newLastDir: "potato/sausage",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "",
|
||||||
|
remote: "a/b/c/d/e/f.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: []string{"a", "a/b", "a/b/c", "a/b/c/d", "a/b/c/d/e"},
|
||||||
|
newLastDir: "a/b/c/d/e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "a/b/c/d/e",
|
||||||
|
remote: "a/b/c/d/E/f.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: []string{"a/b/c/d/E"},
|
||||||
|
newLastDir: "a/b/c/d/E",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "a/b/c/d/e",
|
||||||
|
remote: "a/b/C/D/E/f.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: []string{"a/b/C", "a/b/C/D", "a/b/C/D/E"},
|
||||||
|
newLastDir: "a/b/C/D/E",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "a/b/c",
|
||||||
|
remote: "a/b/c/d/e/f.txt",
|
||||||
|
level: 100,
|
||||||
|
dirNames: []string{"a/b/c/d", "a/b/c/d/e"},
|
||||||
|
newLastDir: "a/b/c/d/e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "",
|
||||||
|
remote: "a/b/c/d/e/f.txt",
|
||||||
|
level: 1,
|
||||||
|
dirNames: []string{"a"},
|
||||||
|
newLastDir: "a/b/c/d/e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "a/b/c",
|
||||||
|
remote: "a/b/c/d/e/f.txt",
|
||||||
|
level: 1,
|
||||||
|
dirNames: nil,
|
||||||
|
newLastDir: "a/b/c/d/e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "",
|
||||||
|
remote: "a/b/c/d/e/f.txt",
|
||||||
|
level: 3,
|
||||||
|
dirNames: []string{"a", "a/b", "a/b/c"},
|
||||||
|
newLastDir: "a/b/c/d/e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
lastDir: "a/b/C/D/E",
|
||||||
|
remote: "a/b/c/d/e/f.txt",
|
||||||
|
level: 3,
|
||||||
|
dirNames: []string{"a/b/c"},
|
||||||
|
newLastDir: "a/b/c/d/e",
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
dirNames, newLastDir := sendDir(test.lastDir, test.remote, test.level)
|
||||||
|
assert.Equal(t, test.dirNames, dirNames, "dirNames fail for sendDir(%q,%q,%v)", test.lastDir, test.remote, test.level)
|
||||||
|
assert.Equal(t, test.newLastDir, newLastDir, "newLastDir fail for sendDir(%q,%q,%v)", test.lastDir, test.remote, test.level)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
|
@ -462,7 +462,7 @@ func (f *Fs) ListDir(out fs.ListOpts, job dircache.ListDirJob) (jobs []dircache.
|
||||||
case item.MimeType == driveFolderType:
|
case item.MimeType == driveFolderType:
|
||||||
if out.IncludeDirectory(remote) {
|
if out.IncludeDirectory(remote) {
|
||||||
dir := &fs.Dir{
|
dir := &fs.Dir{
|
||||||
Name: item.Title,
|
Name: remote,
|
||||||
Bytes: -1,
|
Bytes: -1,
|
||||||
Count: -1,
|
Count: -1,
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
|
@ -226,12 +226,25 @@ func (f *Fs) NewFsObject(remote string) fs.Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Strips the root off path and returns it
|
// Strips the root off path and returns it
|
||||||
func (f *Fs) stripRoot(path string) (string, error) {
|
func strip(path, root string) (string, error) {
|
||||||
lowercase := strings.ToLower(path)
|
if len(root) > 0 {
|
||||||
if !strings.HasPrefix(lowercase, f.slashRootSlash) {
|
if root[0] != '/' {
|
||||||
return "", fmt.Errorf("Path %q is not under root %q", path, f.slashRootSlash)
|
root = "/" + root
|
||||||
|
}
|
||||||
|
if root[len(root)-1] != '/' {
|
||||||
|
root += "/"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return path[len(f.slashRootSlash):], nil
|
lowercase := strings.ToLower(path)
|
||||||
|
if !strings.HasPrefix(lowercase, root) {
|
||||||
|
return "", fmt.Errorf("Path %q is not under root %q", path, root)
|
||||||
|
}
|
||||||
|
return path[len(root):], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strips the root off path and returns it
|
||||||
|
func (f *Fs) stripRoot(path string) (string, error) {
|
||||||
|
return strip(path, f.slashRootSlash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk the root returning a channel of FsObjects
|
// Walk the root returning a channel of FsObjects
|
||||||
|
@ -252,81 +265,80 @@ func (f *Fs) list(out fs.ListOpts, dir string) {
|
||||||
for {
|
for {
|
||||||
deltaPage, err := f.db.Delta(cursor, root)
|
deltaPage, err := f.db.Delta(cursor, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
out.SetError(fmt.Errorf("Couldn't list: %s", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if deltaPage.Reset && cursor != "" {
|
||||||
|
fs.ErrorLog(f, "Unexpected reset during listing - try again")
|
||||||
fs.Stats.Error()
|
fs.Stats.Error()
|
||||||
fs.ErrorLog(f, "Couldn't list: %s", err)
|
|
||||||
break
|
break
|
||||||
} else {
|
}
|
||||||
if deltaPage.Reset && cursor != "" {
|
fs.Debug(f, "%d delta entries received", len(deltaPage.Entries))
|
||||||
fs.ErrorLog(f, "Unexpected reset during listing - try again")
|
for i := range deltaPage.Entries {
|
||||||
fs.Stats.Error()
|
deltaEntry := &deltaPage.Entries[i]
|
||||||
break
|
entry := deltaEntry.Entry
|
||||||
}
|
if entry == nil {
|
||||||
fs.Debug(f, "%d delta entries received", len(deltaPage.Entries))
|
// This notifies of a deleted object
|
||||||
for i := range deltaPage.Entries {
|
} else {
|
||||||
deltaEntry := &deltaPage.Entries[i]
|
if len(entry.Path) <= 1 || entry.Path[0] != '/' {
|
||||||
entry := deltaEntry.Entry
|
fs.Stats.Error()
|
||||||
if entry == nil {
|
fs.ErrorLog(f, "dropbox API inconsistency: a path should always start with a slash and be at least 2 characters: %s", entry.Path)
|
||||||
// This notifies of a deleted object
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
lastSlashIndex := strings.LastIndex(entry.Path, "/")
|
||||||
|
|
||||||
|
var parentPath string
|
||||||
|
if lastSlashIndex == 0 {
|
||||||
|
parentPath = ""
|
||||||
} else {
|
} else {
|
||||||
if len(entry.Path) <= 1 || entry.Path[0] != '/' {
|
parentPath = entry.Path[1:lastSlashIndex]
|
||||||
fs.Stats.Error()
|
}
|
||||||
fs.ErrorLog(f, "dropbox API inconsistency: a path should always start with a slash and be at least 2 characters: %s", entry.Path)
|
lastComponent := entry.Path[lastSlashIndex+1:]
|
||||||
continue
|
|
||||||
|
if entry.IsDir {
|
||||||
|
nameTree.PutCaseCorrectDirectoryName(parentPath, lastComponent)
|
||||||
|
name, err := f.stripRoot(entry.Path + "/")
|
||||||
|
if err != nil {
|
||||||
|
out.SetError(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
name = strings.Trim(name, "/")
|
||||||
lastSlashIndex := strings.LastIndex(entry.Path, "/")
|
if name != "" && name != dir {
|
||||||
|
dir := &fs.Dir{
|
||||||
var parentPath string
|
Name: name,
|
||||||
if lastSlashIndex == 0 {
|
When: time.Time(entry.ClientMtime),
|
||||||
parentPath = ""
|
Bytes: entry.Bytes,
|
||||||
} else {
|
Count: -1,
|
||||||
parentPath = entry.Path[1:lastSlashIndex]
|
}
|
||||||
|
if out.AddDir(dir) {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lastComponent := entry.Path[lastSlashIndex+1:]
|
} else {
|
||||||
|
parentPathCorrectCase := nameTree.GetPathWithCorrectCase(parentPath)
|
||||||
if entry.IsDir {
|
if parentPathCorrectCase != nil {
|
||||||
nameTree.PutCaseCorrectDirectoryName(parentPath, lastComponent)
|
path, err := f.stripRoot(*parentPathCorrectCase + "/" + lastComponent)
|
||||||
name, err := f.stripRoot(entry.Path + "/")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out.SetError(err)
|
out.SetError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
name = strings.Trim(name, "/")
|
if o := f.newFsObjectWithInfo(path, entry); o != nil {
|
||||||
if name != "" {
|
if out.Add(o) {
|
||||||
dir := &fs.Dir{
|
|
||||||
Name: name,
|
|
||||||
When: time.Time(entry.ClientMtime),
|
|
||||||
Bytes: entry.Bytes,
|
|
||||||
Count: -1,
|
|
||||||
}
|
|
||||||
if out.AddDir(dir) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parentPathCorrectCase := nameTree.GetPathWithCorrectCase(parentPath)
|
nameTree.PutFile(parentPath, lastComponent, entry)
|
||||||
if parentPathCorrectCase != nil {
|
|
||||||
path, err := f.stripRoot(*parentPathCorrectCase + "/" + lastComponent)
|
|
||||||
if err != nil {
|
|
||||||
out.SetError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if o := f.newFsObjectWithInfo(path, entry); o != nil {
|
|
||||||
if out.Add(o) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nameTree.PutFile(parentPath, lastComponent, entry)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !deltaPage.HasMore {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
cursor = deltaPage.Cursor.Cursor
|
|
||||||
}
|
}
|
||||||
|
if !deltaPage.HasMore {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
cursor = deltaPage.Cursor.Cursor
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
walkFunc := func(caseCorrectFilePath string, entry *dropbox.Entry) error {
|
walkFunc := func(caseCorrectFilePath string, entry *dropbox.Entry) error {
|
||||||
|
@ -347,41 +359,56 @@ func (f *Fs) list(out fs.ListOpts, dir string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// List walks the path returning a channel of FsObjects
|
// listOneLevel walks the path one level deep
|
||||||
func (f *Fs) List(out fs.ListOpts, dir string) {
|
func (f *Fs) listOneLevel(out fs.ListOpts, dir string) {
|
||||||
defer out.Finished()
|
root := f.root
|
||||||
f.list(out, dir)
|
if dir != "" {
|
||||||
}
|
root += "/" + dir
|
||||||
|
}
|
||||||
// ListDir walks the path returning a channel of FsObjects
|
entry, err := f.db.Metadata(root, true, false, "", "", metadataLimit)
|
||||||
func (f *Fs) ListDir() fs.DirChan {
|
if err != nil {
|
||||||
out := make(fs.DirChan, fs.Config.Checkers)
|
out.SetError(fmt.Errorf("Couldn't list single level: %s", err))
|
||||||
go func() {
|
return
|
||||||
defer close(out)
|
}
|
||||||
entry, err := f.db.Metadata(f.root, true, false, "", "", metadataLimit)
|
for i := range entry.Contents {
|
||||||
|
entry := &entry.Contents[i]
|
||||||
|
remote, err := strip(entry.Path, root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fs.Stats.Error()
|
out.SetError(err)
|
||||||
fs.ErrorLog(f, "Couldn't list directories in root: %s", err)
|
return
|
||||||
|
}
|
||||||
|
if entry.IsDir {
|
||||||
|
dir := &fs.Dir{
|
||||||
|
Name: remote,
|
||||||
|
When: time.Time(entry.ClientMtime),
|
||||||
|
Bytes: entry.Bytes,
|
||||||
|
Count: -1,
|
||||||
|
}
|
||||||
|
if out.AddDir(dir) {
|
||||||
|
return
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for i := range entry.Contents {
|
if o := f.newFsObjectWithInfo(remote, entry); o != nil {
|
||||||
entry := &entry.Contents[i]
|
if out.Add(o) {
|
||||||
if entry.IsDir {
|
return
|
||||||
name, err := f.stripRoot(entry.Path)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
out <- &fs.Dir{
|
|
||||||
Name: name,
|
|
||||||
When: time.Time(entry.ClientMtime),
|
|
||||||
Bytes: entry.Bytes,
|
|
||||||
Count: -1,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
return out
|
}
|
||||||
|
|
||||||
|
// List walks the path returning a channel of FsObjects
|
||||||
|
func (f *Fs) List(out fs.ListOpts, dir string) {
|
||||||
|
defer out.Finished()
|
||||||
|
level := out.Level()
|
||||||
|
switch level {
|
||||||
|
case 1:
|
||||||
|
f.listOneLevel(out, dir)
|
||||||
|
case fs.MaxLevel:
|
||||||
|
f.list(out, dir)
|
||||||
|
default:
|
||||||
|
out.SetError(fs.ErrorLevelNotSupported)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A read closer which doesn't close the input
|
// A read closer which doesn't close the input
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
17
fs/fs.go
17
fs/fs.go
|
@ -457,6 +457,23 @@ func (o *Lister) Get() (Object, *Dir, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get all the objects and dirs from the listing.
|
||||||
|
func (o *Lister) GetAll() (objs []Object, dirs []*Dir, err error) {
|
||||||
|
for {
|
||||||
|
obj, dir, err := o.Get()
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
return nil, nil, err
|
||||||
|
case obj != nil:
|
||||||
|
objs = append(objs, obj)
|
||||||
|
case dir != nil:
|
||||||
|
dirs = append(dirs, dir)
|
||||||
|
default:
|
||||||
|
return objs, dirs, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetObject will return an object from the listing.
|
// GetObject will return an object from the listing.
|
||||||
// It will skip over any directories.
|
// It will skip over any directories.
|
||||||
// Will return (nil, nil) when all objects have been returned.
|
// Will return (nil, nil) when all objects have been returned.
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
@ -129,14 +130,42 @@ func TestFsListEmpty(t *testing.T) {
|
||||||
fstest.CheckListing(t, remote, []fstest.Item{})
|
fstest.CheckListing(t, remote, []fstest.Item{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// winPath converts a path into a windows safe path
|
||||||
|
func winPath(s string) string {
|
||||||
|
s = strings.Replace(s, "?", "_", -1)
|
||||||
|
s = strings.Replace(s, `"`, "_", -1)
|
||||||
|
s = strings.Replace(s, "<", "_", -1)
|
||||||
|
s = strings.Replace(s, ">", "_", -1)
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// dirsToNames returns a sorted list of names
|
||||||
|
func dirsToNames(dirs []*fs.Dir) []string {
|
||||||
|
names := []string{}
|
||||||
|
for _, dir := range dirs {
|
||||||
|
names = append(names, winPath(dir.Name))
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
|
// objsToNames returns a sorted list of object names
|
||||||
|
func objsToNames(objs []fs.Object) []string {
|
||||||
|
names := []string{}
|
||||||
|
for _, obj := range objs {
|
||||||
|
names = append(names, winPath(obj.Remote()))
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
return names
|
||||||
|
}
|
||||||
|
|
||||||
// TestFsListDirEmpty tests listing the directories from an empty directory
|
// TestFsListDirEmpty tests listing the directories from an empty directory
|
||||||
func TestFsListDirEmpty(t *testing.T) {
|
func TestFsListDirEmpty(t *testing.T) {
|
||||||
skipIfNotOk(t)
|
skipIfNotOk(t)
|
||||||
dirs, err := fs.NewLister().SetLevel(1).Start(remote, "").GetDirs()
|
objs, dirs, err := fs.NewLister().SetLevel(1).Start(remote, "").GetAll()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for _, dir := range dirs {
|
assert.Equal(t, []string{}, objsToNames(objs))
|
||||||
t.Errorf("Found unexpected item %q", dir.Name)
|
assert.Equal(t, []string{}, dirsToNames(dirs))
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFsNewFsObjectNotFound tests not finding a object
|
// TestFsNewFsObjectNotFound tests not finding a object
|
||||||
|
@ -164,14 +193,24 @@ func findObject(t *testing.T, Name string) fs.Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPut(t *testing.T, file *fstest.Item) {
|
func testPut(t *testing.T, file *fstest.Item) {
|
||||||
|
again:
|
||||||
buf := bytes.NewBufferString(fstest.RandomString(100))
|
buf := bytes.NewBufferString(fstest.RandomString(100))
|
||||||
hash := fs.NewMultiHasher()
|
hash := fs.NewMultiHasher()
|
||||||
in := io.TeeReader(buf, hash)
|
in := io.TeeReader(buf, hash)
|
||||||
|
|
||||||
|
tries := 1
|
||||||
|
const maxTries = 10
|
||||||
file.Size = int64(buf.Len())
|
file.Size = int64(buf.Len())
|
||||||
obji := fs.NewStaticObjectInfo(file.Path, file.ModTime, file.Size, true, nil, nil)
|
obji := fs.NewStaticObjectInfo(file.Path, file.ModTime, file.Size, true, nil, nil)
|
||||||
obj, err := remote.Put(in, obji)
|
obj, err := remote.Put(in, obji)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// Retry if err returned a retry error
|
||||||
|
if r, ok := err.(fs.Retry); ok && r.Retry() && tries < maxTries {
|
||||||
|
t.Logf("Put error: %v - low level retry %d/%d", err, tries, maxTries)
|
||||||
|
|
||||||
|
tries++
|
||||||
|
goto again
|
||||||
|
}
|
||||||
t.Fatal("Put error", err)
|
t.Fatal("Put error", err)
|
||||||
}
|
}
|
||||||
file.Hashes = hash.Sums()
|
file.Hashes = hash.Sums()
|
||||||
|
@ -196,26 +235,20 @@ func TestFsPutFile2(t *testing.T) {
|
||||||
// TestFsListDirFile2 tests the files are correctly uploaded
|
// TestFsListDirFile2 tests the files are correctly uploaded
|
||||||
func TestFsListDirFile2(t *testing.T) {
|
func TestFsListDirFile2(t *testing.T) {
|
||||||
skipIfNotOk(t)
|
skipIfNotOk(t)
|
||||||
found := false
|
var objNames, dirNames []string
|
||||||
for i := 1; i <= eventualConsistencyRetries; i++ {
|
for i := 1; i <= eventualConsistencyRetries; i++ {
|
||||||
dirs, err := fs.NewLister().SetLevel(1).Start(remote, "").GetDirs()
|
objs, dirs, err := fs.NewLister().SetLevel(1).Start(remote, "").GetAll()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for _, dir := range dirs {
|
objNames = objsToNames(objs)
|
||||||
if dir.Name != `hello? sausage` && dir.Name != `hello_ sausage` {
|
dirNames = dirsToNames(dirs)
|
||||||
t.Errorf("Found unexpected item %q", dir.Name)
|
if len(objNames) >= 1 && len(dirNames) >= 1 {
|
||||||
} else {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if found {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
t.Logf("Sleeping for 1 second for TestFsListDirFile2 eventual consistency: %d/%d", i, eventualConsistencyRetries)
|
t.Logf("Sleeping for 1 second for TestFsListDirFile2 eventual consistency: %d/%d", i, eventualConsistencyRetries)
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
if !found {
|
assert.Equal(t, []string{`hello_ sausage`}, dirNames)
|
||||||
t.Errorf("Didn't find %q", `hello? sausage`)
|
assert.Equal(t, []string{file1.Path}, objNames)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFsListDirRoot tests that DirList works in the root
|
// TestFsListDirRoot tests that DirList works in the root
|
||||||
|
@ -225,17 +258,9 @@ func TestFsListDirRoot(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to make remote %q: %v", RemoteName, err)
|
t.Fatalf("Failed to make remote %q: %v", RemoteName, err)
|
||||||
}
|
}
|
||||||
found := false
|
|
||||||
dirs, err := fs.NewLister().SetLevel(1).Start(rootRemote, "").GetDirs()
|
dirs, err := fs.NewLister().SetLevel(1).Start(rootRemote, "").GetDirs()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for _, dir := range dirs {
|
assert.Contains(t, dirsToNames(dirs), subRemoteLeaf, "Remote leaf not found")
|
||||||
if dir.Name == subRemoteLeaf {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
t.Errorf("Didn't find %q", subRemoteLeaf)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFsListSubdir tests List works for a subdirectory
|
// TestFsListSubdir tests List works for a subdirectory
|
||||||
|
@ -244,18 +269,31 @@ func TestFsListSubdir(t *testing.T) {
|
||||||
test := func(fileName string) bool {
|
test := func(fileName string) bool {
|
||||||
dir, _ := path.Split(fileName)
|
dir, _ := path.Split(fileName)
|
||||||
dir = dir[:len(dir)-1]
|
dir = dir[:len(dir)-1]
|
||||||
objs, err := fs.NewLister().Start(remote, dir).GetObjects()
|
objs, dirs, err := fs.NewLister().Start(remote, dir).GetAll()
|
||||||
if err == fs.ErrorDirNotFound {
|
if err == fs.ErrorDirNotFound {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, objs, 1)
|
require.Len(t, objs, 1)
|
||||||
assert.Equal(t, fileName, objs[0].Remote())
|
assert.Equal(t, fileName, objs[0].Remote())
|
||||||
|
require.Len(t, dirs, 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
assert.True(t, test(file2.Path) || test(file2.WinPath), "normal and alternative lists failed")
|
assert.True(t, test(file2.Path) || test(file2.WinPath), "normal and alternative lists failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestFsListLevel2 tests List works for 2 levels
|
||||||
|
func TestFsListLevel2(t *testing.T) {
|
||||||
|
skipIfNotOk(t)
|
||||||
|
objs, dirs, err := fs.NewLister().SetLevel(2).Start(remote, "").GetAll()
|
||||||
|
if err == fs.ErrorLevelNotSupported {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, []string{file1.Path}, objsToNames(objs))
|
||||||
|
assert.Equal(t, []string{`hello_ sausage`, `hello_ sausage/êé`}, dirsToNames(dirs))
|
||||||
|
}
|
||||||
|
|
||||||
// TestFsListFile1 tests file present
|
// TestFsListFile1 tests file present
|
||||||
func TestFsListFile1(t *testing.T) {
|
func TestFsListFile1(t *testing.T) {
|
||||||
skipIfNotOk(t)
|
skipIfNotOk(t)
|
||||||
|
|
|
@ -305,6 +305,7 @@ type listFn func(remote string, object *storage.Object, isDirectory bool) error
|
||||||
// If directories is set it only sends directories
|
// If directories is set it only sends directories
|
||||||
func (f *Fs) list(dir string, level int, fn listFn) error {
|
func (f *Fs) list(dir string, level int, fn listFn) error {
|
||||||
root := f.root
|
root := f.root
|
||||||
|
rootLength := len(root)
|
||||||
if dir != "" {
|
if dir != "" {
|
||||||
root += dir + "/"
|
root += dir + "/"
|
||||||
}
|
}
|
||||||
|
@ -316,7 +317,6 @@ func (f *Fs) list(dir string, level int, fn listFn) error {
|
||||||
default:
|
default:
|
||||||
return fs.ErrorLevelNotSupported
|
return fs.ErrorLevelNotSupported
|
||||||
}
|
}
|
||||||
rootLength := len(root)
|
|
||||||
for {
|
for {
|
||||||
objects, err := list.Do()
|
objects, err := list.Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
|
@ -225,7 +225,7 @@ func (f *Fs) List(out fs.ListOpts, dir string) {
|
||||||
|
|
||||||
// Start the process
|
// Start the process
|
||||||
traversing.Add(1)
|
traversing.Add(1)
|
||||||
in <- listArgs{remote: "", dirpath: root, level: out.Level() - 1}
|
in <- listArgs{remote: dir, dirpath: root, level: out.Level() - 1}
|
||||||
for i := 0; i < fs.Config.Checkers; i++ {
|
for i := 0; i < fs.Config.Checkers; i++ {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
|
@ -31,6 +31,7 @@ func TestFsPutFile2(t *testing.T) { fstests.TestFsPutFile2(t) }
|
||||||
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
func TestFsListDirFile2(t *testing.T) { fstests.TestFsListDirFile2(t) }
|
||||||
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
func TestFsListDirRoot(t *testing.T) { fstests.TestFsListDirRoot(t) }
|
||||||
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
func TestFsListSubdir(t *testing.T) { fstests.TestFsListSubdir(t) }
|
||||||
|
func TestFsListLevel2(t *testing.T) { fstests.TestFsListLevel2(t) }
|
||||||
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
func TestFsListFile1(t *testing.T) { fstests.TestFsListFile1(t) }
|
||||||
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
func TestFsNewFsObject(t *testing.T) { fstests.TestFsNewFsObject(t) }
|
||||||
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
func TestFsListFile1and2(t *testing.T) { fstests.TestFsListFile1and2(t) }
|
||||||
|
|
Loading…
Reference in a new issue