Files
core/internal/ingest/service_observation_test.go

166 lines
5.9 KiB
Go

package ingest
import (
"encoding/json"
"testing"
"time"
)
func TestObservationDetailsPayloadIncludesStatusCheckedAt(t *testing.T) {
statusCheckedAt := "2026-02-10T15:28:00Z"
statusChangedAt := "2026-02-10T15:20:00Z"
errorDescription := "Error Code on GPU 0 [18:00.0] (S/N 1653925025827) = 020000190097 (unexpected device interrupts)"
historyDetails := "auto-recovered after reboot"
component := HardwareComponent{
ComponentType: "storage",
Status: "CRITICAL",
StatusCheckedAt: &statusCheckedAt,
StatusChangedAt: &statusChangedAt,
StatusHistory: []HardwareStatusHistoryEntry{
{Status: "CRITICAL", ChangedAt: "2026-02-10T15:20:00Z"},
{Status: "OK", ChangedAt: "2026-02-10T15:25:00Z", Details: &historyDetails},
},
ErrorDescription: &errorDescription,
}
payload, err := observationDetailsPayload(component)
if err != nil {
t.Fatalf("observationDetailsPayload() error = %v", err)
}
var details map[string]any
if err := json.Unmarshal(payload, &details); err != nil {
t.Fatalf("unmarshal details: %v", err)
}
got, ok := details["status_checked_at"]
if !ok {
t.Fatalf("status_checked_at is missing in details payload")
}
if got != statusCheckedAt {
t.Fatalf("status_checked_at = %v, want %v", got, statusCheckedAt)
}
gotChangedAt, ok := details["status_changed_at"]
if !ok {
t.Fatalf("status_changed_at is missing in details payload")
}
if gotChangedAt != statusChangedAt {
t.Fatalf("status_changed_at = %v, want %v", gotChangedAt, statusChangedAt)
}
historyRaw, ok := details["status_history"].([]any)
if !ok {
t.Fatalf("status_history is missing in details payload")
}
if len(historyRaw) != 2 {
t.Fatalf("status_history len = %d, want 2", len(historyRaw))
}
gotErr, ok := details["error_description"]
if !ok {
t.Fatalf("error_description is missing in details payload")
}
if gotErr != errorDescription {
t.Fatalf("error_description = %v, want %v", gotErr, errorDescription)
}
}
func TestParseComponentStatusEventTime(t *testing.T) {
explicit := "2026-02-10T15:22:00Z"
component := HardwareComponent{
Status: statusCritical,
StatusChangedAt: &explicit,
StatusHistory: []HardwareStatusHistoryEntry{
{Status: "OK", ChangedAt: "2026-02-10T15:10:00Z"},
{Status: "CRITICAL", ChangedAt: "2026-02-10T15:18:00Z"},
},
}
actual := parseComponentStatusEventTime(component)
if actual == nil {
t.Fatalf("parseComponentStatusEventTime() = nil, want non-nil")
}
want, _ := time.Parse(time.RFC3339, explicit)
if !actual.Equal(want.UTC()) {
t.Fatalf("parseComponentStatusEventTime() = %s, want %s", actual.UTC().Format(time.RFC3339), want.UTC().Format(time.RFC3339))
}
}
func TestParseComponentStatusEventTimeFallsBackToStatusCheckedAt(t *testing.T) {
checkedAt := "2026-01-22T09:45:36Z"
component := HardwareComponent{
Status: statusCritical,
StatusCheckedAt: &checkedAt,
}
actual := parseComponentStatusEventTime(component)
if actual == nil {
t.Fatalf("parseComponentStatusEventTime() = nil, want non-nil")
}
want, _ := time.Parse(time.RFC3339, checkedAt)
if !actual.Equal(want.UTC()) {
t.Fatalf("parseComponentStatusEventTime() = %s, want %s", actual.UTC().Format(time.RFC3339), want.UTC().Format(time.RFC3339))
}
}
func TestCollectedFallbackTime(t *testing.T) {
collected, _ := time.Parse(time.RFC3339, "2026-02-10T15:30:00Z")
ingested, _ := time.Parse(time.RFC3339, "2026-02-10T15:40:00Z")
if got := collectedFallbackTime(collected, ingested); !got.Equal(collected.UTC()) {
t.Fatalf("collectedFallbackTime(collected, ingested) = %s, want %s", got.Format(time.RFC3339), collected.UTC().Format(time.RFC3339))
}
if got := collectedFallbackTime(time.Time{}, ingested); !got.Equal(ingested.UTC()) {
t.Fatalf("collectedFallbackTime(zero, ingested) = %s, want %s", got.Format(time.RFC3339), ingested.UTC().Format(time.RFC3339))
}
}
func TestEventFallbackTime(t *testing.T) {
actual, _ := time.Parse(time.RFC3339, "2026-02-10T15:22:00Z")
collected, _ := time.Parse(time.RFC3339, "2026-02-10T15:30:00Z")
ingested, _ := time.Parse(time.RFC3339, "2026-02-10T15:40:00Z")
if got := eventFallbackTime(&actual, ingested, collected); !got.Equal(actual.UTC()) {
t.Fatalf("eventFallbackTime(actual, ingested, collected) = %s, want %s", got.Format(time.RFC3339), actual.UTC().Format(time.RFC3339))
}
if got := eventFallbackTime(nil, ingested, collected); !got.Equal(ingested.UTC()) {
t.Fatalf("eventFallbackTime(nil, ingested, collected) = %s, want %s", got.Format(time.RFC3339), ingested.UTC().Format(time.RFC3339))
}
if got := eventFallbackTime(nil, time.Time{}, collected); !got.Equal(collected.UTC()) {
t.Fatalf("eventFallbackTime(nil, zero, collected) = %s, want %s", got.Format(time.RFC3339), collected.UTC().Format(time.RFC3339))
}
}
func TestParseComponentFirstSeenTime(t *testing.T) {
changedAt := "2026-02-10T15:22:00Z"
checkedAt := "2026-02-10T15:21:00Z"
component := HardwareComponent{
StatusChangedAt: &changedAt,
StatusCheckedAt: &checkedAt,
StatusHistory: []HardwareStatusHistoryEntry{
{Status: "OK", ChangedAt: "2026-02-10T15:10:00Z"},
{Status: "CRITICAL", ChangedAt: "2026-02-10T15:18:00Z"},
},
}
collected, _ := time.Parse(time.RFC3339, "2026-02-10T15:30:00Z")
ingested, _ := time.Parse(time.RFC3339, "2026-02-10T15:40:00Z")
got := parseComponentFirstSeenTime(component, collected, ingested)
want, _ := time.Parse(time.RFC3339, "2026-02-10T15:10:00Z")
if !got.Equal(want.UTC()) {
t.Fatalf("parseComponentFirstSeenTime() = %s, want %s", got.UTC().Format(time.RFC3339), want.UTC().Format(time.RFC3339))
}
}
func TestParseComponentFirstSeenTimeFallback(t *testing.T) {
component := HardwareComponent{}
collected, _ := time.Parse(time.RFC3339, "2026-02-10T15:30:00Z")
ingested, _ := time.Parse(time.RFC3339, "2026-02-10T15:40:00Z")
got := parseComponentFirstSeenTime(component, collected, ingested)
if !got.Equal(ingested.UTC()) {
t.Fatalf("parseComponentFirstSeenTime() = %s, want %s", got.UTC().Format(time.RFC3339), ingested.UTC().Format(time.RFC3339))
}
}