Remove outdated code of metabase and localstore
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
869d9e571c
commit
a875d80491
41 changed files with 1725 additions and 3123 deletions
|
@ -1,226 +1,409 @@
|
|||
package meta
|
||||
package meta_test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"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"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
v2object "github.com/nspcc-dev/neofs-api-go/v2/object"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func addNFilters(fs *objectSDK.SearchFilters, n int) {
|
||||
for i := 0; i < n; i++ {
|
||||
key := make([]byte, 32)
|
||||
rand.Read(key)
|
||||
|
||||
val := make([]byte, 32)
|
||||
rand.Read(val)
|
||||
|
||||
fs.AddFilter(string(key), string(val), objectSDK.MatchStringEqual)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDB_Select(b *testing.B) {
|
||||
db := newDB(b)
|
||||
|
||||
defer releaseDB(db)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
obj := generateObject(b, testPrm{
|
||||
withParent: true,
|
||||
attrNum: 100,
|
||||
})
|
||||
|
||||
require.NoError(b, db.Put(obj))
|
||||
}
|
||||
|
||||
for _, item := range []struct {
|
||||
name string
|
||||
filters func(*objectSDK.SearchFilters)
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
filters: func(*objectSDK.SearchFilters) {
|
||||
return
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "1 filter",
|
||||
filters: func(fs *objectSDK.SearchFilters) {
|
||||
addNFilters(fs, 1)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "10 filters",
|
||||
filters: func(fs *objectSDK.SearchFilters) {
|
||||
addNFilters(fs, 10)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "100 filters",
|
||||
filters: func(fs *objectSDK.SearchFilters) {
|
||||
addNFilters(fs, 100)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "1000 filters",
|
||||
filters: func(fs *objectSDK.SearchFilters) {
|
||||
addNFilters(fs, 1000)
|
||||
},
|
||||
},
|
||||
} {
|
||||
b.Run(item.name, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
b.StopTimer()
|
||||
fs := new(objectSDK.SearchFilters)
|
||||
item.filters(fs)
|
||||
b.StartTimer()
|
||||
|
||||
_, err := db.Select(*fs)
|
||||
|
||||
b.StopTimer()
|
||||
require.NoError(b, err)
|
||||
b.StartTimer()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMismatchAfterMatch(t *testing.T) {
|
||||
func TestDB_SelectUserAttributes(t *testing.T) {
|
||||
db := newDB(t)
|
||||
defer releaseDB(db)
|
||||
|
||||
obj := generateObject(t, testPrm{
|
||||
attrNum: 1,
|
||||
})
|
||||
cid := testCID()
|
||||
|
||||
require.NoError(t, db.Put(obj))
|
||||
raw1 := generateRawObjectWithCID(t, cid)
|
||||
addAttribute(raw1, "foo", "bar")
|
||||
addAttribute(raw1, "x", "y")
|
||||
|
||||
a := obj.Attributes()[0]
|
||||
err := db.Put(raw1.Object(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
fs := objectSDK.SearchFilters{}
|
||||
raw2 := generateRawObjectWithCID(t, cid)
|
||||
addAttribute(raw2, "foo", "bar")
|
||||
addAttribute(raw2, "x", "z")
|
||||
|
||||
// 1st - mismatching filter
|
||||
fs.AddFilter(a.Key(), a.Value()+"1", objectSDK.MatchStringEqual)
|
||||
err = db.Put(raw2.Object(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// 2nd - matching filter
|
||||
fs.AddFilter(a.Key(), a.Value(), objectSDK.MatchStringEqual)
|
||||
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 addCommonAttribute(objs ...*object.Object) *objectSDK.Attribute {
|
||||
aCommon := objectSDK.NewAttribute()
|
||||
aCommon.SetKey("common key")
|
||||
aCommon.SetValue("common value")
|
||||
func TestDB_SelectRootPhyParent(t *testing.T) {
|
||||
db := newDB(t)
|
||||
defer releaseDB(db)
|
||||
|
||||
for _, o := range objs {
|
||||
object.NewRawFromObject(o).SetAttributes(
|
||||
append(o.Attributes(), aCommon)...,
|
||||
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(),
|
||||
)
|
||||
}
|
||||
|
||||
return aCommon
|
||||
}
|
||||
|
||||
func TestSelectRemoved(t *testing.T) {
|
||||
db := newDB(t)
|
||||
defer releaseDB(db)
|
||||
|
||||
// create 2 objects
|
||||
obj1 := generateObject(t, testPrm{})
|
||||
obj2 := generateObject(t, testPrm{})
|
||||
|
||||
// add common attribute
|
||||
a := addCommonAttribute(obj1, obj2)
|
||||
|
||||
// add to DB
|
||||
require.NoError(t, db.Put(obj1))
|
||||
require.NoError(t, db.Put(obj2))
|
||||
|
||||
fs := objectSDK.SearchFilters{}
|
||||
fs.AddFilter(a.Key(), a.Value(), objectSDK.MatchStringEqual)
|
||||
|
||||
testSelect(t, db, fs, obj1.Address(), obj2.Address())
|
||||
|
||||
// remote 1st object
|
||||
require.NoError(t, db.Delete(obj1.Address()))
|
||||
|
||||
testSelect(t, db, fs, obj2.Address())
|
||||
}
|
||||
|
||||
func TestMissingObjectAttribute(t *testing.T) {
|
||||
db := newDB(t)
|
||||
defer releaseDB(db)
|
||||
|
||||
// add object w/o attribute
|
||||
obj1 := generateObject(t, testPrm{
|
||||
attrNum: 1,
|
||||
})
|
||||
|
||||
// add object w/o attribute
|
||||
obj2 := generateObject(t, testPrm{})
|
||||
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(),
|
||||
)
|
||||
})
|
||||
|
||||
a1 := obj1.Attributes()[0]
|
||||
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(),
|
||||
)
|
||||
})
|
||||
|
||||
// add common attribute
|
||||
aCommon := addCommonAttribute(obj1, obj2)
|
||||
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())
|
||||
})
|
||||
|
||||
// write to DB
|
||||
require.NoError(t, db.Put(obj1))
|
||||
require.NoError(t, db.Put(obj2))
|
||||
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())
|
||||
})
|
||||
|
||||
fs := objectSDK.SearchFilters{}
|
||||
t.Run("objects with parent", func(t *testing.T) {
|
||||
fs := generateSearchFilter(cid)
|
||||
fs.AddFilter(v2object.FilterHeaderParent,
|
||||
parent.ID().String(),
|
||||
objectSDK.MatchStringEqual)
|
||||
|
||||
// 1st filter by common attribute
|
||||
fs.AddFilter(aCommon.Key(), aCommon.Value(), objectSDK.MatchStringEqual)
|
||||
testSelect(t, db, fs,
|
||||
rightChild.Object().Address(),
|
||||
link.Object().Address(),
|
||||
)
|
||||
})
|
||||
|
||||
// next filter by attribute from 1st object only
|
||||
fs.AddFilter(a1.Key(), a1.Value(), objectSDK.MatchStringEqual)
|
||||
|
||||
testSelect(t, db, fs, obj1.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 TestSelectParentID(t *testing.T) {
|
||||
func TestDB_SelectInhume(t *testing.T) {
|
||||
db := newDB(t)
|
||||
defer releaseDB(db)
|
||||
|
||||
// generate 2 objects
|
||||
obj1 := generateObject(t, testPrm{})
|
||||
obj2 := generateObject(t, testPrm{})
|
||||
cid := testCID()
|
||||
|
||||
// set parent ID of 1st object
|
||||
par := testOID()
|
||||
object.NewRawFromObject(obj1).SetParentID(par)
|
||||
raw1 := generateRawObjectWithCID(t, cid)
|
||||
err := db.Put(raw1.Object(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// store objects
|
||||
require.NoError(t, db.Put(obj1))
|
||||
require.NoError(t, db.Put(obj2))
|
||||
raw2 := generateRawObjectWithCID(t, cid)
|
||||
err = db.Put(raw2.Object(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// filter by parent ID
|
||||
fs := objectSDK.SearchFilters{}
|
||||
fs.AddParentIDFilter(objectSDK.MatchStringEqual, par)
|
||||
fs := generateSearchFilter(cid)
|
||||
testSelect(t, db, fs,
|
||||
raw1.Object().Address(),
|
||||
raw2.Object().Address(),
|
||||
)
|
||||
|
||||
testSelect(t, db, fs, obj1.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 TestSelectObjectID(t *testing.T) {
|
||||
func TestDB_SelectPayloadHash(t *testing.T) {
|
||||
db := newDB(t)
|
||||
defer releaseDB(db)
|
||||
|
||||
// generate object
|
||||
obj := generateObject(t, testPrm{})
|
||||
cid := testCID()
|
||||
|
||||
// store objects
|
||||
require.NoError(t, db.Put(obj))
|
||||
raw1 := generateRawObjectWithCID(t, cid)
|
||||
err := db.Put(raw1.Object(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// filter by object ID
|
||||
fs := objectSDK.SearchFilters{}
|
||||
fs.AddObjectIDFilter(objectSDK.MatchStringEqual, obj.ID())
|
||||
raw2 := generateRawObjectWithCID(t, cid)
|
||||
err = db.Put(raw2.Object(), nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
testSelect(t, db, fs, obj.Address())
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue