119 lines
3.7 KiB
Go
119 lines
3.7 KiB
Go
package normalize
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.maximumdirect.net/ejr/feedkit/event"
|
|
)
|
|
|
|
func TestPayloadJSONBytesSupportedShapes(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
payload any
|
|
want string
|
|
}{
|
|
{name: "rawmessage", payload: json.RawMessage(`{"a":1}`), want: `{"a":1}`},
|
|
{name: "bytes", payload: []byte(`{"a":2}`), want: `{"a":2}`},
|
|
{name: "string", payload: `{"a":3}`, want: `{"a":3}`},
|
|
{name: "map", payload: map[string]any{"a": 4}, want: `{"a":4}`},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
got, err := PayloadJSONBytes(event.Event{Payload: tc.payload})
|
|
if err != nil {
|
|
t.Fatalf("PayloadJSONBytes() unexpected error: %v", err)
|
|
}
|
|
if string(got) != tc.want {
|
|
t.Fatalf("PayloadJSONBytes() = %s, want %s", string(got), tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPayloadJSONBytesRejectsInvalidPayloads(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
payload any
|
|
want string
|
|
}{
|
|
{name: "nil", payload: nil, want: "payload is nil"},
|
|
{name: "empty rawmessage", payload: json.RawMessage{}, want: "payload is empty json.RawMessage"},
|
|
{name: "empty bytes", payload: []byte{}, want: "payload is empty []byte"},
|
|
{name: "empty string", payload: "", want: "payload is empty string"},
|
|
{name: "unsupported", payload: 123, want: "unsupported payload type"},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
_, err := PayloadJSONBytes(event.Event{Payload: tc.payload})
|
|
if err == nil {
|
|
t.Fatalf("PayloadJSONBytes() expected error")
|
|
}
|
|
if !strings.Contains(err.Error(), tc.want) {
|
|
t.Fatalf("PayloadJSONBytes() error = %q, want substring %q", err, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDecodeJSONPayload(t *testing.T) {
|
|
type payload struct {
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
got, err := DecodeJSONPayload[payload](event.Event{
|
|
Payload: json.RawMessage(`{"name":"alice"}`),
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("DecodeJSONPayload() unexpected error: %v", err)
|
|
}
|
|
if got.Name != "alice" {
|
|
t.Fatalf("DecodeJSONPayload() = %#v, want name alice", got)
|
|
}
|
|
}
|
|
|
|
func TestFinalizeEventPreservesEnvelopeAndEffectiveAtBehavior(t *testing.T) {
|
|
existingEffectiveAt := time.Date(2026, 3, 28, 11, 0, 0, 0, time.UTC)
|
|
in := event.Event{
|
|
ID: "evt-1",
|
|
Kind: event.Kind("observation"),
|
|
Source: "source-a",
|
|
EmittedAt: time.Date(2026, 3, 28, 12, 0, 0, 0, time.UTC),
|
|
EffectiveAt: &existingEffectiveAt,
|
|
Schema: "raw.example.v1",
|
|
Payload: map[string]any{"old": true},
|
|
}
|
|
|
|
out, err := FinalizeEvent(in, "example.v1", map[string]any{"value": 1.234567}, time.Time{})
|
|
if err != nil {
|
|
t.Fatalf("FinalizeEvent() unexpected error: %v", err)
|
|
}
|
|
if out.ID != in.ID || out.Kind != in.Kind || out.Source != in.Source || out.EmittedAt != in.EmittedAt {
|
|
t.Fatalf("FinalizeEvent() changed preserved envelope fields: %#v", out)
|
|
}
|
|
if out.EffectiveAt == nil || !out.EffectiveAt.Equal(existingEffectiveAt) {
|
|
t.Fatalf("FinalizeEvent() effectiveAt = %#v, want preserved existing value", out.EffectiveAt)
|
|
}
|
|
|
|
nextEffectiveAt := time.Date(2026, 3, 28, 13, 0, 0, 0, time.FixedZone("x", -4*3600))
|
|
out, err = FinalizeEvent(in, "example.v1", map[string]any{"value": 1.234567}, nextEffectiveAt)
|
|
if err != nil {
|
|
t.Fatalf("FinalizeEvent() unexpected overwrite error: %v", err)
|
|
}
|
|
if out.EffectiveAt == nil || !out.EffectiveAt.Equal(nextEffectiveAt.UTC()) {
|
|
t.Fatalf("FinalizeEvent() effectiveAt = %#v, want %s", out.EffectiveAt, nextEffectiveAt.UTC())
|
|
}
|
|
|
|
payloadMap, ok := out.Payload.(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("FinalizeEvent() payload type = %T, want map[string]any", out.Payload)
|
|
}
|
|
if payloadMap["value"] != 1.234567 {
|
|
t.Fatalf("FinalizeEvent() payload value = %#v, want unrounded 1.234567", payloadMap["value"])
|
|
}
|
|
}
|