using System; using System.Collections.Generic; using System.Text.Json.Nodes; namespace StellaOps.Notify.Models.Tests; public sealed class NotifyCanonicalJsonSerializerTests { [Fact] public void SerializeRuleIsDeterministic() { var ruleA = NotifyRule.Create( ruleId: "rule-1", tenantId: "tenant-a", name: "critical", match: NotifyRuleMatch.Create(eventKinds: new[] { NotifyEventKinds.ScannerReportReady }), actions: new[] { NotifyRuleAction.Create(actionId: "b", channel: "slack:sec"), NotifyRuleAction.Create(actionId: "a", channel: "email:soc") }, metadata: new Dictionary { ["beta"] = "2", ["alpha"] = "1" }, createdAt: DateTimeOffset.Parse("2025-10-18T00:00:00Z"), updatedAt: DateTimeOffset.Parse("2025-10-18T00:00:00Z")); var ruleB = NotifyRule.Create( ruleId: "rule-1", tenantId: "tenant-a", name: "critical", match: NotifyRuleMatch.Create(eventKinds: new[] { NotifyEventKinds.ScannerReportReady }), actions: new[] { NotifyRuleAction.Create(actionId: "a", channel: "email:soc"), NotifyRuleAction.Create(actionId: "b", channel: "slack:sec") }, metadata: new Dictionary { ["alpha"] = "1", ["beta"] = "2" }, createdAt: DateTimeOffset.Parse("2025-10-18T00:00:00Z"), updatedAt: DateTimeOffset.Parse("2025-10-18T00:00:00Z")); var jsonA = NotifyCanonicalJsonSerializer.Serialize(ruleA); var jsonB = NotifyCanonicalJsonSerializer.Serialize(ruleB); Assert.Equal(jsonA, jsonB); Assert.Contains("\"schemaVersion\":\"notify.rule@1\"", jsonA, StringComparison.Ordinal); } [Fact] public void SerializeEventOrdersPayloadKeys() { var payload = JsonNode.Parse("{\"b\":2,\"a\":1}"); var @event = NotifyEvent.Create( eventId: Guid.NewGuid(), kind: NotifyEventKinds.ScannerReportReady, tenant: "tenant-a", ts: DateTimeOffset.Parse("2025-10-18T05:41:22Z"), payload: payload, scope: NotifyEventScope.Create(repo: "ghcr.io/acme/api", digest: "sha256:123")); var json = NotifyCanonicalJsonSerializer.Serialize(@event); var payloadIndex = json.IndexOf("\"payload\":{", StringComparison.Ordinal); Assert.NotEqual(-1, payloadIndex); var aIndex = json.IndexOf("\"a\":1", payloadIndex, StringComparison.Ordinal); var bIndex = json.IndexOf("\"b\":2", payloadIndex, StringComparison.Ordinal); Assert.True(aIndex is >= 0 && bIndex is >= 0 && aIndex < bIndex, "Payload keys should be ordered alphabetically."); } }