using System; using System.Text.Json.Nodes; using System.Threading; using System.Threading.Tasks; using FluentAssertions; using Microsoft.Extensions.Logging.Abstractions; using Moq; using StellaOps.Findings.Ledger.Domain; using StellaOps.Findings.Ledger.Infrastructure; using StellaOps.Findings.Ledger.Services; using StellaOps.Findings.Ledger.Services.Incident; using Xunit; namespace StellaOps.Findings.Ledger.Tests.Services; public class LedgerEventWriteServiceIncidentTests { [Fact] public async Task AppendAsync_sequence_mismatch_records_conflict_snapshot() { var repo = new Mock(); repo.Setup(r => r.GetByEventIdAsync(It.IsAny(), It.IsAny(), It.IsAny())) .ReturnsAsync((LedgerEventRecord?)null); var chainId = Guid.NewGuid(); var chainHead = new LedgerChainHead( SequenceNumber: 1, EventHash: "hash-prev", RecordedAt: DateTimeOffset.UtcNow); repo.Setup(r => r.GetChainHeadAsync("tenant-a", chainId, It.IsAny())) .ReturnsAsync(chainHead); var scheduler = new Mock(); var diagnostics = new Mock(); var service = new LedgerEventWriteService( repo.Object, scheduler.Object, NullLogger.Instance, diagnostics.Object); var draft = new LedgerEventDraft( "tenant-a", chainId, 3, Guid.NewGuid(), LedgerEventConstants.EventFindingCreated, "v1", "finding-1", "artifact-1", null, "actor-1", "operator", DateTimeOffset.UtcNow, DateTimeOffset.UtcNow, new JsonObject(), new JsonObject(), null); var result = await service.AppendAsync(draft, CancellationToken.None); result.Status.Should().Be(LedgerWriteStatus.Conflict); diagnostics.Verify(d => d.RecordConflict(It.Is(s => s.Reason == "sequence_mismatch")), Times.Once); } }