[#168] acl: Implement binary/JSON encoders/decoders on Table

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2020-11-13 14:55:45 +03:00 committed by Alex Vanin
parent ae68790bbd
commit 233756ca8f
6 changed files with 117 additions and 96 deletions

View file

@ -111,3 +111,47 @@ func NewTableFromV2(table *v2acl.Table) *Table {
return t
}
// Marshal marshals Table into a protobuf binary form.
//
// Buffer is allocated when the argument is empty.
// Otherwise, the first buffer is used.
func (t *Table) Marshal(b ...[]byte) ([]byte, error) {
var buf []byte
if len(b) > 0 {
buf = b[0]
}
return t.ToV2().
StableMarshal(buf)
}
// Unmarshal unmarshals protobuf binary representation of Table.
func (t *Table) Unmarshal(data []byte) error {
fV2 := new(v2acl.Table)
if err := fV2.Unmarshal(data); err != nil {
return err
}
*t = *NewTableFromV2(fV2)
return nil
}
// MarshalJSON encodes Table to protobuf JSON format.
func (t *Table) MarshalJSON() ([]byte, error) {
return t.ToV2().
MarshalJSON()
}
// UnmarshalJSON decodes Table from protobuf JSON format.
func (t *Table) UnmarshalJSON(data []byte) error {
tV2 := new(v2acl.Table)
if err := tV2.UnmarshalJSON(data); err != nil {
return err
}
*t = *NewTableFromV2(tV2)
return nil
}

View file

@ -78,3 +78,30 @@ func TestTable_AddRecord(t *testing.T) {
require.Equal(t, records, table.Records())
}
func TestRecordEncoding(t *testing.T) {
tab := eacl.NewTable()
tab.AddRecord(
eacl.CreateRecord(eacl.ActionDeny, eacl.OperationHead),
)
t.Run("binary", func(t *testing.T) {
data, err := tab.Marshal()
require.NoError(t, err)
tab2 := eacl.NewTable()
require.NoError(t, tab2.Unmarshal(data))
require.Equal(t, tab, tab2)
})
t.Run("json", func(t *testing.T) {
data, err := tab.MarshalJSON()
require.NoError(t, err)
r2 := eacl.NewTable()
require.NoError(t, r2.UnmarshalJSON(data))
require.Equal(t, tab, r2)
})
}

View file

@ -11,54 +11,6 @@ var (
errEmptyInput = errors.New("empty input")
)
func RecordToJSON(r *Record) ([]byte, error) {
if r == nil {
return nil, errEmptyInput
}
msg := RecordToGRPCMessage(r)
return protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(msg)
}
func RecordFromJSON(data []byte) (*Record, error) {
if len(data) == 0 {
return nil, errEmptyInput
}
msg := new(acl.EACLRecord)
if err := protojson.Unmarshal(data, msg); err != nil {
return nil, err
}
return RecordFromGRPCMessage(msg), nil
}
func TableToJSON(t *Table) ([]byte, error) {
if t == nil {
return nil, errEmptyInput
}
msg := TableToGRPCMessage(t)
return protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(msg)
}
func TableFromJSON(data []byte) (*Table, error) {
if len(data) == 0 {
return nil, errEmptyInput
}
msg := new(acl.EACLTable)
if err := protojson.Unmarshal(data, msg); err != nil {
return nil, err
}
return TableFromGRPCMessage(msg), nil
}
func BearerTokenToJSON(t *BearerToken) ([]byte, error) {
if t == nil {
return nil, errEmptyInput
@ -142,3 +94,23 @@ func (r *Record) UnmarshalJSON(data []byte) error {
return nil
}
func (t *Table) MarshalJSON() ([]byte, error) {
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
TableToGRPCMessage(t),
)
}
func (t *Table) UnmarshalJSON(data []byte) error {
msg := new(acl.EACLTable)
if err := protojson.Unmarshal(data, msg); err != nil {
return err
}
*t = *TableFromGRPCMessage(msg)
return nil
}

View file

@ -7,50 +7,6 @@ import (
"github.com/stretchr/testify/require"
)
func TestRecordJSON(t *testing.T) {
exp := generateRecord(false)
t.Run("non empty", func(t *testing.T) {
data, err := acl.RecordToJSON(exp)
require.NoError(t, err)
got, err := acl.RecordFromJSON(data)
require.NoError(t, err)
require.Equal(t, exp, got)
})
t.Run("empty", func(t *testing.T) {
_, err := acl.RecordToJSON(nil)
require.Error(t, err)
_, err = acl.RecordFromJSON(nil)
require.Error(t, err)
})
}
func TestEACLTableJSON(t *testing.T) {
exp := generateEACL()
t.Run("non empty", func(t *testing.T) {
data, err := acl.TableToJSON(exp)
require.NoError(t, err)
got, err := acl.TableFromJSON(data)
require.NoError(t, err)
require.Equal(t, exp, got)
})
t.Run("empty", func(t *testing.T) {
_, err := acl.TableToJSON(nil)
require.Error(t, err)
_, err = acl.TableFromJSON(nil)
require.Error(t, err)
})
}
func TestBearerTokenJSON(t *testing.T) {
exp := generateBearerToken("token")
@ -88,3 +44,16 @@ func TestTargetJSON(t *testing.T) {
require.Equal(t, tar, tar2)
}
func TestTable_MarshalJSON(t *testing.T) {
tab := new(acl.Table)
tab.SetRecords([]*acl.Record{generateRecord(false)})
data, err := tab.MarshalJSON()
require.NoError(t, err)
tab2 := new(acl.Table)
require.NoError(t, tab2.UnmarshalJSON(data))
require.Equal(t, tab, tab2)
}

View file

@ -94,6 +94,17 @@ func (t *Table) StableSize() (size int) {
return size
}
func (t *Table) Unmarshal(data []byte) error {
m := new(acl.EACLTable)
if err := proto.Unmarshal(data, m); err != nil {
return err
}
*t = *TableFromGRPCMessage(m)
return nil
}
// StableMarshal marshals unified acl record structure in a protobuf
// compatible way without field order shuffle.
func (r *Record) StableMarshal(buf []byte) ([]byte, error) {

View file

@ -170,7 +170,6 @@ func TestRecord_StableMarshal(t *testing.T) {
func TestTable_StableMarshal(t *testing.T) {
tableFrom := new(acl.Table)
transport := new(grpc.EACLTable)
t.Run("non empty", func(t *testing.T) {
cid := new(refs.ContainerID)
@ -190,10 +189,9 @@ func TestTable_StableMarshal(t *testing.T) {
wire, err := tableFrom.StableMarshal(nil)
require.NoError(t, err)
err = goproto.Unmarshal(wire, transport)
require.NoError(t, err)
tableTo := new(acl.Table)
require.NoError(t, tableTo.Unmarshal(wire))
tableTo := acl.TableFromGRPCMessage(transport)
require.Equal(t, tableFrom, tableTo)
})
}