5
5
"encoding/base64"
6
6
"math/rand"
7
7
"slices"
8
+ "strconv"
8
9
"testing"
9
10
10
11
"github.com/nspcc-dev/neofs-sdk-go/checksum"
@@ -15,11 +16,18 @@ import (
15
16
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
16
17
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
17
18
"github.com/nspcc-dev/neofs-sdk-go/user"
19
+ usertest "github.com/nspcc-dev/neofs-sdk-go/user/test"
18
20
"github.com/nspcc-dev/neofs-sdk-go/version"
19
21
"github.com/stretchr/testify/require"
20
22
"go.etcd.io/bbolt"
21
23
)
22
24
25
+ func sortObjectIDs (ids []oid.ID ) []oid.ID {
26
+ s := slices .Clone (ids )
27
+ slices .SortFunc (s , func (a , b oid.ID ) int { return bytes .Compare (a [:], b [:]) })
28
+ return s
29
+ }
30
+
23
31
func assertAttrPrefixed [T string | []byte ](t testing.TB , mb * bbolt.Bucket , id oid.ID , prefix byte , attr string , val T ) {
24
32
k := []byte {prefix }
25
33
k = append (k , attr ... )
@@ -191,8 +199,7 @@ func TestDB_SearchObjects(t *testing.T) {
191
199
require .NoError (t , err , i )
192
200
}
193
201
194
- idsSorted := slices .Clone (ids )
195
- slices .SortFunc (idsSorted , func (a , b oid.ID ) int { return bytes .Compare (a [:], b [:]) })
202
+ idsSorted := sortObjectIDs (ids )
196
203
197
204
t .Run ("all at once" , func (t * testing.T ) {
198
205
for _ , tc := range []struct {
@@ -259,4 +266,109 @@ func TestDB_SearchObjects(t *testing.T) {
259
266
require .EqualError (t , err , "view BoltDB: unexpected object key len 31, expected 33" )
260
267
})
261
268
})
269
+ t .Run ("filters" , func (t * testing.T ) {
270
+ cnr := cidtest .ID ()
271
+ owner1 , owner2 := usertest .ID (), usertest .ID ()
272
+ const n = 4
273
+ var objs [n ]object.Object
274
+ ids := make ([]oid.ID , len (objs ))
275
+ for i := range objs {
276
+ objs [i ].SetContainerID (cnr )
277
+ objs [i ].SetPayloadChecksum (checksumtest .Checksum ()) // required to Put
278
+ if i % 2 == 0 {
279
+ objs [i ].SetOwnerID (& owner1 )
280
+ } else {
281
+ objs [i ].SetOwnerID (& owner2 )
282
+ }
283
+
284
+ id := oidtest .ID ()
285
+ objs [i ].SetID (id )
286
+
287
+ si := strconv .Itoa (i )
288
+ objs [i ].SetAttributes (
289
+ * object .NewAttribute ("attr_" + si , "val_" + si ),
290
+ * object .NewAttribute ("attr_common" , "val_common" ),
291
+ )
292
+
293
+ require .NoError (t , db .Put (& objs [i ], nil , nil ))
294
+ }
295
+
296
+ ids = sortObjectIDs (ids )
297
+
298
+ check := func (k string , m object.SearchMatchType , v string , matchInds []uint ) {
299
+ var fs object.SearchFilters
300
+ fs .AddFilter ("attr_common" , "val_common" , object .MatchStringEqual )
301
+ fs .AddFilter (k , v , m )
302
+
303
+ res , cursor , err := db .Search (cnr , fs , []string {"attr_common" }, "" , n )
304
+ require .NoError (t , err )
305
+ require .Empty (t , cursor )
306
+ require .Len (t , res , len (matchInds ))
307
+ for i , ind := range matchInds {
308
+ require .Equal (t , ids [ind ], res [i ].ID )
309
+ require .Len (t , res [i ].Attributes , 1 )
310
+ require .Equal (t , "val_common" , res [i ].Attributes [0 ])
311
+ }
312
+ }
313
+
314
+ t .Run ("container" , func (t * testing.T ) {
315
+ // Since container ID is a selection parameter itself, only EQ and PREFIX with
316
+ // CID prefix match. For other prefixes, result is always empty, and it can be
317
+ // obtained without touching the BoltDB.
318
+ check := func (m object.SearchMatchType , v string , match bool ) {
319
+ var inds []uint
320
+ if match {
321
+ inds = []uint {0 , 1 , 2 , 3 }
322
+ }
323
+ check (object .FilterContainerID , m , v , inds )
324
+ }
325
+
326
+ cnrStr := cnr .EncodeToString ()
327
+ otherCnrStr := cidtest .OtherID (cnr ).EncodeToString ()
328
+ check (object .MatchStringEqual , cnrStr , true )
329
+ check (object .MatchStringEqual , otherCnrStr , false )
330
+ check (object .MatchStringNotEqual , cnrStr , false )
331
+ check (object .MatchStringNotEqual , otherCnrStr , true )
332
+ for _ , m := range []object.SearchMatchType {
333
+ object .MatchNotPresent , object .MatchNumGT , object .MatchNumGE , object .MatchNumLT , object .MatchNumLE ,
334
+ } {
335
+ check (m , cnrStr , false )
336
+ check (m , otherCnrStr , false )
337
+ }
338
+ for i := range len (cnrStr ) {
339
+ check (object .MatchCommonPrefix , cnrStr [:i ], true )
340
+ if cnrStr [:i ] != otherCnrStr [:i ] {
341
+ check (object .MatchCommonPrefix , otherCnrStr [:i ], false )
342
+ }
343
+ }
344
+ // TODO: also check that BoltDB is untouched when on mismatch
345
+ })
346
+ t .Run ("owner" , func (t * testing.T ) {
347
+ check := func (m object.SearchMatchType , v string , matchInds []uint ) {
348
+ check (object .FilterOwnerID , m , v , matchInds )
349
+ }
350
+ owner1Str := owner1 .EncodeToString ()
351
+ owner2Str := owner2 .EncodeToString ()
352
+ otherOwnerStr := usertest .OtherID (owner1 , owner2 ).EncodeToString ()
353
+ check (object .MatchStringEqual , owner1Str , []uint {0 , 2 })
354
+ check (object .MatchStringEqual , owner2Str , []uint {1 , 3 })
355
+ check (object .MatchStringEqual , otherOwnerStr , nil )
356
+ check (object .MatchStringNotEqual , owner1Str , []uint {1 , 3 })
357
+ check (object .MatchStringNotEqual , owner2Str , []uint {0 , 2 })
358
+ check (object .MatchStringNotEqual , otherOwnerStr , []uint {0 , 1 , 2 , 3 })
359
+ for _ , m := range []object.SearchMatchType {
360
+ object .MatchNotPresent , object .MatchNumGT , object .MatchNumGE , object .MatchNumLT , object .MatchNumLE ,
361
+ } {
362
+ check (m , owner1Str , nil )
363
+ check (m , owner2Str , nil )
364
+ }
365
+ for i := range len (owner1Str ) {
366
+ check (object .MatchCommonPrefix , owner1Str [:i ], []uint {0 , 2 })
367
+ check (object .MatchCommonPrefix , owner2Str [:i ], []uint {1 , 3 })
368
+ if owner1Str [:i ] != otherOwnerStr [:i ] {
369
+ check (object .MatchCommonPrefix , otherOwnerStr [:i ], nil )
370
+ }
371
+ }
372
+ })
373
+ })
262
374
}
0 commit comments