9c5d3d9dfa
Signed-off-by: Alex Vanin <alexey@nspcc.ru>
191 lines
4 KiB
Go
191 lines
4 KiB
Go
package client
|
|
|
|
import (
|
|
"errors"
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
"github.com/nspcc-dev/neofs-api-go/v2/object"
|
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
|
signatureV2 "github.com/nspcc-dev/neofs-api-go/v2/signature"
|
|
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
|
|
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestObjectSearch(t *testing.T) {
|
|
ids := make([]oid.ID, 20)
|
|
for i := range ids {
|
|
ids[i] = *oidtest.ID()
|
|
}
|
|
|
|
resp, setID := testListReaderResponse(t)
|
|
|
|
buf := make([]oid.ID, 2)
|
|
checkRead := func(t *testing.T, expected []oid.ID) {
|
|
n, ok := resp.Read(buf)
|
|
require.True(t, ok == (len(expected) == len(buf)), "expected no error")
|
|
require.Equal(t, len(expected), n, "expected %d items to be read", len(expected))
|
|
require.Equal(t, expected, buf[:len(expected)])
|
|
}
|
|
|
|
// nil panic
|
|
require.Panics(t, func() { resp.Read(nil) })
|
|
|
|
// both ID fetched
|
|
setID(ids[:3])
|
|
checkRead(t, ids[:2])
|
|
|
|
// one ID cached, second fetched
|
|
setID(ids[3:6])
|
|
checkRead(t, ids[2:4])
|
|
|
|
// both ID cached
|
|
resp.ctxCall.resp = nil
|
|
checkRead(t, ids[4:6])
|
|
|
|
// both ID fetched in 2 requests, with empty one in the middle
|
|
var n int
|
|
resp.ctxCall.rResp = func() error {
|
|
switch n {
|
|
case 0:
|
|
setID(ids[6:7])
|
|
case 1:
|
|
setID(nil)
|
|
case 2:
|
|
setID(ids[7:8])
|
|
default:
|
|
t.FailNow()
|
|
}
|
|
n++
|
|
return nil
|
|
}
|
|
checkRead(t, ids[6:8])
|
|
|
|
// read from tail multiple times
|
|
resp.ctxCall.rResp = nil
|
|
setID(ids[8:11])
|
|
buf = buf[:1]
|
|
checkRead(t, ids[8:9])
|
|
checkRead(t, ids[9:10])
|
|
checkRead(t, ids[10:11])
|
|
|
|
// handle EOF
|
|
buf = buf[:2]
|
|
n = 0
|
|
resp.ctxCall.rResp = func() error {
|
|
if n > 0 {
|
|
return io.EOF
|
|
}
|
|
n++
|
|
setID(ids[11:12])
|
|
return nil
|
|
}
|
|
checkRead(t, ids[11:12])
|
|
}
|
|
|
|
func TestObjectIterate(t *testing.T) {
|
|
ids := make([]oid.ID, 3)
|
|
for i := range ids {
|
|
ids[i] = *oidtest.ID()
|
|
}
|
|
|
|
t.Run("iterate all sequence", func(t *testing.T) {
|
|
resp, setID := testListReaderResponse(t)
|
|
|
|
// Iterate over all sequence
|
|
var n int
|
|
resp.ctxCall.rResp = func() error {
|
|
switch n {
|
|
case 0:
|
|
setID(ids[0:2])
|
|
case 1:
|
|
setID(nil)
|
|
case 2:
|
|
setID(ids[2:3])
|
|
default:
|
|
return io.EOF
|
|
}
|
|
n++
|
|
return nil
|
|
}
|
|
|
|
var actual []oid.ID
|
|
require.NoError(t, resp.Iterate(func(id oid.ID) bool {
|
|
actual = append(actual, id)
|
|
return false
|
|
}))
|
|
require.Equal(t, ids[:3], actual)
|
|
})
|
|
t.Run("stop by return value", func(t *testing.T) {
|
|
resp, setID := testListReaderResponse(t)
|
|
|
|
var actual []oid.ID
|
|
setID(ids)
|
|
require.NoError(t, resp.Iterate(func(id oid.ID) bool {
|
|
actual = append(actual, id)
|
|
return len(actual) == 2
|
|
}))
|
|
require.Equal(t, ids[:2], actual)
|
|
})
|
|
t.Run("stop after error", func(t *testing.T) {
|
|
resp, setID := testListReaderResponse(t)
|
|
expectedErr := errors.New("test error")
|
|
|
|
var actual []oid.ID
|
|
var n int
|
|
resp.ctxCall.rResp = func() error {
|
|
switch n {
|
|
case 0:
|
|
setID(ids[:2])
|
|
default:
|
|
return expectedErr
|
|
}
|
|
n++
|
|
return nil
|
|
}
|
|
|
|
err := resp.Iterate(func(id oid.ID) bool {
|
|
actual = append(actual, id)
|
|
return false
|
|
})
|
|
require.True(t, errors.Is(err, expectedErr), "got: %v", err)
|
|
require.Equal(t, ids[:2], actual)
|
|
})
|
|
}
|
|
|
|
func testListReaderResponse(t *testing.T) (*ObjectListReader, func(id []oid.ID) *object.SearchResponse) {
|
|
p, err := keys.NewPrivateKey()
|
|
require.NoError(t, err)
|
|
|
|
obj := &ObjectListReader{
|
|
cancelCtxStream: func() {},
|
|
ctxCall: contextCall{
|
|
closer: func() error { return nil },
|
|
result: func(v2 responseV2) {},
|
|
statusRes: new(ResObjectSearch),
|
|
},
|
|
reqWritten: true,
|
|
bodyResp: object.SearchResponseBody{},
|
|
tail: nil,
|
|
}
|
|
|
|
return obj, func(id []oid.ID) *object.SearchResponse {
|
|
resp := new(object.SearchResponse)
|
|
resp.SetBody(new(object.SearchResponseBody))
|
|
|
|
v2id := make([]refs.ObjectID, len(id))
|
|
for i := range id {
|
|
v2id[i] = *id[i].ToV2()
|
|
}
|
|
resp.GetBody().SetIDList(v2id)
|
|
err := signatureV2.SignServiceMessage(&p.PrivateKey, resp)
|
|
if err != nil {
|
|
t.Fatalf("error: %v", err)
|
|
}
|
|
obj.ctxCall.resp = resp
|
|
obj.bodyResp = *resp.GetBody()
|
|
return resp
|
|
}
|
|
}
|