-
Notifications
You must be signed in to change notification settings - Fork 2
[TEST] Encina.Audit.Marten integration tests — real Marten store end-to-end #951
Copy link
Copy link
Open
Labels
area-auditAudit trails and change trackingAudit trails and change trackingarea-complianceGDPR, EU Laws, and Regulatory Compliance patternsGDPR, EU Laws, and Regulatory Compliance patternsarea-event-sourcingEvent Sourcing patterns and infrastructureEvent Sourcing patterns and infrastructurearea-martenMarten event sourcing providerMarten event sourcing providerarea-testingTesting utilities and frameworksTesting utilities and frameworkscomplexity-mediumComplexity: MediumComplexity: MediumdogfoodingUsing Encina.Testing infrastructure in Encina's own testsUsing Encina.Testing infrastructure in Encina's own testsmarten-integrationMarten library integrationMarten library integrationpriority-highPriority: High (⭐⭐⭐⭐)Priority: High (⭐⭐⭐⭐)testing-integrationIntegration testing utilitiesIntegration testing utilities
Milestone
Metadata
Metadata
Assignees
Labels
area-auditAudit trails and change trackingAudit trails and change trackingarea-complianceGDPR, EU Laws, and Regulatory Compliance patternsGDPR, EU Laws, and Regulatory Compliance patternsarea-event-sourcingEvent Sourcing patterns and infrastructureEvent Sourcing patterns and infrastructurearea-martenMarten event sourcing providerMarten event sourcing providerarea-testingTesting utilities and frameworksTesting utilities and frameworkscomplexity-mediumComplexity: MediumComplexity: MediumdogfoodingUsing Encina.Testing infrastructure in Encina's own testsUsing Encina.Testing infrastructure in Encina's own testsmarten-integrationMarten library integrationMarten library integrationpriority-highPriority: High (⭐⭐⭐⭐)Priority: High (⭐⭐⭐⭐)testing-integrationIntegration testing utilitiesIntegration testing utilities
Projects
StatusShow more project fields
Todo
Test Category
Description
Encina.Audit.Martencurrently has no integration tests — the foldertests/Encina.IntegrationTests/AuditMarten/does not exist. This gap allowed #949 (IServiceProviderrejected by JasperFx projection validator) to ship undetected: every unit test bypassed Marten's projection graph, soConfigureMartenAuditProjections.Configure(StoreOptions)was never actually invoked end-to-end in CI.The fix for #949 added a unit test (
Configure_ValidOptions_RegistersAuditProjections) that exercises theStoreOptions.Projections.Add(...)path on a plainStoreOptionsinstance, which is sufficient to regression-lock theInvalidProjectionException. However, the full async projection daemon, temporal key lookup viaIDocumentOperations, and crypto-shredding lifecycle have never been exercised against a real PostgreSQL-backed Marten store.This issue tracks building that integration coverage.
Packages / Providers Affected
Encina.Audit.MartenCurrent Coverage
Encina.Audit.MartenPer CLAUDE.md database test policy: "For database-related milestones, DO NOT create
.mdjustification files for IntegrationTests — create real IntegrationTests using Docker/Testcontainers. The whole point of database features is to interact with real databases."Infrastructure Required
postgres:17-alpineservice indocker-compose.yml)A
MartenAuditFixtureneeds to be created following the same pattern asEFCorePostgreSqlFixture: a collection fixture that boots Marten against the shared PostgreSQL container and runsClearAllDataAsync()between tests (dropping themt_doc_audit_entry_read_model,mt_doc_read_audit_entry_read_model,mt_doc_temporal_key_document,mt_doc_temporal_key_destroyed_marker, andmt_eventstables).Test Plan
Tests to Implement
Store registration & boot
AddEncinaAuditMarten_BootsMartenStore_WithoutThrowing— regression test for [BUG] Marten audit projections unregisterable: IServiceProvider parameter rejected by JasperFx validation #949 against a real store (not justStoreOptions)AddEncinaAuditMarten_WithCustomShreddedPlaceholder_RegistersProjectionsAddEncinaAuditMarten_WithAddHealthCheckTrue_RegistersHealthCheckAddEncinaAuditMarten_WithEnableAutoPurgeTrue_RegistersHostedServiceWrite path (MartenAuditStore)
AddAsync_PersistsEncryptedEntry_AndAppendsAuditEntryRecordedEventAddAsync_MultipleEntries_SameTemporalPeriod_ReuseSameKeyAddAsync_EntriesInDifferentPeriods_CreateSeparateKeysRead path (MartenReadAuditStore)
AddReadAsync_PersistsEncryptedReadEntryAsync projection daemon (AuditEntryProjection.Create)
DaemonRebuild_ProjectsAllEventsIntoAuditEntryReadModel_WithDecryptedPii— starts the async daemon, waits for high-water-mark catch-up, then asserts theAuditEntryReadModeldocuments match the events with decrypted PII fieldsDaemonRebuild_WithDestroyedTemporalKey_ProjectsShreddedPlaceholder— creates events, destroys the key viaDestroyKeysBeforeAsync, rebuilds projection, assertsIsShredded == trueandUserId == \"[SHREDDED]\"DaemonRebuild_WithCustomPlaceholder_ProjectsCustomPlaceholder— verifiesMartenAuditOptions.ShreddedPlaceholderis wired through the projection constructorRead audit projection (ReadAuditEntryProjection.Create)
DaemonRebuild_ProjectsAllReadEvents_WithDecryptedPiiDaemonRebuild_ReadEvent_WithDestroyedKey_ProjectsShreddedPlaceholderTemporal key lifecycle
DestroyKeysBeforeAsync_RemovesKeyDocuments_AndStoresDestroyedMarkerDestroyKeysBeforeAsync_IdempotentForAlreadyDestroyedPeriodsGetOrCreateKeyAsync_AfterDestruction_ReturnsKeyNotFoundErrorRetention service (MartenAuditRetentionService)
MartenAuditRetentionService_CrossesRetentionBoundary_DestroysExpiredKeysSuccess Criteria
Encina.Audit.Martenreaches ≥85% line coverage on the integration flagConfigure_ValidOptions_RegistersProjectionsAndIndexesruns against a booted Marten storePostgreSqlFixturecollection pattern)Collection Fixture (Integration Tests Only)
Marten-AuditMarten(new — per-package collection since Marten audit has its own document schema)MartenAuditFixture(new) — reuses the existing shared PostgreSQL container via thepostgresdocker-compose service, but scopes the Marten document store to a dedicated schema (encina_audit_test) to avoid collisions with other Marten integration testsAlternatively, this could use the
EFCorePostgreSqlFixtureconnection string with a uniqueDatabaseSchemaName— evaluate which approach minimizes containers during implementation.Related Issues
AggregateStreamAsyncdoesn't set Version (adjacent integration gap inEncina.Marten)Dependencies