frostfs-node/pkg/local_object_storage/metabase/select_test.go

410 lines
10 KiB
Go

package meta_test
import (
"encoding/hex"
"testing"
"github.com/nspcc-dev/neofs-api-go/pkg"
"github.com/nspcc-dev/neofs-api-go/pkg/container"
objectSDK "github.com/nspcc-dev/neofs-api-go/pkg/object"
v2object "github.com/nspcc-dev/neofs-api-go/v2/object"
"github.com/stretchr/testify/require"
)
func TestDB_SelectUserAttributes(t *testing.T) {
db := newDB(t)
defer releaseDB(db)
cid := testCID()
raw1 := generateRawObjectWithCID(t, cid)
addAttribute(raw1, "foo", "bar")
addAttribute(raw1, "x", "y")
err := db.Put(raw1.Object(), nil)
require.NoError(t, err)
raw2 := generateRawObjectWithCID(t, cid)
addAttribute(raw2, "foo", "bar")
addAttribute(raw2, "x", "z")
err = db.Put(raw2.Object(), nil)
require.NoError(t, err)
raw3 := generateRawObjectWithCID(t, cid)
addAttribute(raw3, "a", "b")
err = db.Put(raw3.Object(), nil)
require.NoError(t, err)
fs := generateSearchFilter(cid)
fs.AddFilter("foo", "bar", objectSDK.MatchStringEqual)
testSelect(t, db, fs,
raw1.Object().Address(),
raw2.Object().Address(),
)
fs = generateSearchFilter(cid)
fs.AddFilter("x", "y", objectSDK.MatchStringEqual)
testSelect(t, db, fs, raw1.Object().Address())
fs = generateSearchFilter(cid)
fs.AddFilter("a", "b", objectSDK.MatchStringEqual)
testSelect(t, db, fs, raw3.Object().Address())
fs = generateSearchFilter(cid)
fs.AddFilter("c", "d", objectSDK.MatchStringEqual)
testSelect(t, db, fs)
fs = generateSearchFilter(cid)
testSelect(t, db, fs,
raw1.Object().Address(),
raw2.Object().Address(),
raw3.Object().Address(),
)
}
func TestDB_SelectRootPhyParent(t *testing.T) {
db := newDB(t)
defer releaseDB(db)
cid := testCID()
// prepare
small := generateRawObjectWithCID(t, cid)
err := db.Put(small.Object(), nil)
require.NoError(t, err)
ts := generateRawObjectWithCID(t, cid)
ts.SetType(objectSDK.TypeTombstone)
err = db.Put(ts.Object(), nil)
require.NoError(t, err)
sg := generateRawObjectWithCID(t, cid)
sg.SetType(objectSDK.TypeStorageGroup)
err = db.Put(sg.Object(), nil)
require.NoError(t, err)
leftChild := generateRawObjectWithCID(t, cid)
leftChild.InitRelations()
err = db.Put(leftChild.Object(), nil)
require.NoError(t, err)
parent := generateRawObjectWithCID(t, cid)
rightChild := generateRawObjectWithCID(t, cid)
rightChild.SetParent(parent.Object().SDK())
rightChild.SetParentID(parent.ID())
err = db.Put(rightChild.Object(), nil)
require.NoError(t, err)
link := generateRawObjectWithCID(t, cid)
link.SetParent(parent.Object().SDK())
link.SetParentID(parent.ID())
link.SetChildren(leftChild.ID(), rightChild.ID())
err = db.Put(link.Object(), nil)
require.NoError(t, err)
t.Run("root objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddRootFilter()
testSelect(t, db, fs,
small.Object().Address(),
parent.Object().Address(),
)
})
t.Run("phy objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddPhyFilter()
testSelect(t, db, fs,
small.Object().Address(),
ts.Object().Address(),
sg.Object().Address(),
leftChild.Object().Address(),
rightChild.Object().Address(),
link.Object().Address(),
)
})
t.Run("regular objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderObjectType, "Regular", objectSDK.MatchStringEqual)
testSelect(t, db, fs,
small.Object().Address(),
leftChild.Object().Address(),
rightChild.Object().Address(),
link.Object().Address(),
parent.Object().Address(),
)
})
t.Run("tombstone objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderObjectType, "Tombstone", objectSDK.MatchStringEqual)
testSelect(t, db, fs, ts.Object().Address())
})
t.Run("storage group objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderObjectType, "StorageGroup", objectSDK.MatchStringEqual)
testSelect(t, db, fs, sg.Object().Address())
})
t.Run("objects with parent", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderParent,
parent.ID().String(),
objectSDK.MatchStringEqual)
testSelect(t, db, fs,
rightChild.Object().Address(),
link.Object().Address(),
)
})
t.Run("all objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
testSelect(t, db, fs,
small.Object().Address(),
ts.Object().Address(),
sg.Object().Address(),
leftChild.Object().Address(),
rightChild.Object().Address(),
link.Object().Address(),
parent.Object().Address(),
)
})
}
func TestDB_SelectInhume(t *testing.T) {
db := newDB(t)
defer releaseDB(db)
cid := testCID()
raw1 := generateRawObjectWithCID(t, cid)
err := db.Put(raw1.Object(), nil)
require.NoError(t, err)
raw2 := generateRawObjectWithCID(t, cid)
err = db.Put(raw2.Object(), nil)
require.NoError(t, err)
fs := generateSearchFilter(cid)
testSelect(t, db, fs,
raw1.Object().Address(),
raw2.Object().Address(),
)
tombstone := objectSDK.NewAddress()
tombstone.SetContainerID(cid)
tombstone.SetObjectID(testOID())
err = db.Inhume(raw2.Object().Address(), tombstone)
require.NoError(t, err)
fs = generateSearchFilter(cid)
testSelect(t, db, fs,
raw1.Object().Address(),
)
}
func TestDB_SelectPayloadHash(t *testing.T) {
db := newDB(t)
defer releaseDB(db)
cid := testCID()
raw1 := generateRawObjectWithCID(t, cid)
err := db.Put(raw1.Object(), nil)
require.NoError(t, err)
raw2 := generateRawObjectWithCID(t, cid)
err = db.Put(raw2.Object(), nil)
require.NoError(t, err)
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderPayloadHash,
hex.EncodeToString(raw1.PayloadChecksum().Sum()),
objectSDK.MatchStringEqual)
testSelect(t, db, fs, raw1.Object().Address())
}
func TestDB_SelectWithSlowFilters(t *testing.T) {
db := newDB(t)
defer releaseDB(db)
cid := testCID()
v20 := new(pkg.Version)
v20.SetMajor(2)
v21 := new(pkg.Version)
v21.SetMajor(2)
v21.SetMinor(1)
raw1 := generateRawObjectWithCID(t, cid)
raw1.SetPayloadSize(10)
raw1.SetCreationEpoch(11)
raw1.SetVersion(v20)
err := db.Put(raw1.Object(), nil)
require.NoError(t, err)
raw2 := generateRawObjectWithCID(t, cid)
raw2.SetPayloadSize(20)
raw2.SetCreationEpoch(21)
raw2.SetVersion(v21)
err = db.Put(raw2.Object(), nil)
require.NoError(t, err)
t.Run("object with TZHash", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderHomomorphicHash,
hex.EncodeToString(raw1.PayloadHomomorphicHash().Sum()),
objectSDK.MatchStringEqual)
testSelect(t, db, fs, raw1.Object().Address())
})
t.Run("object with payload length", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderPayloadLength, "20", objectSDK.MatchStringEqual)
testSelect(t, db, fs, raw2.Object().Address())
})
t.Run("object with creation epoch", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderCreationEpoch, "11", objectSDK.MatchStringEqual)
testSelect(t, db, fs, raw1.Object().Address())
})
t.Run("object with version", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddObjectVersionFilter(objectSDK.MatchStringEqual, v21)
testSelect(t, db, fs, raw2.Object().Address())
})
}
func generateSearchFilter(cid *container.ID) objectSDK.SearchFilters {
fs := objectSDK.SearchFilters{}
fs.AddObjectContainerIDFilter(objectSDK.MatchStringEqual, cid)
return fs
}
func TestDB_SelectObjectID(t *testing.T) {
db := newDB(t)
defer releaseDB(db)
cid := testCID()
// prepare
parent := generateRawObjectWithCID(t, cid)
regular := generateRawObjectWithCID(t, cid)
regular.SetParentID(parent.ID())
regular.SetParent(parent.Object().SDK())
err := db.Put(regular.Object(), nil)
require.NoError(t, err)
ts := generateRawObjectWithCID(t, cid)
ts.SetType(objectSDK.TypeTombstone)
err = db.Put(ts.Object(), nil)
require.NoError(t, err)
sg := generateRawObjectWithCID(t, cid)
sg.SetType(objectSDK.TypeStorageGroup)
err = db.Put(sg.Object(), nil)
require.NoError(t, err)
t.Run("not found objects", func(t *testing.T) {
raw := generateRawObjectWithCID(t, cid)
fs := generateSearchFilter(cid)
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, raw.ID())
testSelect(t, db, fs)
})
t.Run("regular objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, regular.ID())
testSelect(t, db, fs, regular.Object().Address())
})
t.Run("tombstone objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, ts.ID())
testSelect(t, db, fs, ts.Object().Address())
})
t.Run("storage group objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, sg.ID())
testSelect(t, db, fs, sg.Object().Address())
})
t.Run("storage group objects", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, parent.ID())
testSelect(t, db, fs, parent.Object().Address())
})
}
func TestDB_SelectSplitID(t *testing.T) {
db := newDB(t)
defer releaseDB(db)
cid := testCID()
child1 := generateRawObjectWithCID(t, cid)
child2 := generateRawObjectWithCID(t, cid)
child3 := generateRawObjectWithCID(t, cid)
split1 := objectSDK.NewSplitID()
split2 := objectSDK.NewSplitID()
child1.SetSplitID(split1)
child2.SetSplitID(split1)
child3.SetSplitID(split2)
require.NoError(t, db.Put(child1.Object(), nil))
require.NoError(t, db.Put(child2.Object(), nil))
require.NoError(t, db.Put(child3.Object(), nil))
t.Run("split id", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderSplitID, split1.String(), objectSDK.MatchStringEqual)
testSelect(t, db, fs,
child1.Object().Address(),
child2.Object().Address(),
)
fs = generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderSplitID, split2.String(), objectSDK.MatchStringEqual)
testSelect(t, db, fs, child3.Object().Address())
})
t.Run("empty split", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderSplitID, "", objectSDK.MatchStringEqual)
testSelect(t, db, fs)
})
t.Run("unknown split id", func(t *testing.T) {
fs := generateSearchFilter(cid)
fs.AddFilter(v2object.FilterHeaderSplitID,
objectSDK.NewSplitID().String(),
objectSDK.MatchStringEqual)
testSelect(t, db, fs)
})
}