Skip to content

Commit

Permalink
NOISSUE - Convert SenML Payload Time To UnixNano (absmach#2115)
Browse files Browse the repository at this point in the history
Signed-off-by: Rodney Osodo <[email protected]>
Signed-off-by: rodneyosodo <[email protected]>
  • Loading branch information
rodneyosodo authored Mar 15, 2024
1 parent 7a2f71a commit ec7b4b4
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 4 deletions.
2 changes: 1 addition & 1 deletion pkg/transformers/json/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func (ts *transformerService) transformTimeField(payload map[string]interface{})
return 0, err
}

return t.UnixNano(), nil
return transformers.ToUnixNano(t.UnixNano()), nil
}
}

Expand Down
14 changes: 12 additions & 2 deletions pkg/transformers/senml/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const (
JSON = "application/senml+json"
// CBOR represents SenML in CBOR format content type.
CBOR = "application/senml+cbor"

maxRelativeTime = 1 << 28
)

var (
Expand Down Expand Up @@ -59,8 +61,16 @@ func (t transformer) Transform(msg *messaging.Message) (interface{}, error) {
// Use reception timestamp if SenML messsage Time is missing
t := v.Time
if t == 0 {
// Convert the Unix timestamp in nanoseconds to float64
t = float64(msg.GetCreated()) / float64(1e9)
t = float64(msg.GetCreated())
}

// If time is below 2**28 it is relative to the current time
// https://datatracker.ietf.org/doc/html/rfc8428#section-4.5.3
if t >= maxRelativeTime {
t = transformers.ToUnixNano(t)
}
if v.UpdateTime >= maxRelativeTime {
v.UpdateTime = transformers.ToUnixNano(v.UpdateTime)
}

msgs[i] = Message{
Expand Down
2 changes: 1 addition & 1 deletion pkg/transformers/senml/transformer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (

func TestTransformJSON(t *testing.T) {
// Following hex-encoded bytes correspond to the content of:
// [{-2: "base-name", -3: 100.0, -4: "base-unit", -1: 10, -5: 10.0, -6: 100.0, 0: "name", 1: "unit", 6: 300.0, 7: 150.0, 2: 42.0, 5: 10.0}]
// [{"bn":"base-name","bt":100,"bu":"base-unit","bver":10,"bv":10,"bs":100,"n":"name","u":"unit","t":300,"ut":150,"v":42,"s":10}]
// For more details for mapping SenML labels to integers, please take a look here: https://tools.ietf.org/html/rfc8428#page-19.
jsonBytes, err := hex.DecodeString("5b7b22626e223a22626173652d6e616d65222c226274223a3130302c226275223a22626173652d756e6974222c2262766572223a31302c226276223a31302c226273223a3130302c226e223a226e616d65222c2275223a22756e6974222c2274223a3330302c227574223a3135302c2276223a34322c2273223a31307d5d")
assert.Nil(t, err, "Decoding JSON expected to succeed")
Expand Down
20 changes: 20 additions & 0 deletions pkg/transformers/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,23 @@ type Transformer interface {
// Transform Magistrala message to any other format.
Transform(msg *messaging.Message) (interface{}, error)
}

type number interface {
uint64 | int64 | float64
}

// ToUnixNano converts time to UnixNano time format.
func ToUnixNano[N number](t N) N {
switch {
case t == 0:
return 0
case t >= 1e18: // Check if the value is in nanoseconds
return t
case t >= 1e15 && t < 1e18: // Check if the value is in milliseconds
return t * 1e3
case t >= 1e12 && t < 1e15: // Check if the value is in microseconds
return t * 1e6
default: // Assume it's in seconds (Unix time)
return t * 1e9
}
}
140 changes: 140 additions & 0 deletions pkg/transformers/transformer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright (c) Abstract Machines
// SPDX-License-Identifier: Apache-2.0

package transformers_test

import (
"testing"
"time"

"github.com/absmach/magistrala/pkg/transformers"
)

var now = time.Now()

func TestInt64ToUnixNano(t *testing.T) {
cases := []struct {
desc string
time int64
want int64
}{
{
desc: "empty",
time: 0,
want: 0,
},
{
desc: "unix",
time: now.Unix(),
want: now.Unix() * int64(time.Second),
},
{
desc: "unix milli",
time: now.UnixMilli(),
want: now.UnixMilli() * int64(time.Millisecond),
},
{
desc: "unix micro",
time: now.UnixMicro(),
want: now.UnixMicro() * int64(time.Microsecond),
},
{
desc: "unix nano",
time: now.UnixNano(),
want: now.UnixNano(),
},
{
desc: "1e9 nano",
time: time.Unix(1e9, 0).Unix(),
want: time.Unix(1e9, 0).UnixNano(),
},
{
desc: "1e10 nano",
time: time.Unix(1e10, 0).Unix(),
want: time.Unix(1e10, 0).UnixNano(),
},
{
desc: "1e12 nano",
time: time.UnixMilli(1e12).Unix(),
want: time.UnixMilli(1e12).UnixNano(),
},
{
desc: "1e13 nano",
time: time.UnixMilli(1e13).Unix(),
want: time.UnixMilli(1e13).UnixNano(),
},
{
desc: "1e15 nano",
time: time.UnixMicro(1e15).Unix(),
want: time.UnixMicro(1e15).UnixNano(),
},
{
desc: "1e16 nano",
time: time.UnixMicro(1e16).Unix(),
want: time.UnixMicro(1e16).UnixNano(),
},
}

for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
got := transformers.ToUnixNano(c.time)
if got != c.want {
t.Errorf("ToUnixNano(%d) = %d; want %d", c.time, got, c.want)
}
t.Logf("ToUnixNano(%d) = %d; want %d", c.time, got, c.want)
})
}
}

func TestFloat64ToUnixNano(t *testing.T) {
cases := []struct {
desc string
time float64
want float64
}{
{
desc: "empty",
time: 0,
want: 0,
},
{
desc: "unix",
time: float64(now.Unix()),
want: float64(now.Unix() * int64(time.Second)),
},
{
desc: "unix milli",
time: float64(now.UnixMilli()),
want: float64(now.UnixMilli() * int64(time.Millisecond)),
},
{
desc: "unix micro",
time: float64(now.UnixMicro()),
want: float64(now.UnixMicro() * int64(time.Microsecond)),
},
{
desc: "unix nano",
time: float64(now.UnixNano()),
want: float64(now.UnixNano()),
},
}

for _, c := range cases {
t.Run(c.desc, func(t *testing.T) {
got := transformers.ToUnixNano(c.time)
if got != c.want {
t.Errorf("ToUnixNano(%f) = %f; want %f", c.time, got, c.want)
}
t.Logf("ToUnixNano(%f) = %f; want %f", c.time, got, c.want)
})
}
}

func BenchmarkToUnixNano(b *testing.B) {
for i := 0; i < b.N; i++ {
transformers.ToUnixNano(now.Unix())
transformers.ToUnixNano(now.UnixMilli())
transformers.ToUnixNano(now.UnixMicro())
transformers.ToUnixNano(now.UnixNano())
}
}

0 comments on commit ec7b4b4

Please sign in to comment.