Skip to content

Commit aa8e225

Browse files
test(audience-sdk): direct shape assertions for messageId, eventTimestamp, context
Replaces the SDK-149 caveat about indirect verification of message envelope shape. Previously the live-fire suite only confirmed shape via backend rejection — fragile (backend schema drift could mask SDK bugs) and dependent on an external service for what is fundamentally an offline assertion. New direct assertions in MessageBuilderTests: - messageId parses as Guid (Guid.TryParse). - messageId is unique across 1000 successive Track() calls (catches a regression where Guid.NewGuid is replaced by a deterministic source). - eventTimestamp parses via DateTime.TryParseExact("o", RoundtripKind), is UTC, and lies within ~2 s of construction time. - context.library and context.libraryVersion are non-empty strings. Covered for all three top-level message types (Track, Identify, Alias) via a shared EveryMessageType iterator.
1 parent 0d45cf9 commit aa8e225

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

src/Packages/Audience/Tests/Runtime/Events/MessageBuilderTests.cs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
using System;
12
using System.Collections.Generic;
3+
using System.Globalization;
24
using NUnit.Framework;
35

46
namespace Immutable.Audience.Tests
@@ -97,5 +99,68 @@ public void AllMessages_SurfaceIsUnity()
9799
Assert.AreEqual("unity", identify["surface"]);
98100
Assert.AreEqual("unity", alias["surface"]);
99101
}
102+
103+
[Test]
104+
public void AllMessages_MessageId_ParsesAsGuid()
105+
{
106+
foreach (var msg in EveryMessageType())
107+
{
108+
var id = (string)msg["messageId"];
109+
Assert.IsTrue(Guid.TryParse(id, out _),
110+
$"messageId must parse as Guid; got: '{id}'");
111+
}
112+
}
113+
114+
[Test]
115+
public void Track_MessageId_IsUniquePerCall()
116+
{
117+
// Backend deduplicates on messageId; collisions silently drop events.
118+
var ids = new HashSet<string>();
119+
for (var i = 0; i < 1000; i++)
120+
ids.Add((string)MessageBuilder.Track("evt", null, null, PackageVersion)["messageId"]);
121+
Assert.AreEqual(1000, ids.Count);
122+
}
123+
124+
[Test]
125+
public void AllMessages_EventTimestamp_IsRoundTripIso8601Utc()
126+
{
127+
// SDK uses DateTime.UtcNow.ToString("o") — round-trippable ISO 8601.
128+
// Backend schema requires this exact shape; previously only verified
129+
// indirectly via backend rejection.
130+
var before = DateTime.UtcNow.AddSeconds(-2);
131+
foreach (var msg in EveryMessageType())
132+
{
133+
var ts = (string)msg["eventTimestamp"];
134+
Assert.IsTrue(
135+
DateTime.TryParseExact(ts, "o", CultureInfo.InvariantCulture,
136+
DateTimeStyles.RoundtripKind, out var parsed),
137+
$"eventTimestamp must parse as ISO 8601 round-trip ('o') format; got: '{ts}'");
138+
Assert.AreEqual(DateTimeKind.Utc, parsed.Kind, "eventTimestamp must be UTC");
139+
Assert.That(parsed, Is.GreaterThanOrEqualTo(before),
140+
"eventTimestamp must be ~now, not stale");
141+
Assert.That(parsed, Is.LessThanOrEqualTo(DateTime.UtcNow.AddSeconds(2)),
142+
"eventTimestamp must be ~now, not future-dated");
143+
}
144+
}
145+
146+
[Test]
147+
public void AllMessages_Context_LibraryAndLibraryVersionAreNonEmptyStrings()
148+
{
149+
foreach (var msg in EveryMessageType())
150+
{
151+
var ctx = (Dictionary<string, object>)msg["context"];
152+
var library = ctx["library"] as string;
153+
var libraryVersion = ctx["libraryVersion"] as string;
154+
Assert.IsFalse(string.IsNullOrEmpty(library), "context.library must be non-empty string");
155+
Assert.IsFalse(string.IsNullOrEmpty(libraryVersion), "context.libraryVersion must be non-empty string");
156+
}
157+
}
158+
159+
private static IEnumerable<Dictionary<string, object>> EveryMessageType()
160+
{
161+
yield return MessageBuilder.Track("evt", null, null, PackageVersion);
162+
yield return MessageBuilder.Identify(null, "u1", "steam", PackageVersion);
163+
yield return MessageBuilder.Alias("f", "t1", "t", "t2", PackageVersion);
164+
}
100165
}
101166
}

0 commit comments

Comments
 (0)