All checks were successful
ci/woodpecker/push/build-image Pipeline was successful
137 lines
3.6 KiB
Go
137 lines
3.6 KiB
Go
package nws
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.maximumdirect.net/ejr/feedkit/event"
|
|
"gitea.maximumdirect.net/ejr/weatherfeeder/model"
|
|
"gitea.maximumdirect.net/ejr/weatherfeeder/standards"
|
|
)
|
|
|
|
func TestAlertsNormalizerMapsEndsSeparatelyFromExpires(t *testing.T) {
|
|
raw := []byte(`{
|
|
"updated":"2026-06-16T10:00:00+00:00",
|
|
"title":"Current watches, warnings, and advisories for St. Louis",
|
|
"features":[{
|
|
"id":"https://api.weather.gov/alerts/alert-1",
|
|
"properties":{
|
|
"event":"Flood Warning",
|
|
"headline":"Flood Warning issued",
|
|
"sent":"2026-06-16T09:55:00+00:00",
|
|
"effective":"2026-06-16T10:00:00+00:00",
|
|
"onset":"2026-06-16T10:15:00+00:00",
|
|
"ends":"2026-06-16T14:00:00+00:00",
|
|
"expires":"2026-06-16T11:00:00+00:00"
|
|
}
|
|
}]
|
|
}`)
|
|
|
|
out, err := AlertsNormalizer{}.Normalize(context.Background(), alertRawEvent(raw))
|
|
if err != nil {
|
|
t.Fatalf("Normalize() error = %v", err)
|
|
}
|
|
|
|
run := decodeAlertRun(t, out)
|
|
if len(run.Alerts) != 1 {
|
|
t.Fatalf("expected 1 alert, got %d", len(run.Alerts))
|
|
}
|
|
alert := run.Alerts[0]
|
|
wantEnds := time.Date(2026, 6, 16, 14, 0, 0, 0, time.UTC)
|
|
wantExpires := time.Date(2026, 6, 16, 11, 0, 0, 0, time.UTC)
|
|
if alert.Ends == nil || !alert.Ends.Equal(wantEnds) {
|
|
t.Fatalf("ends = %v, want %s", alert.Ends, wantEnds)
|
|
}
|
|
if alert.Expires == nil || !alert.Expires.Equal(wantExpires) {
|
|
t.Fatalf("expires = %v, want %s", alert.Expires, wantExpires)
|
|
}
|
|
}
|
|
|
|
func TestAlertsNormalizerDoesNotFallbackExpiresToEnds(t *testing.T) {
|
|
raw := []byte(`{
|
|
"updated":"2026-06-16T10:00:00+00:00",
|
|
"features":[{
|
|
"id":"alert-ends-only",
|
|
"properties":{
|
|
"event":"Heat Advisory",
|
|
"ends":"2026-06-16T22:00:00+00:00"
|
|
}
|
|
}]
|
|
}`)
|
|
|
|
out, err := AlertsNormalizer{}.Normalize(context.Background(), alertRawEvent(raw))
|
|
if err != nil {
|
|
t.Fatalf("Normalize() error = %v", err)
|
|
}
|
|
|
|
run := decodeAlertRun(t, out)
|
|
alert := run.Alerts[0]
|
|
if alert.Ends == nil {
|
|
t.Fatal("expected ends to be populated")
|
|
}
|
|
if alert.Expires != nil {
|
|
t.Fatalf("expected expires nil when upstream expires is absent, got %v", alert.Expires)
|
|
}
|
|
}
|
|
|
|
func TestAlertsNormalizerIgnoresInvalidEnds(t *testing.T) {
|
|
raw := []byte(`{
|
|
"updated":"2026-06-16T10:00:00+00:00",
|
|
"features":[{
|
|
"id":"alert-invalid-ends",
|
|
"properties":{
|
|
"event":"Special Weather Statement",
|
|
"ends":"not-a-time",
|
|
"expires":"2026-06-16T11:00:00+00:00"
|
|
}
|
|
}]
|
|
}`)
|
|
|
|
out, err := AlertsNormalizer{}.Normalize(context.Background(), alertRawEvent(raw))
|
|
if err != nil {
|
|
t.Fatalf("Normalize() error = %v", err)
|
|
}
|
|
|
|
run := decodeAlertRun(t, out)
|
|
alert := run.Alerts[0]
|
|
if alert.Ends != nil {
|
|
t.Fatalf("expected invalid ends to map nil, got %v", alert.Ends)
|
|
}
|
|
if alert.Expires == nil {
|
|
t.Fatal("expected expires to remain populated")
|
|
}
|
|
}
|
|
|
|
func alertRawEvent(raw []byte) event.Event {
|
|
emittedAt := time.Date(2026, 6, 16, 10, 5, 0, 0, time.UTC)
|
|
return event.Event{
|
|
ID: "raw-alerts",
|
|
Kind: event.Kind(standards.KindAlert),
|
|
Source: "NWSAlerts",
|
|
Schema: standards.SchemaRawNWSAlertsV1,
|
|
EmittedAt: emittedAt,
|
|
Payload: json.RawMessage(raw),
|
|
}
|
|
}
|
|
|
|
func decodeAlertRun(t *testing.T, e *event.Event) model.WeatherAlertRun {
|
|
t.Helper()
|
|
if e == nil {
|
|
t.Fatal("expected normalized event")
|
|
}
|
|
if e.Schema != standards.SchemaWeatherAlertV1 {
|
|
t.Fatalf("schema = %q, want %q", e.Schema, standards.SchemaWeatherAlertV1)
|
|
}
|
|
var run model.WeatherAlertRun
|
|
raw, err := json.Marshal(e.Payload)
|
|
if err != nil {
|
|
t.Fatalf("marshal alert payload: %v", err)
|
|
}
|
|
if err := json.Unmarshal(raw, &run); err != nil {
|
|
t.Fatalf("decode alert payload: %v", err)
|
|
}
|
|
return run
|
|
}
|