Add stable marshal of acl record
Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
parent
64b456996e
commit
6e42ba8d22
2 changed files with 163 additions and 5 deletions
|
@ -1,6 +1,8 @@
|
||||||
package acl
|
package acl
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/util/proto"
|
"github.com/nspcc-dev/neofs-api-go/util/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -12,6 +14,11 @@ const (
|
||||||
|
|
||||||
TargetTypeField = 1
|
TargetTypeField = 1
|
||||||
TargetKeysField = 2
|
TargetKeysField = 2
|
||||||
|
|
||||||
|
RecordOperationField = 1
|
||||||
|
RecordActionField = 2
|
||||||
|
RecordFiltersField = 3
|
||||||
|
RecordTargetsField = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
func (t *Table) StableMarshal(buf []byte) ([]byte, error) {
|
func (t *Table) StableMarshal(buf []byte) ([]byte, error) {
|
||||||
|
@ -23,11 +30,92 @@ func (t *Table) StableSize() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Record) StableMarshal(buf []byte) ([]byte, error) {
|
func (r *Record) StableMarshal(buf []byte) ([]byte, error) {
|
||||||
panic("not implemented")
|
if r == nil {
|
||||||
|
return []byte{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if buf == nil {
|
||||||
|
buf = make([]byte, r.StableSize())
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
offset, n int
|
||||||
|
prefix uint64
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
|
||||||
|
n, err = proto.EnumMarshal(RecordOperationField, buf, int32(r.op))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
n, err = proto.EnumMarshal(RecordActionField, buf[offset:], int32(r.action))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
|
||||||
|
prefix, _ = proto.NestedStructurePrefix(RecordFiltersField)
|
||||||
|
|
||||||
|
for i := range r.filters {
|
||||||
|
offset += binary.PutUvarint(buf[offset:], prefix)
|
||||||
|
|
||||||
|
n = r.filters[i].StableSize()
|
||||||
|
offset += binary.PutUvarint(buf[offset:], uint64(n))
|
||||||
|
|
||||||
|
_, err = r.filters[i].StableMarshal(buf[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix, _ = proto.NestedStructurePrefix(RecordTargetsField)
|
||||||
|
|
||||||
|
for i := range r.targets {
|
||||||
|
offset += binary.PutUvarint(buf[offset:], prefix)
|
||||||
|
|
||||||
|
n = r.targets[i].StableSize()
|
||||||
|
offset += binary.PutUvarint(buf[offset:], uint64(n))
|
||||||
|
|
||||||
|
_, err = r.targets[i].StableMarshal(buf[offset:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += n
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Record) StableSize() int {
|
func (r *Record) StableSize() (size int) {
|
||||||
panic("not implemented")
|
if r == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
size += proto.EnumSize(RecordOperationField, int32(r.op))
|
||||||
|
size += proto.EnumSize(RecordActionField, int32(r.op))
|
||||||
|
|
||||||
|
_, ln := proto.NestedStructurePrefix(RecordFiltersField)
|
||||||
|
|
||||||
|
for i := range r.filters {
|
||||||
|
n := r.filters[i].StableSize()
|
||||||
|
size += ln + proto.VarUIntSize(uint64(n)) + n
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ln = proto.NestedStructurePrefix(RecordTargetsField)
|
||||||
|
|
||||||
|
for i := range r.targets {
|
||||||
|
n := r.targets[i].StableSize()
|
||||||
|
size += ln + proto.VarUIntSize(uint64(n)) + n
|
||||||
|
}
|
||||||
|
|
||||||
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *HeaderFilter) StableMarshal(buf []byte) ([]byte, error) {
|
func (f *HeaderFilter) StableMarshal(buf []byte) ([]byte, error) {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package acl_test
|
package acl_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
"github.com/nspcc-dev/neofs-api-go/v2/acl"
|
||||||
|
@ -8,8 +9,61 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func generateTarget(u acl.Target, k int) *acl.TargetInfo {
|
||||||
|
target := new(acl.TargetInfo)
|
||||||
|
target.SetTarget(u)
|
||||||
|
|
||||||
|
keys := make([][]byte, k)
|
||||||
|
for i := 0; i < k; i++ {
|
||||||
|
s := fmt.Sprintf("Public Key %d", i+1)
|
||||||
|
keys[i] = []byte(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateFilter(t acl.HeaderType, m acl.MatchType, k, v string) *acl.HeaderFilter {
|
||||||
|
filter := new(acl.HeaderFilter)
|
||||||
|
filter.SetHeaderType(t)
|
||||||
|
filter.SetMatchType(m)
|
||||||
|
filter.SetName(k)
|
||||||
|
filter.SetValue(v)
|
||||||
|
|
||||||
|
return filter
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateRecord(another bool) *acl.Record {
|
||||||
|
var record = new(acl.Record)
|
||||||
|
switch another {
|
||||||
|
case true:
|
||||||
|
t1 := generateTarget(acl.TargetUser, 2)
|
||||||
|
f1 := generateFilter(acl.HeaderTypeObject, acl.MatchTypeStringEqual,
|
||||||
|
"OID", "ObjectID Value")
|
||||||
|
|
||||||
|
record.SetOperation(acl.OperationHead)
|
||||||
|
record.SetAction(acl.ActionDeny)
|
||||||
|
record.SetTargets([]*acl.TargetInfo{t1})
|
||||||
|
record.SetFilters([]*acl.HeaderFilter{f1})
|
||||||
|
default:
|
||||||
|
t1 := generateTarget(acl.TargetUser, 2)
|
||||||
|
t2 := generateTarget(acl.TargetSystem, 0)
|
||||||
|
f1 := generateFilter(acl.HeaderTypeObject, acl.MatchTypeStringEqual,
|
||||||
|
"CID", "Container ID Value")
|
||||||
|
f2 := generateFilter(acl.HeaderTypeRequest, acl.MatchTypeStringEqual,
|
||||||
|
"X-Header-Key", "X-Header-Value")
|
||||||
|
|
||||||
|
record.SetOperation(acl.OperationPut)
|
||||||
|
record.SetAction(acl.ActionAllow)
|
||||||
|
record.SetTargets([]*acl.TargetInfo{t1, t2})
|
||||||
|
record.SetFilters([]*acl.HeaderFilter{f1, f2})
|
||||||
|
}
|
||||||
|
|
||||||
|
return record
|
||||||
|
}
|
||||||
|
|
||||||
func TestHeaderFilter_StableMarshal(t *testing.T) {
|
func TestHeaderFilter_StableMarshal(t *testing.T) {
|
||||||
filterFrom := new(acl.HeaderFilter)
|
filterFrom := generateFilter(acl.HeaderTypeObject, acl.MatchTypeStringEqual,
|
||||||
|
"CID", "Container ID Value")
|
||||||
transport := new(grpc.EACLRecord_FilterInfo)
|
transport := new(grpc.EACLRecord_FilterInfo)
|
||||||
|
|
||||||
t.Run("non empty", func(t *testing.T) {
|
t.Run("non empty", func(t *testing.T) {
|
||||||
|
@ -30,7 +84,7 @@ func TestHeaderFilter_StableMarshal(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTargetInfo_StableMarshal(t *testing.T) {
|
func TestTargetInfo_StableMarshal(t *testing.T) {
|
||||||
targetFrom := new(acl.TargetInfo)
|
targetFrom := generateTarget(acl.TargetUser, 2)
|
||||||
transport := new(grpc.EACLRecord_TargetInfo)
|
transport := new(grpc.EACLRecord_TargetInfo)
|
||||||
|
|
||||||
t.Run("non empty", func(t *testing.T) {
|
t.Run("non empty", func(t *testing.T) {
|
||||||
|
@ -50,3 +104,19 @@ func TestTargetInfo_StableMarshal(t *testing.T) {
|
||||||
require.Equal(t, targetFrom, targetTo)
|
require.Equal(t, targetFrom, targetTo)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRecord_StableMarshal(t *testing.T) {
|
||||||
|
recordFrom := generateRecord(false)
|
||||||
|
transport := new(grpc.EACLRecord)
|
||||||
|
|
||||||
|
t.Run("non empty", func(t *testing.T) {
|
||||||
|
wire, err := recordFrom.StableMarshal(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = transport.Unmarshal(wire)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
recordTo := acl.RecordFromGRPCMessage(transport)
|
||||||
|
require.Equal(t, recordFrom, recordTo)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue