2020-10-28 14:49:30 +00:00
|
|
|
package meta
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/rand"
|
|
|
|
"crypto/sha256"
|
|
|
|
"os"
|
|
|
|
"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"
|
|
|
|
"github.com/nspcc-dev/neofs-api-go/pkg/owner"
|
2020-10-29 16:12:38 +00:00
|
|
|
v2object "github.com/nspcc-dev/neofs-api-go/v2/object"
|
2020-10-28 14:49:30 +00:00
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
|
|
|
"github.com/nspcc-dev/neofs-node/pkg/util/test"
|
2020-11-06 09:41:59 +00:00
|
|
|
"github.com/pkg/errors"
|
2020-10-28 14:49:30 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"go.etcd.io/bbolt"
|
|
|
|
)
|
|
|
|
|
|
|
|
func testSelect(t *testing.T, db *DB, fs objectSDK.SearchFilters, exp ...*objectSDK.Address) {
|
|
|
|
res, err := db.Select(fs)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, res, len(exp))
|
|
|
|
|
|
|
|
for i := range exp {
|
|
|
|
require.Contains(t, res, exp[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-29 12:03:55 +00:00
|
|
|
func testCID() *container.ID {
|
|
|
|
cs := [sha256.Size]byte{}
|
|
|
|
rand.Read(cs[:])
|
|
|
|
|
|
|
|
id := container.NewID()
|
|
|
|
id.SetSHA256(cs)
|
|
|
|
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
|
|
|
func testOID() *objectSDK.ID {
|
|
|
|
cs := [sha256.Size]byte{}
|
|
|
|
rand.Read(cs[:])
|
|
|
|
|
|
|
|
id := objectSDK.NewID()
|
|
|
|
id.SetSHA256(cs)
|
|
|
|
|
|
|
|
return id
|
|
|
|
}
|
|
|
|
|
2020-10-28 14:49:30 +00:00
|
|
|
func TestDB(t *testing.T) {
|
|
|
|
version := pkg.NewVersion()
|
|
|
|
version.SetMajor(2)
|
|
|
|
version.SetMinor(1)
|
|
|
|
|
2020-10-29 12:03:55 +00:00
|
|
|
cid := testCID()
|
2020-10-28 14:49:30 +00:00
|
|
|
|
|
|
|
w, err := owner.NEO3WalletFromPublicKey(&test.DecodeKey(-1).PublicKey)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ownerID := owner.NewID()
|
|
|
|
ownerID.SetNeo3Wallet(w)
|
|
|
|
|
2020-10-29 12:03:55 +00:00
|
|
|
oid := testOID()
|
2020-10-28 14:49:30 +00:00
|
|
|
|
|
|
|
obj := object.NewRaw()
|
|
|
|
obj.SetID(oid)
|
|
|
|
obj.SetOwnerID(ownerID)
|
|
|
|
obj.SetContainerID(cid)
|
|
|
|
obj.SetVersion(version)
|
|
|
|
|
|
|
|
k, v := "key", "value"
|
|
|
|
|
|
|
|
a := objectSDK.NewAttribute()
|
|
|
|
a.SetKey(k)
|
|
|
|
a.SetValue(v)
|
|
|
|
|
|
|
|
obj.SetAttributes(a)
|
|
|
|
|
2020-11-02 07:55:35 +00:00
|
|
|
db := newDB(t)
|
2020-10-28 14:49:30 +00:00
|
|
|
|
2020-11-02 07:55:35 +00:00
|
|
|
defer releaseDB(db)
|
2020-10-28 14:49:30 +00:00
|
|
|
|
|
|
|
o := obj.Object()
|
|
|
|
|
|
|
|
require.NoError(t, db.Put(o))
|
|
|
|
|
|
|
|
o2, err := db.Get(o.Address())
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
require.Equal(t, o, o2)
|
|
|
|
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
|
|
|
|
|
|
// filter container ID
|
|
|
|
fs.AddObjectContainerIDFilter(objectSDK.MatchStringEqual, cid)
|
|
|
|
testSelect(t, db, fs, o.Address())
|
|
|
|
|
|
|
|
// filter owner ID
|
|
|
|
fs.AddObjectOwnerIDFilter(objectSDK.MatchStringEqual, ownerID)
|
|
|
|
testSelect(t, db, fs, o.Address())
|
|
|
|
|
|
|
|
// filter attribute
|
|
|
|
fs.AddFilter(k, v, objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, fs, o.Address())
|
|
|
|
|
|
|
|
// filter mismatch
|
|
|
|
fs.AddFilter(k, v+"1", objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, fs)
|
|
|
|
}
|
2020-10-29 12:03:55 +00:00
|
|
|
|
|
|
|
func TestDB_Delete(t *testing.T) {
|
2020-11-02 07:55:35 +00:00
|
|
|
db := newDB(t)
|
2020-10-29 12:03:55 +00:00
|
|
|
|
2020-11-02 07:55:35 +00:00
|
|
|
defer releaseDB(db)
|
2020-10-29 12:03:55 +00:00
|
|
|
|
|
|
|
obj := object.NewRaw()
|
|
|
|
obj.SetContainerID(testCID())
|
|
|
|
obj.SetID(testOID())
|
|
|
|
|
|
|
|
o := obj.Object()
|
|
|
|
|
|
|
|
require.NoError(t, db.Put(o))
|
|
|
|
|
|
|
|
addr := o.Address()
|
|
|
|
|
2020-11-02 07:55:35 +00:00
|
|
|
_, err := db.Get(addr)
|
2020-10-29 12:03:55 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
|
|
fs.AddObjectContainerIDFilter(objectSDK.MatchStringEqual, o.GetContainerID())
|
|
|
|
|
|
|
|
testSelect(t, db, fs, o.Address())
|
|
|
|
|
|
|
|
require.NoError(t, db.Delete(addr))
|
|
|
|
|
|
|
|
_, err = db.Get(addr)
|
|
|
|
require.Error(t, err)
|
|
|
|
|
|
|
|
testSelect(t, db, fs)
|
|
|
|
}
|
2020-10-29 16:12:38 +00:00
|
|
|
|
|
|
|
func TestDB_SelectProperties(t *testing.T) {
|
2020-11-02 07:55:35 +00:00
|
|
|
db := newDB(t)
|
2020-10-29 16:12:38 +00:00
|
|
|
|
2020-11-02 07:55:35 +00:00
|
|
|
defer releaseDB(db)
|
2020-10-29 16:12:38 +00:00
|
|
|
|
|
|
|
parent := object.NewRaw()
|
|
|
|
parent.SetContainerID(testCID())
|
|
|
|
parent.SetID(testOID())
|
|
|
|
|
|
|
|
child := object.NewRaw()
|
|
|
|
child.SetContainerID(testCID())
|
|
|
|
child.SetID(testOID())
|
|
|
|
child.SetParent(parent.Object().SDK())
|
|
|
|
|
|
|
|
parAddr := parent.Object().Address()
|
|
|
|
childAddr := child.Object().Address()
|
|
|
|
|
|
|
|
require.NoError(t, db.Put(child.Object()))
|
|
|
|
|
|
|
|
// root filter
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
|
|
fs.AddRootFilter()
|
|
|
|
testSelect(t, db, fs, parAddr)
|
|
|
|
|
|
|
|
// non-root filter
|
|
|
|
fs = fs[:0]
|
|
|
|
fs.AddNonRootFilter()
|
|
|
|
testSelect(t, db, fs, childAddr)
|
|
|
|
|
|
|
|
// root filter (with random false value)
|
|
|
|
fs = fs[:0]
|
|
|
|
fs.AddFilter(v2object.FilterPropertyRoot, "some false value", objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, fs, childAddr)
|
|
|
|
|
|
|
|
// leaf filter
|
|
|
|
fs = fs[:0]
|
|
|
|
fs.AddLeafFilter()
|
|
|
|
testSelect(t, db, fs, childAddr)
|
|
|
|
|
|
|
|
// non-leaf filter
|
|
|
|
fs = fs[:0]
|
|
|
|
fs.AddNonLeafFilter()
|
|
|
|
testSelect(t, db, fs, parAddr)
|
|
|
|
|
|
|
|
// leaf filter (with random false value)
|
|
|
|
fs = fs[:0]
|
|
|
|
fs.AddFilter(v2object.FilterPropertyLeaf, "some false value", objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, fs, parAddr)
|
|
|
|
|
|
|
|
lnk := object.NewRaw()
|
|
|
|
lnk.SetContainerID(testCID())
|
|
|
|
lnk.SetID(testOID())
|
|
|
|
lnk.SetChildren(testOID())
|
|
|
|
|
|
|
|
lnkAddr := lnk.Object().Address()
|
|
|
|
|
|
|
|
require.NoError(t, db.Put(lnk.Object()))
|
|
|
|
|
|
|
|
// childfree filter
|
|
|
|
fs = fs[:0]
|
|
|
|
fs.AddChildfreeFilter()
|
|
|
|
testSelect(t, db, fs, childAddr, parAddr)
|
|
|
|
|
|
|
|
// non-childfree filter
|
|
|
|
fs = fs[:0]
|
|
|
|
fs.AddNonChildfreeFilter()
|
|
|
|
testSelect(t, db, fs, lnkAddr)
|
|
|
|
|
|
|
|
// childfree filter (with random false value)
|
|
|
|
fs = fs[:0]
|
|
|
|
fs.AddFilter(v2object.FilterPropertyChildfree, "some false value", objectSDK.MatchStringEqual)
|
|
|
|
testSelect(t, db, fs, lnkAddr)
|
|
|
|
}
|
2020-11-02 07:37:16 +00:00
|
|
|
|
|
|
|
func TestDB_Path(t *testing.T) {
|
|
|
|
path := t.Name()
|
|
|
|
|
|
|
|
bdb, err := bbolt.Open(path, 0600, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
db := NewDB(bdb)
|
|
|
|
|
2020-11-02 07:55:35 +00:00
|
|
|
defer releaseDB(db)
|
|
|
|
|
2020-11-02 07:37:16 +00:00
|
|
|
require.Equal(t, path, db.Path())
|
|
|
|
}
|
2020-11-02 07:55:35 +00:00
|
|
|
|
|
|
|
func newDB(t testing.TB) *DB {
|
|
|
|
path := t.Name()
|
|
|
|
|
|
|
|
bdb, err := bbolt.Open(path, 0600, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return NewDB(bdb)
|
|
|
|
}
|
|
|
|
|
|
|
|
func releaseDB(db *DB) {
|
|
|
|
db.Close()
|
|
|
|
os.Remove(db.Path())
|
|
|
|
}
|
2020-11-02 08:01:55 +00:00
|
|
|
|
|
|
|
func TestSelectNonExistentAttributes(t *testing.T) {
|
|
|
|
db := newDB(t)
|
|
|
|
|
|
|
|
defer releaseDB(db)
|
|
|
|
|
|
|
|
obj := object.NewRaw()
|
|
|
|
obj.SetID(testOID())
|
|
|
|
obj.SetContainerID(testCID())
|
|
|
|
|
|
|
|
require.NoError(t, db.Put(obj.Object()))
|
|
|
|
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
|
|
|
|
|
|
// add filter by non-existent attribute
|
|
|
|
fs.AddFilter("key", "value", objectSDK.MatchStringEqual)
|
|
|
|
|
|
|
|
res, err := db.Select(fs)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Empty(t, res)
|
|
|
|
}
|
2020-11-06 09:41:59 +00:00
|
|
|
|
|
|
|
func TestVirtualObject(t *testing.T) {
|
|
|
|
db := newDB(t)
|
|
|
|
defer releaseDB(db)
|
|
|
|
|
|
|
|
// create object with parent
|
|
|
|
obj := generateObject(t, testPrm{
|
|
|
|
withParent: true,
|
|
|
|
})
|
|
|
|
|
|
|
|
require.NoError(t, db.Put(obj))
|
|
|
|
|
|
|
|
childAddr := obj.Address()
|
|
|
|
parAddr := obj.GetParent().Address()
|
|
|
|
|
|
|
|
// child object must be readable
|
|
|
|
_, err := db.Get(childAddr)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// parent object must not be readable
|
|
|
|
_, err = db.Get(parAddr)
|
|
|
|
require.True(t, errors.Is(err, errNotFound))
|
|
|
|
|
|
|
|
fs := objectSDK.SearchFilters{}
|
|
|
|
|
|
|
|
// both objects should appear in selection
|
|
|
|
testSelect(t, db, fs, childAddr, parAddr)
|
|
|
|
|
|
|
|
// filter leaves
|
|
|
|
fs.AddLeafFilter()
|
|
|
|
|
|
|
|
// only child object should appear
|
|
|
|
testSelect(t, db, fs, childAddr)
|
|
|
|
|
|
|
|
fs = fs[:0]
|
|
|
|
|
|
|
|
// filter non-leaf objects
|
|
|
|
fs.AddNonLeafFilter()
|
|
|
|
|
|
|
|
// only parent object should appear
|
|
|
|
testSelect(t, db, fs, parAddr)
|
|
|
|
}
|