elsa-core/test/integration/Elsa.Diagnostics.StructuredLogs.Persistence.ConformanceTests
Sipke Schoorstra 90c29fb589
test(diagnostics): add InMemory/Sqlite StructuredLog store conformance (#8151)
* test(diagnostics): add InMemory/Sqlite StructuredLog store conformance

Add a shared IStructuredLogStore matrix that locks Take clamp, SourceId
tie-break order, ListSources registry/heartbeat, DroppedEvents vs storage
diagnostics, and portable exact-case filters after #8147/#8148.

Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>

* test(diagnostics): lock Sequence and Id query tie-breaks

Cover the later IStructuredLogStore order stages independently so a
SourceId-only assertion cannot hide Sequence or Id regressions.

Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>

* test(diagnostics): isolate Sequence tie-break from Id order

Use IDs that sort opposite Sequence so a skip-Sequence, order-by-Id
implementation cannot pass the shared matrix.

Co-authored-by: Sipke Schoorstra <sipkeschoorstra@outlook.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-09-14 13:20:51 +02:00
..
Elsa.Diagnostics.StructuredLogs.Persistence.ConformanceTests.csproj test(diagnostics): add InMemory/Sqlite StructuredLog store conformance (#8151) 2026-09-14 13:20:51 +02:00
README.md test(diagnostics): add InMemory/Sqlite StructuredLog store conformance (#8151) 2026-09-14 13:20:51 +02:00
StructuredLogStoreConformanceTests.cs test(diagnostics): add InMemory/Sqlite StructuredLog store conformance (#8151) 2026-09-14 13:20:51 +02:00
StructuredLogStoreScenario.cs test(diagnostics): add InMemory/Sqlite StructuredLog store conformance (#8151) 2026-09-14 13:20:51 +02:00

StructuredLogs persistence conformance suite

Shared InMemory / Sqlite assertions for IStructuredLogStore. The matrix locks the contracts already aligned on main after #8147 (Take clamp) and #8148 (SourceId tie-break + registry-backed ListSources).

Shared contracts

Surface Locked behavior
Null Take / max clamp StructuredLogsOptions.MaxRecentLogQuerySize; negative ceiling or Take yields empty
Timestamp / ReceivedAt ties SourceId, then Sequence, then Id (each stage asserted with preceding fields tied; ascending after Relational DESC+Reverse)
ListSources In-process IStructuredLogSourceRegistry metadata and SourceHeartbeatTimeoutStale
QueryAsync.DroppedEvents when writes fit 0
Portable filters Exact-case equality, category prefix, text substring, level, and timestamp range applied before Take

Store-specific contracts (intentionally not unified)

QueryAsync.DroppedEvents after ring overflow. InMemory reports RingBuffer.DroppedCount. Relational QueryAsync stays 0; durable write-queue drops are IStructuredLogStorageDiagnostics.DroppedWriteCount on /storage. The matrix asserts both sides of that split so neither path can silently adopt the other.

Filter equality case folding. InMemory uses OrdinalIgnoreCase. Relational SQL uses = (collation-dependent; Sqlite default is BINARY). Category LIKE and text LIKE are ASCII case-insensitive on Sqlite, which happens to match InMemory for those predicates only. Tests seed exact-case filter values. Case-differing SourceId / TenantId / id equality is not portable across providers — recreate filters after a store change rather than relying on case-insensitive =. Same spirit as User Tasks title-cursor collation notes.

SourceId sort case folding. InMemory ThenBy uses OrdinalIgnoreCase. Relational ORDER BY SourceId follows the column collation. Tie-break tests use lowercase source IDs (pod-a, pod-b) so both providers agree.