using System.Text.Json; using Omika.Core.Observability.External; using Omika.Core.Observability.Outbox; using Omika.Tests.Observability.Forwarding; namespace Omika.Tests.Observability.Outbox; /// Tests du spool central (ClientCode autoritaire écrasé, champs préservés, bornes). public class CentralDiagnosticIngestionStoreTests : IDisposable { private readonly string _dir = ForwardingTestHarness.CreateTempDirectory(); public void Dispose() => ForwardingTestHarness.DeleteDirectory(_dir); private CentralDiagnosticIngestionStore NewStore() => new(new CentralDiagnosticOptions { Directory = _dir }); [Fact] public async Task Store_WritesAuthoritativeClientCode_OverridingPayload() { var store = NewStore(); RemoteDiagnosticRecord record = ForwardingTestHarness.NewRecord(clientCode: "AUTRECLIENT"); int accepted = await store.StoreAsync([record], "BATIK.01", "trace-id"); Assert.Equal(1, accepted); string line = Assert.Single(OutboxTestHarness.ReadAllLinesShared(Assert.Single(Directory.EnumerateFiles(_dir, "*.jsonl")))); using JsonDocument document = JsonDocument.Parse(line); Assert.Equal("BATIK.01", document.RootElement.GetProperty("clientCode").GetString()); } [Fact] public async Task Store_PreservesCanonicalFields() { var store = NewStore(); RemoteDiagnosticRecord record = ForwardingTestHarness.NewRecord( clientCode: "BATIK.01", component: "telemetry-core", screenCode: "AGENDA", featureCode: "AGENDA_REFRESH"); await store.StoreAsync([record], "BATIK.01", "trace-id"); string line = Assert.Single(OutboxTestHarness.ReadAllLinesShared(Assert.Single(Directory.EnumerateFiles(_dir, "*.jsonl")))); using JsonDocument document = JsonDocument.Parse(line); JsonElement root = document.RootElement; Assert.Equal(record.ActorKey, root.GetProperty("actorKey").GetString()); Assert.Equal(record.DeviceKey, root.GetProperty("deviceKey").GetString()); Assert.Equal(record.ServerInstance, root.GetProperty("serverInstance").GetString()); Assert.Equal(record.Environment, root.GetProperty("environment").GetString()); Assert.Equal(record.BatchId.ToString(), root.GetProperty("batchId").GetString()); JsonElement evt = root.GetProperty("event"); Assert.Equal("telemetry-core", evt.GetProperty("component").GetString()); Assert.Equal("AGENDA", evt.GetProperty("screenCode").GetString()); Assert.Equal("AGENDA_REFRESH", evt.GetProperty("featureCode").GetString()); // Identités brutes interdites : jamais dans le spool central. Assert.False(evt.TryGetProperty("deviceId", out _)); Assert.False(evt.TryGetProperty("clientId", out _)); } [Fact] public async Task Store_NoDirectory_Throws() { var store = new CentralDiagnosticIngestionStore(new CentralDiagnosticOptions { Directory = string.Empty }); await Assert.ThrowsAsync(() => store.StoreAsync([ForwardingTestHarness.NewRecord()], "BATIK.01", "trace-id")); } [Fact] public async Task Store_EmptyClientCode_Throws() { var store = NewStore(); await Assert.ThrowsAsync(() => store.StoreAsync([ForwardingTestHarness.NewRecord()], " ", "trace-id")); } }