|
|
|
@ -23,6 +23,7 @@ import ( |
|
|
|
|
"os" |
|
|
|
|
"reflect" |
|
|
|
|
"sort" |
|
|
|
|
"strings" |
|
|
|
|
"testing" |
|
|
|
|
"time" |
|
|
|
|
) |
|
|
|
@ -85,27 +86,27 @@ func createNamespace(disk StorageAPI, volume string, files []string) error { |
|
|
|
|
|
|
|
|
|
// Returns function "listDir" of the type listDirFunc.
|
|
|
|
|
// disks - used for doing disk.ListDir()
|
|
|
|
|
func listDirFactory(ctx context.Context, disk StorageAPI) ListDirFunc { |
|
|
|
|
return func(volume, dirPath, dirEntry string) (emptyDir bool, entries []string) { |
|
|
|
|
func listDirFactory(ctx context.Context, disk StorageAPI, isLeaf IsLeafFunc) ListDirFunc { |
|
|
|
|
return func(volume, dirPath, dirEntry string) (emptyDir bool, entries []string, delayIsLeaf bool) { |
|
|
|
|
entries, err := disk.ListDir(volume, dirPath, -1) |
|
|
|
|
if err != nil { |
|
|
|
|
return false, nil |
|
|
|
|
return false, nil, false |
|
|
|
|
} |
|
|
|
|
if len(entries) == 0 { |
|
|
|
|
return true, nil |
|
|
|
|
return true, nil, false |
|
|
|
|
} |
|
|
|
|
sort.Strings(entries) |
|
|
|
|
return false, filterMatchingPrefix(entries, dirEntry) |
|
|
|
|
entries, delayIsLeaf = filterListEntries(volume, dirPath, entries, dirEntry, isLeaf) |
|
|
|
|
return false, entries, delayIsLeaf |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Test if tree walker returns entries matching prefix alone are received
|
|
|
|
|
// when a non empty prefix is supplied.
|
|
|
|
|
func testTreeWalkPrefix(t *testing.T, listDir ListDirFunc) { |
|
|
|
|
func testTreeWalkPrefix(t *testing.T, listDir ListDirFunc, isLeaf IsLeafFunc, isLeafDir IsLeafDirFunc) { |
|
|
|
|
// Start the tree walk go-routine.
|
|
|
|
|
prefix := "d/" |
|
|
|
|
endWalkCh := make(chan struct{}) |
|
|
|
|
twResultCh := startTreeWalk(context.Background(), volume, prefix, "", true, listDir, endWalkCh) |
|
|
|
|
twResultCh := startTreeWalk(context.Background(), volume, prefix, "", true, listDir, isLeaf, isLeafDir, endWalkCh) |
|
|
|
|
|
|
|
|
|
// Check if all entries received on the channel match the prefix.
|
|
|
|
|
for res := range twResultCh { |
|
|
|
@ -116,11 +117,11 @@ func testTreeWalkPrefix(t *testing.T, listDir ListDirFunc) { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Test if entries received on tree walk's channel appear after the supplied marker.
|
|
|
|
|
func testTreeWalkMarker(t *testing.T, listDir ListDirFunc) { |
|
|
|
|
func testTreeWalkMarker(t *testing.T, listDir ListDirFunc, isLeaf IsLeafFunc, isLeafDir IsLeafDirFunc) { |
|
|
|
|
// Start the tree walk go-routine.
|
|
|
|
|
prefix := "" |
|
|
|
|
endWalkCh := make(chan struct{}) |
|
|
|
|
twResultCh := startTreeWalk(context.Background(), volume, prefix, "d/g", true, listDir, endWalkCh) |
|
|
|
|
twResultCh := startTreeWalk(context.Background(), volume, prefix, "d/g", true, listDir, isLeaf, isLeafDir, endWalkCh) |
|
|
|
|
|
|
|
|
|
// Check if only 3 entries, namely d/g/h, i/j/k, lmn are received on the channel.
|
|
|
|
|
expectedCount := 3 |
|
|
|
@ -157,12 +158,22 @@ func TestTreeWalk(t *testing.T) { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
listDir := listDirFactory(context.Background(), disk) |
|
|
|
|
isLeaf := func(bucket, leafPath string) bool { |
|
|
|
|
return !strings.HasSuffix(leafPath, slashSeparator) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
isLeafDir := func(bucket, leafPath string) bool { |
|
|
|
|
entries, _ := disk.ListDir(bucket, leafPath, 1) |
|
|
|
|
return len(entries) == 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
listDir := listDirFactory(context.Background(), disk, isLeaf) |
|
|
|
|
|
|
|
|
|
// Simple test for prefix based walk.
|
|
|
|
|
testTreeWalkPrefix(t, listDir) |
|
|
|
|
testTreeWalkPrefix(t, listDir, isLeaf, isLeafDir) |
|
|
|
|
|
|
|
|
|
// Simple test when marker is set.
|
|
|
|
|
testTreeWalkMarker(t, listDir) |
|
|
|
|
testTreeWalkMarker(t, listDir, isLeaf, isLeafDir) |
|
|
|
|
|
|
|
|
|
err = os.RemoveAll(fsDir) |
|
|
|
|
if err != nil { |
|
|
|
@ -191,7 +202,16 @@ func TestTreeWalkTimeout(t *testing.T) { |
|
|
|
|
t.Fatal(err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
listDir := listDirFactory(context.Background(), disk) |
|
|
|
|
isLeaf := func(bucket, leafPath string) bool { |
|
|
|
|
return !strings.HasSuffix(leafPath, slashSeparator) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
isLeafDir := func(bucket, leafPath string) bool { |
|
|
|
|
entries, _ := disk.ListDir(bucket, leafPath, 1) |
|
|
|
|
return len(entries) == 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
listDir := listDirFactory(context.Background(), disk, isLeaf) |
|
|
|
|
|
|
|
|
|
// TreeWalk pool with 2 seconds timeout for tree-walk go routines.
|
|
|
|
|
pool := NewTreeWalkPool(2 * time.Second) |
|
|
|
@ -200,7 +220,7 @@ func TestTreeWalkTimeout(t *testing.T) { |
|
|
|
|
prefix := "" |
|
|
|
|
marker := "" |
|
|
|
|
recursive := true |
|
|
|
|
resultCh := startTreeWalk(context.Background(), volume, prefix, marker, recursive, listDir, endWalkCh) |
|
|
|
|
resultCh := startTreeWalk(context.Background(), volume, prefix, marker, recursive, listDir, isLeaf, isLeafDir, endWalkCh) |
|
|
|
|
|
|
|
|
|
params := listParams{ |
|
|
|
|
bucket: volume, |
|
|
|
@ -250,8 +270,17 @@ func TestRecursiveTreeWalk(t *testing.T) { |
|
|
|
|
t.Fatalf("Unable to create StorageAPI: %s", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
isLeaf := func(bucket, leafPath string) bool { |
|
|
|
|
return !strings.HasSuffix(leafPath, slashSeparator) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
isLeafDir := func(bucket, leafPath string) bool { |
|
|
|
|
entries, _ := disk1.ListDir(bucket, leafPath, 1) |
|
|
|
|
return len(entries) == 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create listDir function.
|
|
|
|
|
listDir := listDirFactory(context.Background(), disk1) |
|
|
|
|
listDir := listDirFactory(context.Background(), disk1, isLeaf) |
|
|
|
|
|
|
|
|
|
// Create the namespace.
|
|
|
|
|
var files = []string{ |
|
|
|
@ -329,7 +358,7 @@ func TestRecursiveTreeWalk(t *testing.T) { |
|
|
|
|
t.Run(fmt.Sprintf("Test%d", i+1), func(t *testing.T) { |
|
|
|
|
for entry := range startTreeWalk(context.Background(), volume, |
|
|
|
|
testCase.prefix, testCase.marker, testCase.recursive, |
|
|
|
|
listDir, endWalkCh) { |
|
|
|
|
listDir, isLeaf, isLeafDir, endWalkCh) { |
|
|
|
|
if _, found := testCase.expected[entry.entry]; !found { |
|
|
|
|
t.Errorf("Expected %s, but couldn't find", entry.entry) |
|
|
|
|
} |
|
|
|
@ -355,8 +384,17 @@ func TestSortedness(t *testing.T) { |
|
|
|
|
t.Fatalf("Unable to create StorageAPI: %s", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
isLeaf := func(bucket, leafPath string) bool { |
|
|
|
|
return !strings.HasSuffix(leafPath, slashSeparator) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
isLeafDir := func(bucket, leafPath string) bool { |
|
|
|
|
entries, _ := disk1.ListDir(bucket, leafPath, 1) |
|
|
|
|
return len(entries) == 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create listDir function.
|
|
|
|
|
listDir := listDirFactory(context.Background(), disk1) |
|
|
|
|
listDir := listDirFactory(context.Background(), disk1, isLeaf) |
|
|
|
|
|
|
|
|
|
// Create the namespace.
|
|
|
|
|
var files = []string{ |
|
|
|
@ -398,7 +436,7 @@ func TestSortedness(t *testing.T) { |
|
|
|
|
var actualEntries []string |
|
|
|
|
for entry := range startTreeWalk(context.Background(), volume, |
|
|
|
|
test.prefix, test.marker, test.recursive, |
|
|
|
|
listDir, endWalkCh) { |
|
|
|
|
listDir, isLeaf, isLeafDir, endWalkCh) { |
|
|
|
|
actualEntries = append(actualEntries, entry.entry) |
|
|
|
|
} |
|
|
|
|
if !sort.IsSorted(sort.StringSlice(actualEntries)) { |
|
|
|
@ -426,8 +464,17 @@ func TestTreeWalkIsEnd(t *testing.T) { |
|
|
|
|
t.Fatalf("Unable to create StorageAPI: %s", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
isLeaf := func(bucket, leafPath string) bool { |
|
|
|
|
return !strings.HasSuffix(leafPath, slashSeparator) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
isLeafDir := func(bucket, leafPath string) bool { |
|
|
|
|
entries, _ := disk1.ListDir(bucket, leafPath, 1) |
|
|
|
|
return len(entries) == 0 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Create listDir function.
|
|
|
|
|
listDir := listDirFactory(context.Background(), disk1) |
|
|
|
|
listDir := listDirFactory(context.Background(), disk1, isLeaf) |
|
|
|
|
|
|
|
|
|
// Create the namespace.
|
|
|
|
|
var files = []string{ |
|
|
|
@ -469,7 +516,7 @@ func TestTreeWalkIsEnd(t *testing.T) { |
|
|
|
|
for i, test := range testCases { |
|
|
|
|
var entry TreeWalkResult |
|
|
|
|
for entry = range startTreeWalk(context.Background(), volume, test.prefix, |
|
|
|
|
test.marker, test.recursive, listDir, endWalkCh) { |
|
|
|
|
test.marker, test.recursive, listDir, isLeaf, isLeafDir, endWalkCh) { |
|
|
|
|
} |
|
|
|
|
if entry.entry != test.expectedEntry { |
|
|
|
|
t.Errorf("Test %d: Expected entry %s, but received %s with the EOF marker", i, test.expectedEntry, entry.entry) |
|
|
|
|