Add more tests for List() and fix resulting problems

This commit is contained in:
Nick Craig-Wood 2016-05-07 14:50:35 +01:00
parent 68ec6a9f5b
commit c2d0e86431
19 changed files with 369 additions and 137 deletions

View file

@ -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) }

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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) }

View file

@ -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,
} }

View file

@ -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) }

View file

@ -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

View file

@ -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) }

View file

@ -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.

View file

@ -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)

View file

@ -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 {

View file

@ -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) }

View file

@ -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) }

View file

@ -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() {

View file

@ -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) }

View file

@ -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) }

View file

@ -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) }

View file

@ -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) }

View file

@ -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) }