Airat Arifullin
9b13a18aac
* Update version within go.mod; * Fix deprecated frostfs-api-go/v2 package and use frostfs-sdk-go/api instead. Signed-off-by: Airat Arifullin <a.arifullin@yadro.com>
1242 lines
33 KiB
Go
1242 lines
33 KiB
Go
package meta_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/hex"
|
|
"math/rand"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/object"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/internal/testutil"
|
|
meta "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/metabase"
|
|
v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object"
|
|
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
|
|
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
|
|
objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/erasurecode"
|
|
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
|
|
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/transformer"
|
|
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
|
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestDB_SelectUserAttributes(t *testing.T) {
|
|
t.Parallel()
|
|
t.Run("with_index", func(t *testing.T) {
|
|
testSelectUserAttributes(t, true)
|
|
})
|
|
t.Run("without_index", func(t *testing.T) {
|
|
testSelectUserAttributes(t, false)
|
|
})
|
|
}
|
|
|
|
func testSelectUserAttributes(t *testing.T, index bool) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
raw1 := testutil.GenerateObjectWithCID(cnr)
|
|
testutil.AddAttribute(raw1, "foo", "bar")
|
|
testutil.AddAttribute(raw1, "x", "y")
|
|
|
|
var putPrm meta.PutPrm
|
|
putPrm.SetIndexAttributes(index)
|
|
putPrm.SetObject(raw1)
|
|
_, err := db.Put(context.Background(), putPrm)
|
|
require.NoError(t, err)
|
|
|
|
raw2 := testutil.GenerateObjectWithCID(cnr)
|
|
testutil.AddAttribute(raw2, "foo", "bar")
|
|
testutil.AddAttribute(raw2, "x", "z")
|
|
|
|
putPrm.SetObject(raw2)
|
|
_, err = db.Put(context.Background(), putPrm)
|
|
require.NoError(t, err)
|
|
|
|
raw3 := testutil.GenerateObjectWithCID(cnr)
|
|
testutil.AddAttribute(raw3, "a", "b")
|
|
|
|
putPrm.SetObject(raw3)
|
|
_, err = db.Put(context.Background(), putPrm)
|
|
require.NoError(t, err)
|
|
|
|
raw4 := testutil.GenerateObjectWithCID(cnr)
|
|
testutil.AddAttribute(raw4, objectSDK.AttributeFilePath, "/test/1/2")
|
|
|
|
putPrm.SetObject(raw4)
|
|
_, err = db.Put(context.Background(), putPrm)
|
|
require.NoError(t, err)
|
|
|
|
raw5 := testutil.GenerateObjectWithCID(cnr)
|
|
testutil.AddAttribute(raw5, objectSDK.AttributeFilePath, "/test/1/3")
|
|
|
|
putPrm.SetObject(raw5)
|
|
_, err = db.Put(context.Background(), putPrm)
|
|
require.NoError(t, err)
|
|
|
|
raw6 := testutil.GenerateObjectWithCID(cnr)
|
|
testutil.AddAttribute(raw6, objectSDK.AttributeFilePath, "/test/2/3")
|
|
|
|
putPrm.SetObject(raw6)
|
|
_, err = db.Put(context.Background(), putPrm)
|
|
require.NoError(t, err)
|
|
|
|
raw7 := testutil.GenerateObjectWithCID(cnr)
|
|
var attr objectSDK.Attribute
|
|
attr.SetKey(objectSDK.AttributeFilePath)
|
|
attr.SetValue("/test/3/4")
|
|
attrs := raw7.Attributes()
|
|
attrs = append(attrs, attr)
|
|
ech := objectSDK.NewECHeader(objectSDK.ECParentInfo{
|
|
ID: oidtest.ID(),
|
|
Attributes: attrs,
|
|
}, 0, 3, []byte{}, 0)
|
|
raw7.SetECHeader(ech)
|
|
putPrm.SetObject(raw7)
|
|
_, err = db.Put(context.Background(), putPrm)
|
|
require.NoError(t, err)
|
|
var raw7Parent oid.Address
|
|
raw7Parent.SetContainer(cnr)
|
|
raw7Parent.SetObject(ech.Parent())
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter("foo", "bar", objectSDK.MatchStringEqual)
|
|
testSelect2(t, db, cnr, fs, index,
|
|
object.AddressOf(raw1),
|
|
object.AddressOf(raw2),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter("x", "y", objectSDK.MatchStringEqual)
|
|
testSelect2(t, db, cnr, fs, index, object.AddressOf(raw1))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter("x", "y", objectSDK.MatchStringNotEqual)
|
|
testSelect2(t, db, cnr, fs, index, object.AddressOf(raw2))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter("a", "b", objectSDK.MatchStringEqual)
|
|
testSelect2(t, db, cnr, fs, index, object.AddressOf(raw3))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter("c", "d", objectSDK.MatchStringEqual)
|
|
testSelect2(t, db, cnr, fs, index)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter("foo", "", objectSDK.MatchNotPresent)
|
|
testSelect2(t, db, cnr, fs, index,
|
|
object.AddressOf(raw3),
|
|
object.AddressOf(raw4),
|
|
object.AddressOf(raw5),
|
|
object.AddressOf(raw6),
|
|
object.AddressOf(raw7),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter("a", "", objectSDK.MatchNotPresent)
|
|
testSelect2(t, db, cnr, fs, index,
|
|
object.AddressOf(raw1),
|
|
object.AddressOf(raw2),
|
|
object.AddressOf(raw4),
|
|
object.AddressOf(raw5),
|
|
object.AddressOf(raw6),
|
|
object.AddressOf(raw7),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
testSelect2(t, db, cnr, fs, index,
|
|
object.AddressOf(raw1),
|
|
object.AddressOf(raw2),
|
|
object.AddressOf(raw3),
|
|
object.AddressOf(raw4),
|
|
object.AddressOf(raw5),
|
|
object.AddressOf(raw6),
|
|
object.AddressOf(raw7),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter("key", "", objectSDK.MatchNotPresent)
|
|
testSelect2(t, db, cnr, fs, index,
|
|
object.AddressOf(raw1),
|
|
object.AddressOf(raw2),
|
|
object.AddressOf(raw3),
|
|
object.AddressOf(raw4),
|
|
object.AddressOf(raw5),
|
|
object.AddressOf(raw6),
|
|
object.AddressOf(raw7),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(objectSDK.AttributeFilePath, "/test", objectSDK.MatchCommonPrefix)
|
|
testSelect2(t, db, cnr, fs, index,
|
|
object.AddressOf(raw4),
|
|
object.AddressOf(raw5),
|
|
object.AddressOf(raw6),
|
|
raw7Parent,
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(objectSDK.AttributeFilePath, "/test/1", objectSDK.MatchCommonPrefix)
|
|
testSelect2(t, db, cnr, fs, index,
|
|
object.AddressOf(raw4),
|
|
object.AddressOf(raw5),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(objectSDK.AttributeFilePath, "/test/3/4", objectSDK.MatchStringEqual)
|
|
testSelect2(t, db, cnr, fs, index,
|
|
raw7Parent,
|
|
)
|
|
}
|
|
|
|
func TestDB_SelectRootPhyParent(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
// prepare
|
|
|
|
small := testutil.GenerateObjectWithCID(cnr)
|
|
err := putBig(db, small)
|
|
require.NoError(t, err)
|
|
|
|
ts := testutil.GenerateObjectWithCID(cnr)
|
|
ts.SetType(objectSDK.TypeTombstone)
|
|
err = putBig(db, ts)
|
|
require.NoError(t, err)
|
|
|
|
leftChild := testutil.GenerateObjectWithCID(cnr)
|
|
leftChild.InitRelations()
|
|
err = putBig(db, leftChild)
|
|
require.NoError(t, err)
|
|
|
|
lock := testutil.GenerateObjectWithCID(cnr)
|
|
lock.SetType(objectSDK.TypeLock)
|
|
err = putBig(db, lock)
|
|
require.NoError(t, err)
|
|
|
|
parent := testutil.GenerateObjectWithCID(cnr)
|
|
|
|
rightChild := testutil.GenerateObjectWithCID(cnr)
|
|
rightChild.SetParent(parent)
|
|
idParent, _ := parent.ID()
|
|
rightChild.SetParentID(idParent)
|
|
err = putBig(db, rightChild)
|
|
require.NoError(t, err)
|
|
|
|
link := testutil.GenerateObjectWithCID(cnr)
|
|
link.SetParent(parent)
|
|
link.SetParentID(idParent)
|
|
idLeftChild, _ := leftChild.ID()
|
|
idRightChild, _ := rightChild.ID()
|
|
link.SetChildren(idLeftChild, idRightChild)
|
|
|
|
err = putBig(db, link)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("root objects", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddRootFilter()
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(small),
|
|
object.AddressOf(parent),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterPropertyRoot, "", objectSDK.MatchNotPresent)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("phy objects", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddPhyFilter()
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(small),
|
|
object.AddressOf(ts),
|
|
object.AddressOf(leftChild),
|
|
object.AddressOf(rightChild),
|
|
object.AddressOf(link),
|
|
object.AddressOf(lock),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterPropertyPhy, "", objectSDK.MatchNotPresent)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("regular objects", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderObjectType, v2object.TypeRegular.String(), objectSDK.MatchStringEqual)
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(small),
|
|
object.AddressOf(leftChild),
|
|
object.AddressOf(rightChild),
|
|
object.AddressOf(link),
|
|
object.AddressOf(parent),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderObjectType, v2object.TypeRegular.String(), objectSDK.MatchStringNotEqual)
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(ts),
|
|
object.AddressOf(lock),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderObjectType, "", objectSDK.MatchNotPresent)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("tombstone objects", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderObjectType, v2object.TypeTombstone.String(), objectSDK.MatchStringEqual)
|
|
testSelect(t, db, cnr, fs, object.AddressOf(ts))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderObjectType, v2object.TypeTombstone.String(), objectSDK.MatchStringNotEqual)
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(small),
|
|
object.AddressOf(leftChild),
|
|
object.AddressOf(rightChild),
|
|
object.AddressOf(link),
|
|
object.AddressOf(parent),
|
|
object.AddressOf(lock),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderObjectType, "", objectSDK.MatchNotPresent)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("objects with parent", func(t *testing.T) {
|
|
idParent, _ := parent.ID()
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderParent,
|
|
idParent.EncodeToString(),
|
|
objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(rightChild),
|
|
object.AddressOf(link),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderParent, "", objectSDK.MatchNotPresent)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("all objects", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(small),
|
|
object.AddressOf(ts),
|
|
object.AddressOf(leftChild),
|
|
object.AddressOf(rightChild),
|
|
object.AddressOf(link),
|
|
object.AddressOf(parent),
|
|
object.AddressOf(lock),
|
|
)
|
|
})
|
|
}
|
|
|
|
func TestDB_SelectInhume(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
raw1 := testutil.GenerateObjectWithCID(cnr)
|
|
err := putBig(db, raw1)
|
|
require.NoError(t, err)
|
|
|
|
raw2 := testutil.GenerateObjectWithCID(cnr)
|
|
err = putBig(db, raw2)
|
|
require.NoError(t, err)
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(raw1),
|
|
object.AddressOf(raw2),
|
|
)
|
|
|
|
err = metaInhume(db, object.AddressOf(raw2), oidtest.ID())
|
|
require.NoError(t, err)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(raw1),
|
|
)
|
|
}
|
|
|
|
func TestDB_SelectPayloadHash(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
raw1 := testutil.GenerateObjectWithCID(cnr)
|
|
err := putBig(db, raw1)
|
|
require.NoError(t, err)
|
|
|
|
raw2 := testutil.GenerateObjectWithCID(cnr)
|
|
err = putBig(db, raw2)
|
|
require.NoError(t, err)
|
|
|
|
cs, _ := raw1.PayloadChecksum()
|
|
payloadHash := hex.EncodeToString(cs.Value())
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadHash,
|
|
payloadHash,
|
|
objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw1))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadHash,
|
|
payloadHash[:len(payloadHash)-1],
|
|
objectSDK.MatchCommonPrefix)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw1))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadHash,
|
|
payloadHash,
|
|
objectSDK.MatchStringNotEqual)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw2))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadHash,
|
|
"",
|
|
objectSDK.MatchNotPresent)
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
|
|
t.Run("invalid hashes", func(t *testing.T) {
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadHash,
|
|
payloadHash[:len(payloadHash)-1],
|
|
objectSDK.MatchStringNotEqual)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw1), object.AddressOf(raw2))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadHash,
|
|
payloadHash[:len(payloadHash)-2]+"x",
|
|
objectSDK.MatchCommonPrefix)
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadHash,
|
|
payloadHash[:len(payloadHash)-3]+"x0",
|
|
objectSDK.MatchCommonPrefix)
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
}
|
|
|
|
func TestDB_SelectWithSlowFilters(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
v20 := new(version.Version)
|
|
v20.SetMajor(2)
|
|
|
|
var v21 version.Version
|
|
v21.SetMajor(2)
|
|
v21.SetMinor(1)
|
|
|
|
raw1 := testutil.GenerateObjectWithCID(cnr)
|
|
raw1.SetPayloadSize(10)
|
|
raw1.SetCreationEpoch(11)
|
|
raw1.SetVersion(v20)
|
|
err := putBig(db, raw1)
|
|
require.NoError(t, err)
|
|
|
|
raw2 := testutil.GenerateObjectWithCID(cnr)
|
|
raw2.SetPayloadSize(20)
|
|
raw2.SetCreationEpoch(21)
|
|
raw2.SetVersion(&v21)
|
|
err = putBig(db, raw2)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("object with TZHash", func(t *testing.T) {
|
|
cs, _ := raw1.PayloadHomomorphicHash()
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderHomomorphicHash,
|
|
hex.EncodeToString(cs.Value()),
|
|
objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw1))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderHomomorphicHash,
|
|
hex.EncodeToString(cs.Value()),
|
|
objectSDK.MatchStringNotEqual)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw2))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderHomomorphicHash,
|
|
"",
|
|
objectSDK.MatchNotPresent)
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("object with payload length", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadLength, "20", objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw2))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadLength, "20", objectSDK.MatchStringNotEqual)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw1))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderPayloadLength, "", objectSDK.MatchNotPresent)
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("object with creation epoch", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderCreationEpoch, "11", objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw1))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderCreationEpoch, "11", objectSDK.MatchStringNotEqual)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw2))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderCreationEpoch, "", objectSDK.MatchNotPresent)
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderCreationEpoch, "1", objectSDK.MatchCommonPrefix)
|
|
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw1))
|
|
})
|
|
|
|
t.Run("object with version", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectVersionFilter(objectSDK.MatchStringEqual, v21)
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw2))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectVersionFilter(objectSDK.MatchStringNotEqual, v21)
|
|
testSelect(t, db, cnr, fs, object.AddressOf(raw1))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectVersionFilter(objectSDK.MatchNotPresent, version.Version{})
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
}
|
|
|
|
func TestDB_SelectObjectID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
// prepare
|
|
|
|
parent := testutil.GenerateObjectWithCID(cnr)
|
|
|
|
regular := testutil.GenerateObjectWithCID(cnr)
|
|
idParent, _ := parent.ID()
|
|
regular.SetParentID(idParent)
|
|
regular.SetParent(parent)
|
|
|
|
err := putBig(db, regular)
|
|
require.NoError(t, err)
|
|
|
|
ts := testutil.GenerateObjectWithCID(cnr)
|
|
ts.SetType(objectSDK.TypeTombstone)
|
|
err = putBig(db, ts)
|
|
require.NoError(t, err)
|
|
|
|
lock := testutil.GenerateObjectWithCID(cnr)
|
|
lock.SetType(objectSDK.TypeLock)
|
|
err = putBig(db, lock)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("not found objects", func(t *testing.T) {
|
|
raw := testutil.GenerateObjectWithCID(cnr)
|
|
|
|
id, _ := raw.ID()
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, id)
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringNotEqual, id)
|
|
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(regular),
|
|
object.AddressOf(parent),
|
|
object.AddressOf(ts),
|
|
object.AddressOf(lock),
|
|
)
|
|
})
|
|
|
|
t.Run("regular objects", func(t *testing.T) {
|
|
id, _ := regular.ID()
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, id)
|
|
testSelect(t, db, cnr, fs, object.AddressOf(regular))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringNotEqual, id)
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(parent),
|
|
object.AddressOf(ts),
|
|
object.AddressOf(lock),
|
|
)
|
|
})
|
|
|
|
t.Run("tombstone objects", func(t *testing.T) {
|
|
id, _ := ts.ID()
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, id)
|
|
testSelect(t, db, cnr, fs, object.AddressOf(ts))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringNotEqual, id)
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(regular),
|
|
object.AddressOf(parent),
|
|
object.AddressOf(lock),
|
|
)
|
|
})
|
|
|
|
t.Run("parent objects", func(t *testing.T) {
|
|
id, _ := parent.ID()
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, id)
|
|
testSelect(t, db, cnr, fs, object.AddressOf(parent))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringNotEqual, id)
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(regular),
|
|
object.AddressOf(ts),
|
|
object.AddressOf(lock),
|
|
)
|
|
})
|
|
|
|
t.Run("lock objects", func(t *testing.T) {
|
|
id, _ := lock.ID()
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, id)
|
|
testSelect(t, db, cnr, fs, object.AddressOf(lock))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectIDFilter(objectSDK.MatchStringNotEqual, id)
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(regular),
|
|
object.AddressOf(parent),
|
|
object.AddressOf(ts),
|
|
)
|
|
})
|
|
}
|
|
|
|
func TestDB_SelectOwnerID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
// prepare
|
|
|
|
parent := testutil.GenerateObjectWithCID(cnr)
|
|
|
|
regular := testutil.GenerateObjectWithCID(cnr)
|
|
idParent, _ := parent.ID()
|
|
regular.SetParentID(idParent)
|
|
regular.SetParent(parent)
|
|
|
|
err := putBig(db, regular)
|
|
require.NoError(t, err)
|
|
|
|
ts := testutil.GenerateObjectWithCID(cnr)
|
|
ts.SetType(objectSDK.TypeTombstone)
|
|
err = putBig(db, ts)
|
|
require.NoError(t, err)
|
|
|
|
lock := testutil.GenerateObjectWithCID(cnr)
|
|
lock.SetType(objectSDK.TypeLock)
|
|
err = putBig(db, lock)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("not found objects", func(t *testing.T) {
|
|
raw := testutil.GenerateObjectWithCID(cnr)
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringEqual, raw.OwnerID())
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringNotEqual, raw.OwnerID())
|
|
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(regular),
|
|
object.AddressOf(parent),
|
|
object.AddressOf(ts),
|
|
object.AddressOf(lock),
|
|
)
|
|
})
|
|
|
|
t.Run("regular objects", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringEqual, regular.OwnerID())
|
|
testSelect(t, db, cnr, fs, object.AddressOf(regular))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringNotEqual, regular.OwnerID())
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(parent),
|
|
object.AddressOf(ts),
|
|
object.AddressOf(lock),
|
|
)
|
|
})
|
|
|
|
t.Run("tombstone objects", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringEqual, ts.OwnerID())
|
|
testSelect(t, db, cnr, fs, object.AddressOf(ts))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringNotEqual, ts.OwnerID())
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(regular),
|
|
object.AddressOf(parent),
|
|
object.AddressOf(lock),
|
|
)
|
|
})
|
|
|
|
t.Run("parent objects", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringEqual, parent.OwnerID())
|
|
testSelect(t, db, cnr, fs, object.AddressOf(parent))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringNotEqual, parent.OwnerID())
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(regular),
|
|
object.AddressOf(ts),
|
|
object.AddressOf(lock),
|
|
)
|
|
})
|
|
|
|
t.Run("lock objects", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringEqual, lock.OwnerID())
|
|
testSelect(t, db, cnr, fs, object.AddressOf(lock))
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringNotEqual, lock.OwnerID())
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(regular),
|
|
object.AddressOf(parent),
|
|
object.AddressOf(ts),
|
|
)
|
|
})
|
|
}
|
|
|
|
func TestDB_SelectECWithFastAndSlowFilters(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
ecChunk1 := oidtest.ID()
|
|
ecChunk2 := oidtest.ID()
|
|
ecParent := oidtest.ID()
|
|
var ecParentAddr oid.Address
|
|
ecParentAddr.SetContainer(cnr)
|
|
ecParentAddr.SetObject(ecParent)
|
|
var ecParentAttr []objectSDK.Attribute
|
|
var attr objectSDK.Attribute
|
|
attr.SetKey(objectSDK.AttributeFilePath)
|
|
attr.SetValue("/1/2/3")
|
|
ecParentAttr = append(ecParentAttr, attr)
|
|
|
|
chunkObj := testutil.GenerateObjectWithCID(cnr)
|
|
chunkObj.SetID(ecChunk1)
|
|
chunkObj.SetPayload([]byte{0, 1, 2, 3, 4})
|
|
chunkObj.SetPayloadSize(uint64(5))
|
|
chunkObj.SetECHeader(objectSDK.NewECHeader(objectSDK.ECParentInfo{ID: ecParent, Attributes: ecParentAttr}, 0, 3, []byte{}, 0))
|
|
|
|
chunkObj2 := testutil.GenerateObjectWithCID(cnr)
|
|
chunkObj2.SetID(ecChunk2)
|
|
chunkObj2.SetPayload([]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9})
|
|
chunkObj2.SetPayloadSize(uint64(10))
|
|
chunkObj2.SetECHeader(objectSDK.NewECHeader(objectSDK.ECParentInfo{ID: ecParent, Attributes: ecParentAttr}, 1, 3, []byte{}, 0))
|
|
|
|
// put object with EC
|
|
|
|
var prm meta.PutPrm
|
|
prm.SetObject(chunkObj)
|
|
_, err := db.Put(context.Background(), prm)
|
|
require.NoError(t, err)
|
|
|
|
prm.SetObject(chunkObj2)
|
|
_, err = db.Put(context.Background(), prm)
|
|
require.NoError(t, err)
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddRootFilter()
|
|
fs.AddFilter(objectSDK.AttributeFilePath, "/1/2/3", objectSDK.MatchCommonPrefix)
|
|
testSelect(t, db, cnr, fs, ecParentAddr)
|
|
}
|
|
|
|
type testTarget struct {
|
|
objects []*objectSDK.Object
|
|
}
|
|
|
|
func (tt *testTarget) WriteObject(_ context.Context, obj *objectSDK.Object) error {
|
|
tt.objects = append(tt.objects, obj)
|
|
return nil
|
|
}
|
|
|
|
func cutObject(t *testing.T, p transformer.ChunkedObjectWriter, hdr *objectSDK.Object, size int) *transformer.AccessIdentifiers {
|
|
ctx := context.Background()
|
|
require.NoError(t, p.WriteHeader(ctx, hdr))
|
|
|
|
payload := make([]byte, size)
|
|
rand.New(rand.NewSource(0)).Read(payload)
|
|
|
|
_, err := p.Write(ctx, payload)
|
|
require.NoError(t, err)
|
|
|
|
ids, err := p.Close(ctx)
|
|
require.NoError(t, err)
|
|
return ids
|
|
}
|
|
|
|
func TestDB_RawHead_SplitInfo(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
partSize = 10
|
|
partCount = 2
|
|
dataCount = 2
|
|
parityCount = 1
|
|
)
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
pk, err := keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
|
|
tt := new(testTarget)
|
|
p := transformer.NewPayloadSizeLimiter(transformer.Params{
|
|
Key: &pk.PrivateKey,
|
|
NextTargetInit: func() transformer.ObjectWriter { return tt },
|
|
NetworkState: epochState{e: 1},
|
|
MaxSize: partSize,
|
|
})
|
|
|
|
hdr := objectSDK.New()
|
|
hdr.SetContainerID(cnr)
|
|
hdr.SetOwnerID(usertest.ID())
|
|
ids := cutObject(t, p, hdr, partSize*partCount)
|
|
require.Equal(t, len(tt.objects), partCount+1)
|
|
|
|
t.Run("rep", func(t *testing.T) {
|
|
testGetRawSplitInfo(t, cnr, ids, tt.objects[partCount], tt.objects[partCount-1])
|
|
})
|
|
t.Run("with ec", func(t *testing.T) {
|
|
ec, err := erasurecode.NewConstructor(dataCount, parityCount)
|
|
require.NoError(t, err)
|
|
|
|
cs, err := ec.Split(tt.objects[partCount-1], &pk.PrivateKey)
|
|
require.NoError(t, err)
|
|
|
|
testGetRawSplitInfo(t, cnr, ids, tt.objects[partCount], cs[0])
|
|
})
|
|
}
|
|
|
|
func testGetRawSplitInfo(t *testing.T, cnr cidSDK.ID, ids *transformer.AccessIdentifiers, linking, lastPart *objectSDK.Object) {
|
|
expectedLinkID, ok := linking.ID()
|
|
require.True(t, ok)
|
|
|
|
t.Run("first last, then linking", func(t *testing.T) {
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
require.NoError(t, metaPut(db, lastPart, nil))
|
|
require.NoError(t, metaPut(db, linking, nil))
|
|
|
|
var addr oid.Address
|
|
addr.SetContainer(cnr)
|
|
addr.SetObject(*ids.ParentID)
|
|
|
|
_, err := metaGet(db, addr, true)
|
|
|
|
var siErr *objectSDK.SplitInfoError
|
|
require.ErrorAs(t, err, &siErr)
|
|
|
|
lastID, ok := siErr.SplitInfo().LastPart()
|
|
require.True(t, ok)
|
|
require.Equal(t, ids.SelfID, lastID)
|
|
|
|
linkID, ok := siErr.SplitInfo().Link()
|
|
require.True(t, ok)
|
|
require.Equal(t, expectedLinkID, linkID)
|
|
})
|
|
t.Run("first linking, then last", func(t *testing.T) {
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
require.NoError(t, metaPut(db, linking, nil))
|
|
require.NoError(t, metaPut(db, lastPart, nil))
|
|
|
|
var addr oid.Address
|
|
addr.SetContainer(cnr)
|
|
addr.SetObject(*ids.ParentID)
|
|
|
|
_, err := metaGet(db, addr, true)
|
|
|
|
var siErr *objectSDK.SplitInfoError
|
|
require.ErrorAs(t, err, &siErr)
|
|
|
|
lastID, ok := siErr.SplitInfo().LastPart()
|
|
require.True(t, ok)
|
|
require.Equal(t, ids.SelfID, lastID)
|
|
|
|
linkID, ok := siErr.SplitInfo().Link()
|
|
require.True(t, ok)
|
|
require.Equal(t, expectedLinkID, linkID)
|
|
})
|
|
t.Run("only last part", func(t *testing.T) {
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
require.NoError(t, metaPut(db, lastPart, nil))
|
|
|
|
var addr oid.Address
|
|
addr.SetContainer(cnr)
|
|
addr.SetObject(*ids.ParentID)
|
|
|
|
_, err := metaGet(db, addr, true)
|
|
|
|
var siErr *objectSDK.SplitInfoError
|
|
require.ErrorAs(t, err, &siErr)
|
|
|
|
lastPart, ok := siErr.SplitInfo().LastPart()
|
|
require.True(t, ok)
|
|
require.Equal(t, ids.SelfID, lastPart)
|
|
})
|
|
}
|
|
|
|
func TestDB_SelectSplitID_EC(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
partSize = 10
|
|
partCount = 2
|
|
dataCount = 2
|
|
parityCount = 1
|
|
)
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
pk, err := keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
|
|
tt := new(testTarget)
|
|
p := transformer.NewPayloadSizeLimiter(transformer.Params{
|
|
Key: &pk.PrivateKey,
|
|
NextTargetInit: func() transformer.ObjectWriter { return tt },
|
|
NetworkState: epochState{e: 1},
|
|
MaxSize: partSize,
|
|
})
|
|
|
|
hdr := objectSDK.New()
|
|
hdr.SetContainerID(cnr)
|
|
hdr.SetOwnerID(usertest.ID())
|
|
cutObject(t, p, hdr, partSize*partCount)
|
|
require.Equal(t, len(tt.objects), partCount+1)
|
|
|
|
split := tt.objects[0].SplitID()
|
|
require.NotNil(t, split)
|
|
|
|
ec, err := erasurecode.NewConstructor(dataCount, parityCount)
|
|
require.NoError(t, err)
|
|
|
|
for i := range partCount {
|
|
cs, err := ec.Split(tt.objects[i], &pk.PrivateKey)
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, putBig(db, cs[0]))
|
|
}
|
|
|
|
t.Run("not present", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderSplitID, "", objectSDK.MatchNotPresent)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("split id", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderSplitID, split.String(), objectSDK.MatchStringEqual)
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(tt.objects[0]),
|
|
object.AddressOf(tt.objects[1]),
|
|
)
|
|
})
|
|
|
|
t.Run("empty split", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderSplitID, "", objectSDK.MatchStringEqual)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("unknown split id", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderSplitID,
|
|
objectSDK.NewSplitID().String(),
|
|
objectSDK.MatchStringEqual)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
}
|
|
|
|
func TestDB_SelectSplitID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
child1 := testutil.GenerateObjectWithCID(cnr)
|
|
child2 := testutil.GenerateObjectWithCID(cnr)
|
|
child3 := testutil.GenerateObjectWithCID(cnr)
|
|
|
|
split1 := objectSDK.NewSplitID()
|
|
split2 := objectSDK.NewSplitID()
|
|
|
|
child1.SetSplitID(split1)
|
|
child2.SetSplitID(split1)
|
|
child3.SetSplitID(split2)
|
|
|
|
require.NoError(t, putBig(db, child1))
|
|
require.NoError(t, putBig(db, child2))
|
|
require.NoError(t, putBig(db, child3))
|
|
|
|
t.Run("not present", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderSplitID, "", objectSDK.MatchNotPresent)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("split id", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderSplitID, split1.String(), objectSDK.MatchStringEqual)
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(child1),
|
|
object.AddressOf(child2),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderSplitID, split2.String(), objectSDK.MatchStringEqual)
|
|
testSelect(t, db, cnr, fs, object.AddressOf(child3))
|
|
})
|
|
|
|
t.Run("empty split", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderSplitID, "", objectSDK.MatchStringEqual)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("unknown split id", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter(v2object.FilterHeaderSplitID,
|
|
objectSDK.NewSplitID().String(),
|
|
objectSDK.MatchStringEqual)
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
}
|
|
|
|
func TestDB_SelectContainerID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t)
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
cnr := cidtest.ID()
|
|
|
|
obj1 := testutil.GenerateObjectWithCID(cnr)
|
|
err := putBig(db, obj1)
|
|
require.NoError(t, err)
|
|
|
|
obj2 := testutil.GenerateObjectWithCID(cnr)
|
|
err = putBig(db, obj2)
|
|
require.NoError(t, err)
|
|
|
|
t.Run("same cid", func(t *testing.T) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectContainerIDFilter(objectSDK.MatchStringEqual, cnr)
|
|
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(obj1),
|
|
object.AddressOf(obj2),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectContainerIDFilter(objectSDK.MatchStringNotEqual, cnr)
|
|
|
|
testSelect(t, db, cnr, fs,
|
|
object.AddressOf(obj1),
|
|
object.AddressOf(obj2),
|
|
)
|
|
|
|
fs = objectSDK.SearchFilters{}
|
|
fs.AddObjectContainerIDFilter(objectSDK.MatchNotPresent, cnr)
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
|
|
t.Run("not same cid", func(t *testing.T) {
|
|
newCnr := cidtest.ID()
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddObjectContainerIDFilter(objectSDK.MatchStringEqual, newCnr)
|
|
|
|
testSelect(t, db, cnr, fs)
|
|
})
|
|
}
|
|
|
|
func BenchmarkSelect(b *testing.B) {
|
|
const objCount = 1000
|
|
db := newDB(b)
|
|
defer func() { require.NoError(b, db.Close()) }()
|
|
|
|
cid := cidtest.ID()
|
|
|
|
for i := range objCount {
|
|
var attr objectSDK.Attribute
|
|
attr.SetKey("myHeader")
|
|
attr.SetValue(strconv.Itoa(i))
|
|
obj := testutil.GenerateObjectWithCID(cid)
|
|
obj.SetAttributes(attr)
|
|
require.NoError(b, metaPut(db, obj, nil))
|
|
}
|
|
|
|
b.Run("string equal", func(b *testing.B) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter("myHeader", strconv.Itoa(objCount/2), objectSDK.MatchStringEqual)
|
|
benchmarkSelect(b, db, cid, fs, 1)
|
|
})
|
|
b.Run("string not equal", func(b *testing.B) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter("myHeader", strconv.Itoa(objCount/2), objectSDK.MatchStringNotEqual)
|
|
benchmarkSelect(b, db, cid, fs, objCount-1)
|
|
})
|
|
b.Run("common prefix", func(b *testing.B) {
|
|
prefix := "99"
|
|
n := 1 /* 99 */ + 10 /* 990..999 */
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter("myHeader", prefix, objectSDK.MatchCommonPrefix)
|
|
benchmarkSelect(b, db, cid, fs, n)
|
|
})
|
|
b.Run("unknown", func(b *testing.B) {
|
|
fs := objectSDK.SearchFilters{}
|
|
fs.AddFilter("myHeader", strconv.Itoa(objCount/2), objectSDK.MatchUnknown)
|
|
benchmarkSelect(b, db, cid, fs, 0)
|
|
})
|
|
}
|
|
|
|
func TestExpiredObjects(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
db := newDB(t, meta.WithEpochState(epochState{currEpoch}))
|
|
defer func() { require.NoError(t, db.Close()) }()
|
|
|
|
checkExpiredObjects(t, db, func(exp, nonExp *objectSDK.Object) {
|
|
cidExp, _ := exp.ContainerID()
|
|
cidNonExp, _ := nonExp.ContainerID()
|
|
|
|
objs, err := metaSelect(db, cidExp, objectSDK.SearchFilters{}, false)
|
|
require.NoError(t, err)
|
|
require.Empty(t, objs) // expired object should not be returned
|
|
|
|
objs, err = metaSelect(db, cidNonExp, objectSDK.SearchFilters{}, false)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, objs)
|
|
})
|
|
}
|
|
|
|
func benchmarkSelect(b *testing.B, db *meta.DB, cid cidSDK.ID, fs objectSDK.SearchFilters, expected int) {
|
|
var prm meta.SelectPrm
|
|
prm.SetContainerID(cid)
|
|
prm.SetFilters(fs)
|
|
|
|
for range b.N {
|
|
res, err := db.Select(context.Background(), prm)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if len(res.AddressList()) != expected {
|
|
b.Fatalf("expected %d items, got %d", expected, len(res.AddressList()))
|
|
}
|
|
}
|
|
}
|
|
|
|
func metaSelect(db *meta.DB, cnr cidSDK.ID, fs objectSDK.SearchFilters, useAttributeIndex bool) ([]oid.Address, error) {
|
|
var prm meta.SelectPrm
|
|
prm.SetFilters(fs)
|
|
prm.SetContainerID(cnr)
|
|
prm.SetUseAttributeIndex(useAttributeIndex)
|
|
|
|
res, err := db.Select(context.Background(), prm)
|
|
return res.AddressList(), err
|
|
}
|