Add stable marshal of acl record

Signed-off-by: Alex Vanin <alexey@nspcc.ru>
This commit is contained in:
Alex Vanin 2020-08-17 16:49:19 +03:00 committed by Stanislav Bogatyrev
parent 64b456996e
commit 6e42ba8d22
2 changed files with 163 additions and 5 deletions

View file

@ -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) {

View file

@ -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)
})
}