refactor(audience): SDK test pinning and sample-app custom events (SDK-277) - #727
Closed
ImmutableJeffrey wants to merge 24 commits into
Closed
Conversation
ImmutableJeffrey
force-pushed
the
chore/sdk-272-pr-2-catalogues-and-test-infra
branch
from
May 3, 2026 07:40
1d1a56d to
9c7496b
Compare
ImmutableJeffrey
force-pushed
the
chore/sdk-272-pr-3-test-pinning-and-sample-events
branch
2 times, most recently
from
May 3, 2026 07:43
7ccd158 to
9c4da2e
Compare
ImmutableJeffrey
force-pushed
the
chore/sdk-272-pr-2-catalogues-and-test-infra
branch
from
May 3, 2026 07:53
9c7496b to
91f1783
Compare
ImmutableJeffrey
force-pushed
the
chore/sdk-272-pr-3-test-pinning-and-sample-events
branch
from
May 3, 2026 07:54
9c4da2e to
ba0bcf4
Compare
ConstantsTests already pinned Constants.LibraryVersion against the
package.json "version" field so the two cannot silently drift; the
matching pin for Constants.LibraryName ("com.immutable.audience") and
package.json "name" was missing. Both feed context.library /
context.libraryVersion on every outgoing event, so a rename of either
side without the other would silently miscategorise events on the
backend.
Add a sibling LibraryName_MatchesPackageJson test that walks up to
the same package.json and asserts the two strings match. Reuses the
existing ReadPackageJson helper.
Follow-up to SDK-272 (centralisation of duplicated literals).
…off*Ms
HttpTransportTests pinned the backoff schedule with literal millisecond
numbers (5_000 / 10_000 / 20_000 / 40_000 / 60_000). Constants.HttpBackoff*Ms
now own those values, but the tests still hardcoded the numbers, so a
change to the constants would have flipped production behaviour while
the tests kept passing against the old expectations.
Switch every BackoffMs / NextAttemptAt assertion to derive from
Constants.HttpBackoff{1st,2nd,3rd,4th,Cap}Ms.
Follow-up to SDK-272 (centralisation of duplicated literals).
ParseLowercaseString was added in the SDK-272 stack as the inverse of
ToLowercaseString and consumed by the sample app to map wire strings
back to the enum. It had no direct test, so a typo in any of the eight
case branches or in the Custom fallback would land silently.
Add three parametrised cases:
- Each known enum value maps from its lowercase wire form.
- Mixed-case ("Steam", "STEAM", "Passport") still resolves
via ToLowerInvariant, matching the documented behaviour.
- null, empty, and unknown values fall back to Custom (the parser
never throws so producer code always gets a usable enum).
Follow-up to SDK-272 (centralisation of duplicated literals).
…l platforms Init's lowercase-normalisation tests covered "Steam" / "STEAM" / "steam" but not the other four public DistributionPlatforms values (Epic, GOG, Itch, Standalone). Adding a sixth platform would land without coverage. Add a parametrised Init_LowercasesDistributionPlatform_AcrossAllPublicValues test that takes each public DistributionPlatforms constant, uppercases it, runs Init, and asserts the canonical lowercase form is restored. Follow-up to SDK-272 (centralisation of duplicated literals).
…sages The two centralised message catalogues had no direct unit tests. Behavioural tests observed wording loosely via Does.Contain assertions, which let typos and partial rewords through. Add MessagesTests.cs with one fixture per catalogue. Each constant / formatter has an exact-string assertion. A reword anywhere in the catalogue now fails the build. Follow-up to SDK-272 (centralisation of duplicated literals).
ImmutableJeffrey
force-pushed
the
chore/sdk-272-pr-2-catalogues-and-test-infra
branch
from
May 3, 2026 07:58
91f1783 to
427f963
Compare
ImmutableJeffrey
force-pushed
the
chore/sdk-272-pr-3-test-pinning-and-sample-events
branch
4 times, most recently
from
May 3, 2026 19:06
cf5c443 to
ea260bf
Compare
…ent drafts Two Unity-only test fixtures the dotnet test runner cannot reach (DeviceCollector depends on UnityEngine.SystemInfo / Application; SampleAppUxml needs Unity test framework gating). Both run under the Unity Test Framework once the project is opened in the editor. DeviceCollectorTests (src/Packages/Audience/Tests/Editor/, excluded from the headless dotnet build by Audience.Tests.csproj's Compile Remove="Editor/**/*.cs" rule) pin DeviceCollector's emitted key sets against GameLaunchPropertyKeys and ContextKeys, assert that no unknown keys leak in either direction, and verify every string-typed value is capped at Constants.MaxFieldLength. SampleAppUxmlAlignmentTests (examples/audience/Assets/SampleApp/Tests/ Runtime/, gated by the existing UNITY_INCLUDE_TESTS define on the SampleApp.Tests asmdef) reads Resources/AudienceSample.uxml as XML and asserts every SampleAppUi name and Css constant that is slug-shaped (lowercase / dashes / no spaces) appears as a name= or class= attribute somewhere in the markup. Runtime-only CSS toggles (state-warn, copied, narrow, has-value, etc.) are filtered by the slug-shape heuristic so the test only flags constants that look like they should map directly to UXML. Both files compile cleanly. They will not run under dotnet test. Run them via Unity Test Runner. Follow-up to SDK-272 (centralisation of duplicated literals).
Per the user's "everything random goes in a constant" stance, this is applied against the previous session's recommendation that scenario descriptors read better inline. Recording the override on the user's explicit request. Follow-up to SDK-272 (centralisation of duplicated literals).
…leAppCustomEvents The sample-app demo catalogue (sign_up, sign_in, email_acquired, wishlist_add, wishlist_remove, game_page_viewed, link_clicked, screen_viewed) had its event-name strings inline at every call site. A rename touches the catalogue, the screen_viewed Track call, and each Unity live-fire test that drives the catalogue UI. Move the eight names into a new internal SampleAppCustomEvents class under the sample-app Scripts assembly. Update AudienceSample.Events.cs, AudienceSample.cs (screen_viewed Track), and SampleAppLiveFireTests.cs (button and field lookups by event name) to reference the constants. Per the user's "everything random goes in a constant" stance, applied against the previous session's recommendation that the demo content read better inline. Recording the override on the user's explicit request. Follow-up to SDK-272 (centralisation of duplicated literals).
…mpleAppCustomEventPropertyKeys The sample-app demo catalogue, screen_viewed Track call, and the typed-event live-fire tests had property keys (method, source, gameId, platform, gameName, slug, url, label, path) inline at every call site. Each key duplicates between the catalogue's EventField definition and the live-fire test's UI lookup. Add SampleAppCustomEventPropertyKeys alongside SampleAppCustomEvents (mirrors the SDK's EventPropertyKeys naming) and reference the constants from AudienceSample.Events.cs, AudienceSample.cs (the screen_viewed props dictionary), and SampleAppLiveFireTests.cs (the TypedEventField field-name lookups). Includes gameName and slug beyond the user's listed seven keys: same inline-property-key category, same migration treatment. Per the user's "everything random goes in a constant" stance, applied against the previous session's recommendation that the demo content read better inline. Recording the override on the user's explicit request. Follow-up to SDK-272 (centralisation of duplicated literals).
…xtures The SDK test suite repeated the same identifier and payload literals across MessageBuilderTests, TypedEventTests, JsonTests, ImmutableAudienceTests, and DeleteDataTests. The pairs that appeared both as inputs and as assertion targets were the worst offenders (anon-42, user-42, user-99, from-id, to-id) since a typo flipping one side would silently pass on the other. Add TestFixtures alongside TestDefaults (which already centralises config defaults) and reference TestFixtures.X across the five files. Constants cover anonymous IDs (1, 42, 123), user IDs (42, 99), alias endpoints (from / to), identity values keyed to IdentityType.Custom / Steam / Passport (player-42 / player_steam / player_passport), Resource event payload values (gold currency, quest_reward itemType, main_quest_01 itemId), Purchase event payload values (gem_pack_01 itemId, Starter Gem Pack itemName, txn_abc123 transactionId), and the MilestoneReached name (first_boss_defeated). Includes main_quest_01, player_passport, anon-123, and first_boss_defeated beyond the user's listed values: same per-fixture data category, same migration treatment. tutorial_complete from the user's list does not appear in the test suite (the milestone fixture uses first_boss_defeated); skipped on that basis. Per the user's "everything random goes in a constant" stance, applied against the previous session's recommendation that scenario descriptors read better inline. Recording the override on the user's explicit request. Follow-up to SDK-272 (centralisation of duplicated literals).
TestEventNames.cs (SHA 6d237a3a) was committed without its .meta file. Unity generates one on project open, but the convention across the test folder is to commit them so the GUID is stable across machines (mirrors TestDefaults.cs.meta and TestFixtures.cs.meta). Follow-up to SDK-272 (centralisation of duplicated literals).
…enarios
Adds named event-name constants for the EventQueue scenario tests
(IntervalFlush, DisposeTest), placeholder constants for transport /
queue scaffolding where the event name is just filler (PlaceholderA,
PlaceholderB, PlaceholderTest, PlaceholderTrack, PlaceholderIgnored,
PlaceholderEvt), and BlockedPrefix for the OfflineResilienceTests
$"blocked_{i}" templated string.
Migrates inline references in:
- MessageBuilderTests ("evt" placeholders, six sites)
- EventQueueTests (Msg() helper calls, six sites)
- HttpTransportTests (WireFixture.Track event-name args, eight sites)
- OfflineResilienceTests ($"blocked_{i}" templated literal, three sites)
Per the user's "everything random goes in a constant" stance.
Follow-up to SDK-272 (centralisation of duplicated literals).
…d lookups in live-fire tests
SampleAppLiveFireTests filled the Resource, Purchase, and
MilestoneReached typed-event forms by looking up TextFields with
inline property-name strings ("currency", "amount", "value", "name").
The SDK already centralises these as EventPropertyKeys.Currency /
.Amount / .Value / .Name, made visible to the sample-app tests
through the existing InternalsVisibleTo grant.
Reference EventPropertyKeys.X from the five lookup sites instead of
re-typing the wire-format strings.
Discovered during the sample-app demo property-key centralisation
pass; kept separate because these keys belong to the SDK's typed-event
surface, not the sample-app demo catalogue.
Per the user's "everything random goes in a constant" stance.
Follow-up to SDK-272 (centralisation of duplicated literals).
Adds:
- Track properties: CustomPropKeyRecipeId, CraftingRecipeIronSword
- Distribution platform fixture: ProviderValue
- IdentityType fallback fixture: UnknownProvider
- Identity persistence fixtures: PreExistingId, PreExistingIdFromLastLaunch
- ConsentStore corruption fixture: NotAnInt
- Stress test userId: UserRaceStress
- DeleteData generic userId: SomeUser
- Templated prefix for GzipTests $"anon-{i}": AnonIdPrefix
- Minimal placeholders for MessageBuilder Identify / Alias arg slots
(GenericUserId, GenericFromId, GenericToId, GenericFromType,
GenericToType)
Migrates inline references in:
- DeleteDataTests
- ImmutableAudienceTests (Track props, race-stress userId, provider value)
- Core/IdentityTests (pre-existing-id fixtures)
- IdentityTypeTests (TestCase attribute now references the const)
- Core/ConsentStoreTests (corrupt-file fixture)
- Utility/GzipTests (anon-{i} templated prefix)
- Events/MessageBuilderTests (Identify / Alias placeholder slots)
Per the user's "everything random goes in a constant" stance.
Follow-up to SDK-272 (centralisation of duplicated literals).
Adds SampleAppLiveFireFixtures alongside SampleAppLiveFireTests with three constants (MilestoneSmokeName, GameId, LinkUrl) shared across five inline call sites in the live-fire batch. Retargeting the smoke suite (e.g. switching the game id slug) is now a one-line change instead of a five-line touch. Migrates inline references in SampleAppLiveFireTests for the typed-event Resource / Purchase / MilestoneReached fills and the sample-app custom catalogue fills (WishlistAdd, WishlistRemove, GamePageViewed, LinkClicked). Per the user's "everything random goes in a constant" stance. Follow-up to SDK-272 (centralisation of duplicated literals).
…AppUi.LogPayloadKeys The sample-app builds Dictionary<string, object> echo payloads for each RunAndLog "Ok" row (Track outcomes, Identify / Alias outcomes, OnError rows, Init config echo). Each key was inline at the construction site, so a rename (e.g. "publishableKey" to "key") would touch six call sites today and grow as the demo expands. Adds a LogPayloadKeys sub-class to SampleAppUi with eighteen constants covering the existing payload schema (Event, Overload, Effects, Id, Accepted, From, To, Code, Message, Consent, Debug, FlushIntervalSeconds, FlushSize, PackageVersion, ShutdownFlushTimeoutMs, PublishableKey, PersistentDataPath) plus a nested OverloadValues for the "typed" / "string" enum-like values written under LogPayloadKeys.Overload. Migrates AudienceSample.cs to reference the constants. UXML element names (in the existing SampleAppUi sub-classes) are unchanged. Per the user's "everything random goes in a constant" stance. Follow-up to SDK-272 (centralisation of duplicated literals).
…Messages AudienceSample.cs had inline status strings at every RunAndLog "Ok" return and AppendLog call (SDK stopped, anonymous ID regenerated queue cleared, queue flushed, erasure request dispatched, backend acknowledged, plus two interpolated messages for track-dropped and flushInterval-clamped warnings). Adds five plain-string constants and two format-string constants (suffixed Fmt, used with string.Format) to the existing SampleAppUi.Messages catalogue alongside the consent-flow messages already centralised there. Migrates seven inline references in AudienceSample.cs. The two interpolated status strings used em-dashes; replaced with commas in the centralised form to match the project glyph rule. NoActiveIdentity (already in Messages) had the same em-dash artefact and gets the same comma replacement. Per the user's "everything random goes in a constant" stance. Follow-up to SDK-272 (centralisation of duplicated literals).
…fixtures
HttpTransportTests had inline literals for the malformed-body
diagnostic ("not-json"), the empty JSON object body ("{}"), and the
exception messages thrown by MockHandler factories ("connection
refused", "Request timed out", "simulated").
Adds five file-local consts (MalformedResponseBody, EmptyJsonObjectBody,
ConnectionRefusedMessage, RequestTimedOutMessage,
SimulatedCancellationMessage) at the top of the fixture and migrates
six call sites. The empty body "" is left inline since "the body is
truly empty" carries the meaning at the call site.
NUnit assertions never check the exception messages, but pinning the
"what failure was simulated" intent keeps the fixture's catalogue of
network failure modes visible in one place.
Per the user's "everything random goes in a constant" stance.
Follow-up to SDK-272 (centralisation of duplicated literals).
…CSS classes
AudienceSample.UI.cs RefreshStatusBar set status-cell classes via
inline strings ("state-warn", "state-ok", and "dim" five times) even
though SampleAppUi.Css.StateWarn / .StateOk / .Dim already exist for
exactly this purpose.
Migrates seven call sites to the constants. CSS-side renames now
need to touch one place (Css.Dim) instead of grep-and-replace across
the SetStatusCell call sites.
Per the user's "everything random goes in a constant" stance.
Follow-up to SDK-272 (centralisation of duplicated literals).
…AppUi.ButtonText.CopiedFlash
AudienceSample.UI.cs:368 set the click-to-copy flash via inline
"Copied!". Distinct from the existing SampleAppUi.ButtonText.Copied
("Copied", no exclamation) used as the persistent button label after
copying. Both strings can drift independently today.
Adds ButtonText.CopiedFlash with a comment noting the distinction
and migrates the inline reference. The two consts now sit next to
each other so a future translation pass would catch both.
Per the user's "everything random goes in a constant" stance.
Follow-up to SDK-272 (centralisation of duplicated literals).
JsonTests and JsonReaderTests both used the same literals to verify round-trip behaviour: each input dictionary in JsonTests had a matching encoded form in JsonReaderTests, and vice versa. The single string pair (key / hello), the all-escapes string (val / "say \"hi\"\nback\\slash\ttab"), and the nested object (outer / inner / value) appeared duplicated in both files. Adds JsonRoundTripFixtures with the raw key, raw value, and exact-encoded form for each of the three pairs. Migrates six references across the two files. Renaming any fixture (e.g. swapping "hello" for "world") now needs one edit and both tests stay coherent. Per the user's "everything random goes in a constant" stance. Follow-up to SDK-272 (centralisation of duplicated literals).
…enario values
Adds:
- Currency code fixtures: UsdCurrency ("USD"), EurCurrency ("EUR"),
used across Purchase / Resource typed-event tests
- Progression world fixture: ProgressionWorldTutorial ("tutorial"),
three uses across TypedEventTests and ImmutableAudienceTests
- Exception fixture: ContextProviderBoomMessage ("boom"),
for the ContextProvider sabotage test
- Disk-block sentinel: DiskBlockerContent ("blocker"),
written to the queue directory path so creation fails
- DistributionPlatform mixed-case fixtures:
DistributionPlatformSteamCased ("Steam"),
DistributionPlatformSteamUppercase ("STEAM"),
for Init's lowercase-normalisation test
- Application.platform fixture: PlatformWindows ("WindowsPlayer"),
for the GameLaunch.Platform test
- Generic alias endpoint fixtures: GenericAliasFromId ("fromId"),
GenericAliasToId ("toId"), GenericAliasFromShort ("from"),
for Alias argument-validation tests where the value is filler
Migrates inline references in:
- Events/TypedEventTests (seven Purchase / Resource currency and
Progression world fills)
- ImmutableAudienceTests (boom, USD x2, fromId/toId, from, tutorial,
Steam, STEAM, WindowsPlayer)
- OfflineResilienceTests (blocker)
IdentityTypeTests "Steam" / "STEAM" left inline; the wire-format
casing fixtures stay self-contained inside that test until the
IdentityType wire-format extraction lands. MessagesTests "USD" /
"usd" left inline; the literals there appear inside expected error
strings being verified, so centralising would defeat the test's
own pinning.
Per the user's "everything random goes in a constant" stance.
Follow-up to SDK-272 (centralisation of duplicated literals).
…s file-local consts
ConstantsTests had inline literals for the publishable-key fixtures
the BaseUrl resolution tests pass through Constants.BaseUrl
("pk_imapik-test-abc", "pk_imapik-prod-abc"), the custom override
URL ("https://api.dev.immutable.com"), and the package.json
discovery-walk components ("src", "Packages", "Audience",
"package.json", and the JSON field names "version" / "name").
Adds nine file-local consts at the top of the fixture (matching
the PublishableKeyPrefixTests TestPrefixKey / NonTestKey precedent)
and migrates eleven references across the BaseUrl tests, the
package.json LibraryVersion / LibraryName tests, and the
ReadPackageJson upward-walk helper.
Per the user's "everything random goes in a constant" stance.
Follow-up to SDK-272 (centralisation of duplicated literals).
ImmutableJeffrey
force-pushed
the
chore/sdk-272-pr-3-test-pinning-and-sample-events
branch
from
May 3, 2026 19:15
ea260bf to
4bacd74
Compare
…d-sample-polish refactor(audience): test fixtures and sample-app polish (SDK-277)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Constants.LibraryNameagainst thenamefield inpackage.json.Constants.HttpBackoff*Msinstead of magic numbers.IdentityTypeExtensions.ParseLowercaseStringcases (known platform, unknown, null, empty, mixed case fallback toCustom).DistributionPlatformcasing tests across all platform values.AudienceErrorMessagesandAudienceArgumentMessagesconstants and formatters to their exact wording so a reword fails the build.DeviceCollectorTestsandSampleAppUxmlAlignmentTestsdrafts; both gated byUNITY_INCLUDE_TESTSand excluded from the headlessdotnetbuild viaAudience.Tests.csproj.TestEventNamesfor per-test event-name strings.SampleAppCustomEventsandSampleAppCustomEventPropertyKeysfor the sample-app demo catalogue's custom event names and property keys.SampleAppLiveFireTeststhroughEventPropertyKeys.OnErrorcallback contract unchanged.Linear: SDK-277