Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Provided custom XML marshaling of Event #277

Merged
merged 1 commit into from
Sep 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion models/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ package models

import (
"encoding/json"
"encoding/xml"
"fmt"
"strings"

"github.com/fxamacker/cbor/v2"
)
Expand All @@ -29,7 +32,7 @@ type Event struct {
Modified int64 `json:"modified,omitempty" codec:"modified,omitempty"` // Modified is a timestamp indicating when the event was last modified.
Origin int64 `json:"origin,omitempty" codec:"origin,omitempty"` // Origin is a timestamp that can communicate the time of the original reading, prior to event creation
Readings []Reading `json:"readings,omitempty" codec:"readings,omitempty"` // Readings will contain zero to many entries for the associated readings of a given event.
Tags map[string]string `json:"tags,omitempty" codec:"tags,omitempty"` // Tags is an optional collection of key/value pairs that all the event to be tagged with custom information.
Tags map[string]string `json:"tags,omitempty" codec:"tags,omitempty" xml:"-"` // Tags is an optional collection of key/value pairs that all the event to be tagged with custom information. Ignored for XML since maps not supported.
isValidated bool // internal member used for validation check
}

Expand Down Expand Up @@ -109,3 +112,26 @@ func (e Event) CBOR() []byte {

return cbor
}

// ToXML provides a XML representation of the Event as a string
func (e Event) ToXML() (string, error) {
eventXml, err := xml.Marshal(e)
if err != nil {
return "", err
}

// The Tags field is being ignore from XML Marshaling since maps are not supported.
// We have to provide our own marshaling of the Tags field if it is non-empty
if len(e.Tags) > 0 {
tagsXmlElements := []string{"<Tags>"}
for key, value := range e.Tags {
tag := fmt.Sprintf("<%s>%s</%s>", key, value, key)
tagsXmlElements = append(tagsXmlElements, tag)
}
tagsXmlElements = append(tagsXmlElements, "</Tags>")
tagsXml := strings.Join(tagsXmlElements, "")
eventXml = []byte(strings.Replace(string(eventXml), "</Event>", tagsXml+"</Event>", 1))
}

return string(eventXml), nil
}
28 changes: 25 additions & 3 deletions models/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
package models

import (
"fmt"
"reflect"
"strconv"
"testing"

"github.com/fxamacker/cbor/v2"
"github.com/go-playground/assert/v2"
"github.com/stretchr/testify/assert"
)

var TestEvent = Event{
Expand All @@ -32,6 +33,8 @@ var TestEvent = Event{
Readings: []Reading{TestReading},
Tags: map[string]string{
"GatewayID": "Houston-0001",
"Latitude": "29.630771",
"Longitude": "-95.377603",
},
}

Expand All @@ -48,8 +51,12 @@ func TestEvent_String(t *testing.T) {
",\"modified\":" + strconv.FormatInt(TestEvent.Modified, 10) +
",\"origin\":" + strconv.FormatInt(TestEvent.Origin, 10) +
",\"readings\":[" + TestReading.String() + "]" +
",\"tags\":{\"GatewayID\":\"Houston-0001\"}" +
"}"},
",\"tags\":{" +
"\"GatewayID\":\"Houston-0001\"" +
",\"Latitude\":\"29.630771\"" +
",\"Longitude\":\"-95.377603\"}" +
"}",
},
{"event to string, empty", Event{}, testEmptyJSON},
}
for _, tt := range tests {
Expand Down Expand Up @@ -93,3 +100,18 @@ func Test_encodeAsCBOR(t *testing.T) {
t.Error("Failed to properly decode event")
}
}

func TestEvent_ToXML(t *testing.T) {
// Since the order in map is random we have to verify the individual items exists without depending on order
contains := []string{
"<Event><ID></ID><Pushed>123</Pushed><Device>test device name</Device><Created>123</Created><Modified>123</Modified><Origin>123</Origin><Readings><Id>Thermometer</Id><Pushed>123</Pushed><Created>123</Created><Origin>123</Origin><Modified>123</Modified><Device>test device name</Device><Name>Temperature</Name><Value>45</Value><ValueType>Int16</ValueType><FloatEncoding>float16</FloatEncoding><BinaryValue>�</BinaryValue><MediaType>application/cbor</MediaType></Readings><Tags>",
"<GatewayID>Houston-0001</GatewayID>",
"<Latitude>29.630771</Latitude>",
"<Longitude>-95.377603</Longitude>",
"</Tags></Event>",
}
actual, _ := TestEvent.ToXML()
for _, item := range contains {
assert.Contains(t, actual, item, fmt.Sprintf("Missing item '%s'", item))
}
}
29 changes: 28 additions & 1 deletion v2/dtos/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
package dtos

import (
"encoding/xml"
"fmt"
"strings"

v2 "github.com/edgexfoundry/go-mod-core-contracts/v2"
"github.com/edgexfoundry/go-mod-core-contracts/v2/dtos/common"
"github.com/edgexfoundry/go-mod-core-contracts/v2/models"
Expand All @@ -22,7 +26,7 @@ type Event struct {
Created int64 `json:"created"`
Origin int64 `json:"origin" validate:"required"`
Readings []BaseReading `json:"readings" validate:"gt=0,dive,required"`
Tags map[string]string `json:"tags,omitempty"`
Tags map[string]string `json:"tags,omitempty" xml:"-"` // Have to ignore since map not supported for XML
}

func FromEventModelToDTO(event models.Event) Event {
Expand All @@ -47,3 +51,26 @@ func FromEventModelToDTO(event models.Event) Event {
Tags: tags,
}
}

// ToXML provides a XML representation of the Event as a string
func (e Event) ToXML() (string, error) {
eventXml, err := xml.Marshal(e)
if err != nil {
return "", err
}

// The Tags field is being ignore from XML Marshaling since maps are not supported.
// We have to provide our own marshaling of the Tags field if it is non-empty
if len(e.Tags) > 0 {
tagsXmlElements := []string{"<Tags>"}
for key, value := range e.Tags {
tag := fmt.Sprintf("<%s>%s</%s>", key, value, key)
tagsXmlElements = append(tagsXmlElements, tag)
}
tagsXmlElements = append(tagsXmlElements, "</Tags>")
tagsXml := strings.Join(tagsXmlElements, "")
eventXml = []byte(strings.Replace(string(eventXml), "</Event>", tagsXml+"</Event>", 1))
}

return string(eventXml), nil
}
65 changes: 43 additions & 22 deletions v2/dtos/event_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
package dtos

import (
"fmt"
"testing"

v2 "github.com/edgexfoundry/go-mod-core-contracts/v2"
Expand All @@ -15,29 +16,34 @@ import (
"github.com/stretchr/testify/assert"
)

func TestFromEventModelToDTO(t *testing.T) {
valid := models.Event{
Id: TestUUID,
Pushed: TestTimestamp,
DeviceName: TestDeviceName,
Created: TestTimestamp,
Origin: TestTimestamp,
Tags: map[string]string{
"GatewayID": "Houston-0001",
},
}
expectedDTO := Event{
Versionable: common.Versionable{ApiVersion: v2.ApiVersion},
ID: TestUUID,
Pushed: TestTimestamp,
DeviceName: TestDeviceName,
Created: TestTimestamp,
Origin: TestTimestamp,
Tags: map[string]string{
"GatewayID": "Houston-0001",
},
}
var valid = models.Event{
Id: TestUUID,
Pushed: TestTimestamp,
DeviceName: TestDeviceName,
Created: TestTimestamp,
Origin: TestTimestamp,
Tags: map[string]string{
"GatewayID": "Houston-0001",
"Latitude": "29.630771",
"Longitude": "-95.377603",
},
}

var expectedDTO = Event{
Versionable: common.Versionable{ApiVersion: v2.ApiVersion},
ID: TestUUID,
Pushed: TestTimestamp,
DeviceName: TestDeviceName,
Created: TestTimestamp,
Origin: TestTimestamp,
Tags: map[string]string{
"GatewayID": "Houston-0001",
"Latitude": "29.630771",
"Longitude": "-95.377603",
},
}

func TestFromEventModelToDTO(t *testing.T) {
tests := []struct {
name string
event models.Event
Expand All @@ -51,3 +57,18 @@ func TestFromEventModelToDTO(t *testing.T) {
})
}
}

func TestEvent_ToXML(t *testing.T) {
// Since the order in map is random we have to verify the individual items exists without depending on order
contains := []string{
"<Event><ApiVersion>v2</ApiVersion><ID>7a1707f0-166f-4c4b-bc9d-1d54c74e0137</ID><Pushed>1594963842</Pushed><DeviceName>TestDevice</DeviceName><Created>1594963842</Created><Origin>1594963842</Origin><Tags>",
"<GatewayID>Houston-0001</GatewayID>",
lenny-goodell marked this conversation as resolved.
Show resolved Hide resolved
"<Latitude>29.630771</Latitude>",
"<Longitude>-95.377603</Longitude>",
"</Tags></Event>",
}
actual, _ := expectedDTO.ToXML()
for _, item := range contains {
assert.Contains(t, actual, item, fmt.Sprintf("Missing item '%s'", item))
}
}