Add cloud event base64 serialization convenience functions

This commit is contained in:
Christian Schaible 2024-10-17 14:35:07 +02:00
parent fdecdd935c
commit c62161173e
2 changed files with 181 additions and 0 deletions

76
audit/api/base64.go Normal file
View file

@ -0,0 +1,76 @@
package api
import (
"encoding/base64"
"encoding/json"
"errors"
"strings"
)
var ErrBase64StringEmpty = errors.New("base64 string must not be empty")
var ErrOperationEmpty = errors.New("Operation must not be empty")
var ErrRoutableIdentifierNil = errors.New("routableIdentifier must not be nil")
var ErrUnsupportedBase64StringVersion = errors.New("unsupported base64 cloud event string version")
type serializableEvent struct {
CloudEvent CloudEvent `json:"cloudEvent"`
Operation string `json:"operation"`
RoutableIdentifier RoutableIdentifier `json:"routableIdentifier"`
}
func ToBase64(
cloudEvent *CloudEvent,
routableIdentifier *RoutableIdentifier,
operation string) (*string, error) {
if cloudEvent == nil {
return nil, ErrCloudEventNil
}
if routableIdentifier == nil {
return nil, ErrRoutableIdentifierNil
}
if operation == "" {
return nil, ErrOperationEmpty
}
event := serializableEvent{
CloudEvent: *cloudEvent,
Operation: operation,
RoutableIdentifier: *routableIdentifier,
}
serializedEvent, err := json.Marshal(event)
if err != nil {
return nil, err
}
base64Str := base64.StdEncoding.EncodeToString(serializedEvent)
base64Str = base64Str + "v1"
return &base64Str, nil
}
func FromBase64(base64Str string) (*CloudEvent, *RoutableIdentifier, *string, error) {
if base64Str == "" {
return nil, nil, nil, ErrBase64StringEmpty
}
if !strings.HasSuffix(base64Str, "v1") {
return nil, nil, nil, ErrUnsupportedBase64StringVersion
}
base64Str = strings.TrimSuffix(base64Str, "v1")
base64Bytes, err := base64.StdEncoding.DecodeString(base64Str)
if err != nil {
return nil, nil, nil, err
}
event := serializableEvent{}
err = json.Unmarshal(base64Bytes, &event)
if err != nil {
return nil, nil, nil, err
}
return &event.CloudEvent, &event.RoutableIdentifier, &event.Operation, nil
}

105
audit/api/base64_test.go Normal file
View file

@ -0,0 +1,105 @@
package api
import (
"encoding/base64"
"github.com/stretchr/testify/assert"
"testing"
)
func Test_ToBase64(t *testing.T) {
t.Run("cloud event nil", func(t *testing.T) {
var cloudEvent *CloudEvent = nil
routableIdentifier := RoutableSystemIdentifier
operation := "organization.create"
base64str, err := ToBase64(cloudEvent, routableIdentifier, operation)
assert.ErrorIs(t, err, ErrCloudEventNil)
assert.Nil(t, base64str)
})
t.Run("routable identifier nil", func(t *testing.T) {
cloudEvent := &CloudEvent{}
var routableIdentifier *RoutableIdentifier = nil
operation := "organization.create"
base64str, err := ToBase64(cloudEvent, routableIdentifier, operation)
assert.ErrorIs(t, err, ErrRoutableIdentifierNil)
assert.Nil(t, base64str)
})
t.Run("Operation empty", func(t *testing.T) {
cloudEvent := &CloudEvent{}
routableIdentifier := RoutableSystemIdentifier
operation := ""
base64str, err := ToBase64(cloudEvent, routableIdentifier, operation)
assert.ErrorIs(t, err, ErrOperationEmpty)
assert.Nil(t, base64str)
})
t.Run("encoded event", func(t *testing.T) {
e := &CloudEvent{}
r := RoutableSystemIdentifier
o := "organization.create"
base64str, err := ToBase64(e, r, o)
assert.NoError(t, err)
cloudEvent, routableIdentifier, operation, err := FromBase64(*base64str)
assert.NoError(t, err)
assert.Equal(t, e, cloudEvent)
assert.Equal(t, r, routableIdentifier)
assert.Equal(t, o, *operation)
})
}
func Test_FromBase64(t *testing.T) {
t.Run("empty string", func(t *testing.T) {
cloudEvent, routableIdentifier, operation, err := FromBase64("")
assert.ErrorIs(t, err, ErrBase64StringEmpty)
assert.Nil(t, cloudEvent)
assert.Nil(t, routableIdentifier)
assert.Nil(t, operation)
})
t.Run("without version suffix", func(t *testing.T) {
cloudEvent, routableIdentifier, operation, err := FromBase64("ey")
assert.ErrorIs(t, err, ErrUnsupportedBase64StringVersion)
assert.Nil(t, cloudEvent)
assert.Nil(t, routableIdentifier)
assert.Nil(t, operation)
})
t.Run("no base64 string", func(t *testing.T) {
cloudEvent, routableIdentifier, operation, err := FromBase64("no base 64 v1")
assert.EqualError(t, err, "illegal base64 data at input byte 2")
assert.Nil(t, cloudEvent)
assert.Nil(t, routableIdentifier)
assert.Nil(t, operation)
})
t.Run("no json serialized event", func(t *testing.T) {
base64Str := base64.StdEncoding.EncodeToString([]byte("not expected"))
base64Str = base64Str + "v1"
cloudEvent, routableIdentifier, operation, err := FromBase64(base64Str)
assert.EqualError(t, err, "invalid character 'o' in literal null (expecting 'u')")
assert.Nil(t, cloudEvent)
assert.Nil(t, routableIdentifier)
assert.Nil(t, operation)
})
t.Run("decoded event", func(t *testing.T) {
e := &CloudEvent{}
r := RoutableSystemIdentifier
o := "organization.create"
base64str, err := ToBase64(e, r, o)
assert.NoError(t, err)
cloudEvent, routableIdentifier, operation, err := FromBase64(*base64str)
assert.NoError(t, err)
assert.Equal(t, e, cloudEvent)
assert.Equal(t, r, routableIdentifier)
assert.Equal(t, o, *operation)
})
}