Skip to content

Commit

Permalink
Add eventsv1 serializer code (#1)
Browse files Browse the repository at this point in the history
* Add eventsv1 serializer code

re: AB#10081

* Update eventsv1/serializer.go

Signed-off-by: Joe Gough <[email protected]>

---------

Signed-off-by: Joe Gough <[email protected]>
Co-authored-by: jgough <[email protected]>
  • Loading branch information
honourfish and jgough authored Dec 3, 2024
1 parent 446a636 commit 20a4ba0
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 26 deletions.
12 changes: 9 additions & 3 deletions eventsv1/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ module github.com/datatrails/go-datatrails-serialization/eventsv1

go 1.23.0

require github.com/stretchr/testify v1.10.0
require (
github.com/datatrails/go-datatrails-common-api-gen v0.6.1
github.com/stretchr/testify v1.10.0
github.com/zeebo/bencode v1.0.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
20 changes: 16 additions & 4 deletions eventsv1/go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/datatrails/go-datatrails-common-api-gen v0.6.1 h1:rkzx2FBdTTNirLNLWHpXRme3GrOssPP27reQUwdFAJc=
github.com/datatrails/go-datatrails-common-api-gen v0.6.1/go.mod h1:rTMGdMdu5M6mGpbXZy1D84cBTGE8JwsDH6BYh9LJlmA=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/zeebo/bencode v1.0.0 h1:zgop0Wu1nu4IexAZeCZ5qbsjU4O1vMrfCrVgUjbHVuA=
github.com/zeebo/bencode v1.0.0/go.mod h1:Ct7CkrWIQuLWAy9M3atFHYq4kG9Ao/SsY5cdtCXmp9Y=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
51 changes: 51 additions & 0 deletions eventsv1/serializer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package eventsv1

import (
"encoding/json"

"github.com/datatrails/go-datatrails-common-api-gen/attribute/v2/attribute"
"github.com/zeebo/bencode"
)

/**
* serializes datatatrails v1 events.
*
* Event v1 serialization is the following:
*
* 1. take the attributes and trails fields from the v1 event
* 2. json marshal the attributes and trails
* 3. bencode the json marshaled attributes and trails
*/

// SerializableEvent is the event
// containing only fields that will be serialized.
type SerializableEvent struct {
Attributes map[string]*attribute.Attribute `json:"attributes"`
Trails []string `json:"trails"`
}

// SerializeEvent serializes a v1 event
func SerializeEvent(attributes map[string]*attribute.Attribute, trails []string) ([]byte, error) {

// 1. take attributes and trails from v1 event
serializableEvent := SerializableEvent{
Attributes: attributes,
Trails: trails,
}

// 2. json marshal the attributes and trails
jsonSerializedEvent, err := json.Marshal(&serializableEvent)
if err != nil {
return nil, err
}

// 3. bencode the json marshaled attributes and trails
//
// NOTE: this gives a consistent ordering to the attributes that json doesn't give.
bencodeSerializedEvent, err := bencode.EncodeBytes(jsonSerializedEvent)
if err != nil {
return nil, err
}

return bencodeSerializedEvent, nil
}
245 changes: 245 additions & 0 deletions eventsv1/serializer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
package eventsv1

import (
"testing"

"github.com/datatrails/go-datatrails-common-api-gen/attribute/v2/attribute"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

// TestSerializeEventConsistency tests:
//
// 1. an event with the same attributes and trails in the same order, serializes to the same bytes.
// 2. an event with the same trails and same attributes in a different order, serializes to the same bytes.
// 3. an event with the same attributes and same trails in a different order, serializes to different bytes.
// 4. an event with the same trails and different attributes serializes to different bytes.
// 5. an event with the same attributes and different trails, serializes to different bytes.
func TestSerializeEventConsistency(t *testing.T) {
type event struct {
attributes map[string]*attribute.Attribute
trails []string
}
tests := []struct {
name string
event1 event
event2 event
sameSerialization bool
}{
{
name: "same attributes and trails in same order",
event1: event{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"sugar": attribute.NewStringAttribute("250g"),
"eggs": attribute.NewStringAttribute("2"),
"milk": attribute.NewStringAttribute("300ml"),
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
},
trails: []string{
"cake",
"viccy sponge",
},
},
event2: event{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"sugar": attribute.NewStringAttribute("250g"),
"eggs": attribute.NewStringAttribute("2"),
"milk": attribute.NewStringAttribute("300ml"),
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
},
trails: []string{
"cake",
"viccy sponge",
},
},
sameSerialization: true,
},
{
name: "same attributes and trails, attributes in different order",
event1: event{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"sugar": attribute.NewStringAttribute("250g"),
"eggs": attribute.NewStringAttribute("2"),
"milk": attribute.NewStringAttribute("300ml"),
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
},
trails: []string{
"cake",
"viccy sponge",
},
},
event2: event{
attributes: map[string]*attribute.Attribute{
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
"flour": attribute.NewStringAttribute("500g"),
"milk": attribute.NewStringAttribute("300ml"),
"eggs": attribute.NewStringAttribute("2"),
"sugar": attribute.NewStringAttribute("250g"),
},
trails: []string{
"cake",
"viccy sponge",
},
},
sameSerialization: true,
},
{
name: "same attributes and trails, trails in different order",
event1: event{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"sugar": attribute.NewStringAttribute("250g"),
"eggs": attribute.NewStringAttribute("2"),
"milk": attribute.NewStringAttribute("300ml"),
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
},
trails: []string{
"cake",
"viccy sponge",
},
},
event2: event{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"sugar": attribute.NewStringAttribute("250g"),
"eggs": attribute.NewStringAttribute("2"),
"milk": attribute.NewStringAttribute("300ml"),
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
},
trails: []string{
"viccy sponge",
"cake",
},
},
sameSerialization: false,
},
{
name: "same trails and different attributes in same order",
event1: event{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"sugar": attribute.NewStringAttribute("250g"),
"eggs": attribute.NewStringAttribute("2"),
"milk": attribute.NewStringAttribute("300ml"),
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
},
trails: []string{
"cake",
"viccy sponge",
},
},
event2: event{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"sugar": attribute.NewStringAttribute("250g"),
"eggs": attribute.NewStringAttribute("2"),
"milk": attribute.NewStringAttribute("300ml"),
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
"bicarbonate of soda": attribute.NewStringAttribute("2 tsp"),
},
trails: []string{
"cake",
"viccy sponge",
},
},
sameSerialization: false,
},
{
name: "same attributes and different trails in same order",
event1: event{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"sugar": attribute.NewStringAttribute("250g"),
"eggs": attribute.NewStringAttribute("2"),
"milk": attribute.NewStringAttribute("300ml"),
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
},
trails: []string{
"cake",
"viccy sponge",
},
},
event2: event{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"sugar": attribute.NewStringAttribute("250g"),
"eggs": attribute.NewStringAttribute("2"),
"milk": attribute.NewStringAttribute("300ml"),
"vanilla extract": attribute.NewStringAttribute("1 tsp"),
},
trails: []string{
"cake",
"dessert",
},
},
sameSerialization: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {

serializedEvent1, err := SerializeEvent(test.event1.attributes, test.event1.trails)
require.Nil(t, err)

serializedEvent2, err := SerializeEvent(test.event2.attributes, test.event2.trails)
require.Nil(t, err)

if test.sameSerialization {
assert.Equal(t, serializedEvent1, serializedEvent2)
} else {
assert.NotEqual(t, serializedEvent1, serializedEvent2)
}

})
}
}

// TestSerializeEvent tests:
//
// 1. an event with all types of attributes [string|list|dict] can be serialized without error.
func TestSerializeEvent(t *testing.T) {
type args struct {
attributes map[string]*attribute.Attribute
trails []string
}
tests := []struct {
name string
args args
err error
}{
{
name: "all attribute types no error",
args: args{
attributes: map[string]*attribute.Attribute{
"flour": attribute.NewStringAttribute("500g"),
"method": attribute.NewListAttribute([]map[string]string{
{"1": "put flour sugar into mixing bowl"},
{"2": "put in eggs and mix"},
{"3": "put in milk and mix"},
}),
"baking time": attribute.NewDictAttribute(map[string]string{
"oven time": "30 mins",
}),
},
trails: []string{
"cake",
"viccy sponge",
},
},
err: nil,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {

actual, err := SerializeEvent(test.args.attributes, test.args.trails)
require.NotNil(t, actual)

assert.Equal(t, test.err, err)

})
}
}
5 changes: 0 additions & 5 deletions eventsv1/test.go

This file was deleted.

14 changes: 0 additions & 14 deletions eventsv1/test_test.go

This file was deleted.

0 comments on commit 20a4ba0

Please sign in to comment.