using System.Text; using System.Text.Json; using Omika.Core.Observability.External; using Omika.Core.Observability.Outbox; namespace Omika.Tests.Observability.External; /// /// §5C.1C — Le source fichier du RemoteDiagnosticForwarder applique la même /// protection partial-line que le reader du Worker (via JsonlCompleteLineReader). /// public class RemoteDiagnosticFileForwarderSourceTests { private static readonly UTF8Encoding Utf8NoBom = new(encoderShouldEmitUTF8Identifier: false); private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web); [Fact] public void PartialFinalLine_IsNotReturned_AndDoesNotAdvance() { string dir = CreateTempDir(); try { string line1 = Serialize(NewRecord(Guid.NewGuid())); string line2 = Serialize(NewRecord(Guid.NewGuid())); // fragment sans newline File.WriteAllText( Path.Combine(dir, "omika-mobile-diagnostic-20260101-001.jsonl"), line1 + "\n" + line2, Utf8NoBom); var source = new RemoteDiagnosticFileForwarderSource( new RemoteDiagnosticOptions { Directory = dir }, "forwarder-checkpoint.json"); RemoteDiagnosticForwardReadResult read = source.ReadNext(null, 10); Assert.Single(read.Records); // seul line1 (complète) Assert.Equal(0, read.NextPosition!.LineIndex); // fragment non checkpointé } finally { Directory.Delete(dir, recursive: true); } } [Fact] public void CompletePoisonLine_IsSkipped_AndCursorAdvances() { string dir = CreateTempDir(); try { string line = Serialize(NewRecord(Guid.NewGuid())); File.WriteAllText( Path.Combine(dir, "omika-mobile-diagnostic-20260101-001.jsonl"), "{ json invalide\n" + line + "\n", Utf8NoBom); var source = new RemoteDiagnosticFileForwarderSource( new RemoteDiagnosticOptions { Directory = dir }, "forwarder-checkpoint.json"); RemoteDiagnosticForwardReadResult read = source.ReadNext(null, 10); Assert.Single(read.Records); Assert.Equal(1, read.NextPosition!.LineIndex); // poison (0) sautée, ligne (1) } finally { Directory.Delete(dir, recursive: true); } } private static RemoteDiagnosticRecord NewRecord(Guid eventId) => new() { ReceivedAtUtc = DateTimeOffset.UtcNow, BatchId = Guid.NewGuid(), IngestionTraceId = Guid.NewGuid().ToString("D"), Event = new DiagnosticEventDto { EventId = eventId, EventCode = "TEST", TimestampUtc = DateTimeOffset.UtcNow, Level = "Info", Priority = "P2" } }; private static string Serialize(RemoteDiagnosticRecord record) => JsonSerializer.Serialize(record, JsonOptions); private static string CreateTempDir() { string dir = Path.Combine(Path.GetTempPath(), "omika-fwd-test-" + Guid.NewGuid().ToString("N")); Directory.CreateDirectory(dir); return dir; } }