2024-07-08 10:48:39 +00:00
|
|
|
package pilorama
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestDuplicateDirectory(t *testing.T) {
|
|
|
|
for i := range providers {
|
|
|
|
if providers[i].name == "inmemory" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
t.Run(providers[i].name, func(t *testing.T) {
|
|
|
|
testDuplicateDirectory(t, providers[i].construct(t))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func testDuplicateDirectory(t *testing.T, f Forest) {
|
|
|
|
ctx := context.Background()
|
|
|
|
d := CIDDescriptor{CID: cidtest.ID(), Size: 1}
|
|
|
|
treeID := "sometree"
|
|
|
|
|
|
|
|
treeApply := func(t *testing.T, parent, child uint64, filename string, internal bool) {
|
|
|
|
// Nothing magic here, we add items in order and children are unique.
|
|
|
|
// This simplifies function interface a bit.
|
|
|
|
ts := child
|
|
|
|
|
|
|
|
kv := []KeyValue{{Key: AttributeFilename, Value: []byte(filename)}}
|
|
|
|
if !internal {
|
|
|
|
kv = append(kv, KeyValue{Key: "uniqueAttr", Value: []byte{byte(child)}})
|
|
|
|
}
|
|
|
|
|
|
|
|
err := f.TreeApply(ctx, d.CID, treeID, &Move{
|
|
|
|
Parent: parent,
|
|
|
|
Child: child,
|
|
|
|
Meta: Meta{
|
|
|
|
Time: ts,
|
|
|
|
Items: kv,
|
|
|
|
},
|
|
|
|
}, true)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// The following tree is constructed:
|
|
|
|
// 0
|
|
|
|
// [1] |-- dir1 (internal)
|
|
|
|
// [2] |-- value1
|
|
|
|
// [3] |-- dir3 (internal)
|
|
|
|
// [4] |-- value3
|
|
|
|
// [5] |-- dir1 (internal)
|
|
|
|
// [6] |-- value2
|
|
|
|
// [7] |-- dir3 (internal)
|
|
|
|
// [8] |-- value4
|
|
|
|
// [9] |-- dir2 (internal)
|
|
|
|
// [10] |-- value0
|
|
|
|
treeApply(t, RootID, 1, "dir1", true)
|
|
|
|
treeApply(t, 1, 2, "value1", false)
|
|
|
|
treeApply(t, 1, 3, "dir3", true)
|
|
|
|
treeApply(t, 3, 4, "value3", false)
|
|
|
|
treeApply(t, RootID, 5, "dir1", true)
|
|
|
|
treeApply(t, 5, 6, "value2", false)
|
|
|
|
treeApply(t, 5, 7, "dir3", true)
|
|
|
|
treeApply(t, 7, 8, "value4", false)
|
|
|
|
treeApply(t, RootID, 9, "dir2", true)
|
|
|
|
treeApply(t, RootID, 10, "value0", false)
|
|
|
|
|
|
|
|
// The compacted view:
|
|
|
|
// 0
|
|
|
|
// [1,5] |-- dir1 (internal)
|
|
|
|
// [2] |-- value1
|
|
|
|
// [3,7] |-- dir3 (internal)
|
|
|
|
// [4] |-- value3
|
|
|
|
// [8] |-- value4
|
|
|
|
// [6] |-- value2
|
|
|
|
// [9] |-- dir2 (internal)
|
|
|
|
// [10] |-- value0
|
|
|
|
testGetByPath := func(t *testing.T, p string) []byte {
|
|
|
|
pp := strings.Split(p, "/")
|
|
|
|
nodes, err := f.TreeGetByPath(context.Background(), d.CID, treeID, AttributeFilename, pp, false)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, 1, len(nodes))
|
|
|
|
|
|
|
|
meta, _, err := f.TreeGetMeta(ctx, d.CID, treeID, nodes[0])
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, []byte(pp[len(pp)-1]), meta.GetAttr(AttributeFilename))
|
|
|
|
return meta.GetAttr("uniqueAttr")
|
|
|
|
}
|
|
|
|
|
|
|
|
require.Equal(t, []byte{2}, testGetByPath(t, "dir1/value1"))
|
|
|
|
require.Equal(t, []byte{4}, testGetByPath(t, "dir1/dir3/value3"))
|
|
|
|
require.Equal(t, []byte{8}, testGetByPath(t, "dir1/dir3/value4"))
|
|
|
|
require.Equal(t, []byte{10}, testGetByPath(t, "value0"))
|
2024-07-10 06:30:01 +00:00
|
|
|
|
|
|
|
testSortedByFilename := func(t *testing.T, root MultiNode, last *string, batchSize int) ([]MultiNodeInfo, *string) {
|
|
|
|
res, last, err := f.TreeSortedByFilename(context.Background(), d.CID, treeID, root, last, batchSize)
|
|
|
|
require.NoError(t, err)
|
|
|
|
return res, last
|
|
|
|
}
|
|
|
|
|
|
|
|
t.Run("test sorted listing, full children branch", func(t *testing.T) {
|
|
|
|
t.Run("big batch size", func(t *testing.T) {
|
|
|
|
res, _ := testSortedByFilename(t, MultiNode{RootID}, nil, 10)
|
|
|
|
require.Equal(t, 3, len(res))
|
|
|
|
require.Equal(t, MultiNode{1, 5}, res[0].Children)
|
|
|
|
require.Equal(t, MultiNode{9}, res[1].Children)
|
|
|
|
require.Equal(t, MultiNode{10}, res[2].Children)
|
|
|
|
|
|
|
|
t.Run("multi-root", func(t *testing.T) {
|
|
|
|
res, _ := testSortedByFilename(t, MultiNode{1, 5}, nil, 10)
|
|
|
|
require.Equal(t, 3, len(res))
|
|
|
|
require.Equal(t, MultiNode{3, 7}, res[0].Children)
|
|
|
|
require.Equal(t, MultiNode{2}, res[1].Children)
|
|
|
|
require.Equal(t, MultiNode{6}, res[2].Children)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
t.Run("small batch size", func(t *testing.T) {
|
|
|
|
res, last := testSortedByFilename(t, MultiNode{RootID}, nil, 1)
|
|
|
|
require.Equal(t, 1, len(res))
|
|
|
|
require.Equal(t, MultiNode{1, 5}, res[0].Children)
|
|
|
|
|
|
|
|
res, last = testSortedByFilename(t, MultiNode{RootID}, last, 1)
|
|
|
|
require.Equal(t, 1, len(res))
|
|
|
|
require.Equal(t, MultiNode{9}, res[0].Children)
|
|
|
|
|
|
|
|
res, last = testSortedByFilename(t, MultiNode{RootID}, last, 1)
|
|
|
|
require.Equal(t, 1, len(res))
|
|
|
|
require.Equal(t, MultiNode{10}, res[0].Children)
|
|
|
|
|
|
|
|
res, _ = testSortedByFilename(t, MultiNode{RootID}, last, 1)
|
|
|
|
require.Equal(t, 0, len(res))
|
|
|
|
|
|
|
|
t.Run("multi-root", func(t *testing.T) {
|
|
|
|
res, last := testSortedByFilename(t, MultiNode{1, 5}, nil, 1)
|
|
|
|
require.Equal(t, 1, len(res))
|
|
|
|
require.Equal(t, MultiNode{3, 7}, res[0].Children)
|
|
|
|
|
|
|
|
res, last = testSortedByFilename(t, MultiNode{1, 5}, last, 1)
|
|
|
|
require.Equal(t, 1, len(res))
|
|
|
|
require.Equal(t, MultiNode{2}, res[0].Children)
|
|
|
|
|
|
|
|
res, last = testSortedByFilename(t, MultiNode{1, 5}, last, 1)
|
|
|
|
require.Equal(t, 1, len(res))
|
|
|
|
require.Equal(t, MultiNode{6}, res[0].Children)
|
|
|
|
|
|
|
|
res, _ = testSortedByFilename(t, MultiNode{RootID}, last, 1)
|
|
|
|
require.Equal(t, 0, len(res))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
2024-07-08 10:48:39 +00:00
|
|
|
}
|