frostfs-api-go/service/verify_test.go
Evgeniy Kulikov 8d028100e9
service: Use sync pool for Sign/Verify request headers
```
// Before
BenchmarkSignRequestHeader-8   	     146	   8070375 ns/op	 4210607 B/op	      48 allocs/op
BenchmarkVerifyRequestHeader-8   	      14	  83058325 ns/op	42085955 B/op	    1601 allocs/op

// After
BenchmarkSignRequestHeader-8   	     156	   7709172 ns/op	   33902 B/op	      45 allocs/op
BenchmarkVerifyRequestHeader-8   	      15	  76910232 ns/op	   54368 B/op	    1563 allocs/op

// Summary:
benchmark                          old ns/op     new ns/op     delta
BenchmarkSignRequestHeader-8       8070375       7709172       -4.48%
BenchmarkVerifyRequestHeader-8     83058325      76910232      -7.40%

benchmark                          old allocs     new allocs     delta
BenchmarkSignRequestHeader-8       48             45             -6.25%
BenchmarkVerifyRequestHeader-8     1601           1563           -2.37%

benchmark                          old bytes     new bytes     delta
BenchmarkSignRequestHeader-8       4210607       33902         -99.19%
BenchmarkVerifyRequestHeader-8     42085955      54368         -99.87%
```
2019-12-20 17:14:51 +03:00

201 lines
4.7 KiB
Go

package service
import (
"bytes"
"log"
"math"
"testing"
"github.com/gogo/protobuf/proto"
crypto "github.com/nspcc-dev/neofs-crypto"
"github.com/nspcc-dev/neofs-crypto/test"
"github.com/nspcc-dev/neofs-proto/refs"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
)
func BenchmarkSignRequestHeader(b *testing.B) {
key := test.DecodeKey(0)
custom := testCustomField{1, 2, 3, 4, 5, 6, 7, 8}
some := &TestRequest{
IntField: math.MaxInt32,
StringField: "TestRequestStringField",
BytesField: make([]byte, 1<<22),
CustomField: &custom,
RequestMetaHeader: RequestMetaHeader{
TTL: math.MaxInt32 - 8,
Epoch: math.MaxInt64 - 12,
},
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
require.NoError(b, SignRequestHeader(key, some))
}
}
func BenchmarkVerifyRequestHeader(b *testing.B) {
custom := testCustomField{1, 2, 3, 4, 5, 6, 7, 8}
some := &TestRequest{
IntField: math.MaxInt32,
StringField: "TestRequestStringField",
BytesField: make([]byte, 1<<22),
CustomField: &custom,
RequestMetaHeader: RequestMetaHeader{
TTL: math.MaxInt32 - 8,
Epoch: math.MaxInt64 - 12,
},
}
for i := 0; i < 10; i++ {
key := test.DecodeKey(i)
require.NoError(b, SignRequestHeader(key, some))
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
require.NoError(b, VerifyRequestHeader(some))
}
}
func TestSignRequestHeader(t *testing.T) {
req := &TestRequest{
IntField: math.MaxInt32,
StringField: "TestRequestStringField",
BytesField: []byte("TestRequestBytesField"),
}
key := test.DecodeKey(0)
peer := crypto.MarshalPublicKey(&key.PublicKey)
data, err := req.Marshal()
require.NoError(t, err)
require.NoError(t, SignRequestHeader(key, req))
require.Len(t, req.Signatures, 1)
for i := range req.Signatures {
sign := req.Signatures[i].GetSign()
require.Equal(t, peer, req.Signatures[i].GetPeer())
require.NoError(t, crypto.Verify(&key.PublicKey, data, sign))
}
}
func TestVerifyRequestHeader(t *testing.T) {
req := &TestRequest{
IntField: math.MaxInt32,
StringField: "TestRequestStringField",
BytesField: []byte("TestRequestBytesField"),
RequestMetaHeader: RequestMetaHeader{TTL: 10},
}
for i := 0; i < 10; i++ {
req.TTL--
require.NoError(t, SignRequestHeader(test.DecodeKey(i), req))
}
require.NoError(t, VerifyRequestHeader(req))
}
func TestMaintainableRequest(t *testing.T) {
req := &TestRequest{
IntField: math.MaxInt32,
StringField: "TestRequestStringField",
BytesField: []byte("TestRequestBytesField"),
RequestMetaHeader: RequestMetaHeader{TTL: 10},
}
count := 10
owner := test.DecodeKey(count + 1)
for i := 0; i < count; i++ {
req.TTL--
key := test.DecodeKey(i)
require.NoError(t, SignRequestHeader(key, req))
// sign first key (session key) by owner key
if i == 0 {
sign, err := crypto.Sign(owner, crypto.MarshalPublicKey(&key.PublicKey))
require.NoError(t, err)
req.SetOwner(&owner.PublicKey, sign)
}
}
{ // Validate owner
user, err := refs.NewOwnerID(&owner.PublicKey)
require.NoError(t, err)
require.NoError(t, req.CheckOwner(user))
}
{ // Good case:
require.NoError(t, VerifyRequestHeader(req))
// validate, that first key (session key) was signed with owner
signatures := req.GetSignatures()
require.Len(t, signatures, count)
pub, err := req.GetOwner()
require.NoError(t, err)
require.Equal(t, &owner.PublicKey, pub)
}
{ // wrong owner:
req.Signatures[0].Origin = nil
pub, err := req.GetOwner()
require.NoError(t, err)
require.NotEqual(t, &owner.PublicKey, pub)
}
{ // Wrong signatures:
copy(req.Signatures[count-1].Sign, req.Signatures[count-1].Peer)
err := VerifyRequestHeader(req)
require.EqualError(t, errors.Cause(err), crypto.ErrInvalidSignature.Error())
}
}
func TestVerifyAndSignRequestHeaderWithoutCloning(t *testing.T) {
key := test.DecodeKey(0)
custom := testCustomField{1, 2, 3, 4, 5, 6, 7, 8}
b := &TestRequest{
IntField: math.MaxInt32,
StringField: "TestRequestStringField",
BytesField: []byte("TestRequestBytesField"),
CustomField: &custom,
RequestMetaHeader: RequestMetaHeader{
TTL: math.MaxInt32 - 8,
Epoch: math.MaxInt64 - 12,
},
}
require.NoError(t, SignRequestHeader(key, b))
require.NoError(t, VerifyRequestHeader(b))
require.Len(t, b.Signatures, 1)
require.Equal(t, custom, *b.CustomField)
require.Equal(t, uint32(math.MaxInt32-8), b.GetTTL())
require.Equal(t, uint64(math.MaxInt64-12), b.GetEpoch())
buf := bytes.NewBuffer(nil)
log.SetOutput(buf)
cp, ok := proto.Clone(b).(*TestRequest)
require.True(t, ok)
require.NotEqual(t, b, cp)
require.Contains(t, buf.String(), "proto: don't know how to copy")
}