using FluentAssertions; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; [Collection("Integration")] public class SepsisRefactorTests : IAsyncLifetime { private readonly ApiFixture _fixture; private Guid _encounterId; private Guid _patientId; public SepsisRefactorTests(ApiFixture fixture) => _fixture = fixture; public async Task InitializeAsync() { using var scope = _fixture.Services.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); await DbResetHelper.ResetAsync(db); var patient = new Patient { Id = Guid.NewGuid(), Mrn = "MRN-REFACTOR-001", FirstName = "Refactor", LastName = "Test", DateOfBirth = new DateOnly(1960, 1, 1), Gender = "M", CreatedAt = DateTimeOffset.UtcNow }; var encounter = new Encounter { Id = Guid.NewGuid(), PatientId = patient.Id, EncounterType = EncounterType.Inpatient, Status = EncounterStatus.Active, Department = Department.Icu, AttendingPhysician = "Dr. Refactor", AdmittedAt = DateTimeOffset.UtcNow, CreatedAt = DateTimeOffset.UtcNow }; db.Patients.Add(patient); db.Encounters.Add(encounter); await db.SaveChangesAsync(); _patientId = patient.Id; _encounterId = encounter.Id; } public Task DisposeAsync() => Task.CompletedTask; [Fact] public async Task SirsObservations_NoSepsisWarningAlert() { using var scope = _fixture.Services.CreateScope(); var qsofa = scope.ServiceProvider.GetRequiredService(); var db = scope.ServiceProvider.GetRequiredService(); await qsofa.ProcessObservationAsync(_encounterId, _patientId, "TEMP_C", 39m); await qsofa.ProcessObservationAsync(_encounterId, _patientId, "HEART_RATE", 110m); await qsofa.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 22m); await qsofa.ProcessObservationAsync(_encounterId, _patientId, "WBC_K_UL", 15m); (await db.ClinicalAlerts.CountAsync(a => a.AlertType == AlertType.SepsisWarning)) .Should().Be(0); } [Fact] public async Task SofaDelta2_TriggersSepsisBundleCreation() { using var scope = _fixture.Services.CreateScope(); var handler = scope.ServiceProvider.GetRequiredService(); var db = scope.ServiceProvider.GetRequiredService(); var alertId = Guid.NewGuid(); db.ClinicalAlerts.Add(new ClinicalAlert { Id = alertId, EncounterId = _encounterId, PatientId = _patientId, AlertType = AlertType.SofaSepsis, Severity = AlertSeverity.Critical, Details = "SOFA delta +2", Status = AlertStatus.Open, TriggeredAt = DateTimeOffset.UtcNow }); await db.SaveChangesAsync(); await handler.OnSepsisAlertCreatedAsync( _encounterId, alertId, AlertType.SofaSepsis, CancellationToken.None); (await db.SepsisBundles.CountAsync()).Should().Be(1); } [Fact] public async Task QsofaScreen_DoesNotTriggerBundle() { using var scope = _fixture.Services.CreateScope(); var detector = scope.ServiceProvider.GetRequiredService(); var db = scope.ServiceProvider.GetRequiredService(); await detector.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 24m); await detector.ProcessObservationAsync(_encounterId, _patientId, "SYSTOLIC_BP", 95m); (await db.SepsisBundles.CountAsync()).Should().Be(0); } [Fact] public async Task QsofaScreen_IsWarningNotCritical() { using var scope = _fixture.Services.CreateScope(); var detector = scope.ServiceProvider.GetRequiredService(); var db = scope.ServiceProvider.GetRequiredService(); await detector.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 24m); await detector.ProcessObservationAsync(_encounterId, _patientId, "SYSTOLIC_BP", 95m); var alert = await db.ClinicalAlerts.SingleAsync(); alert.AlertType.Should().Be(AlertType.QsofaScreen); alert.Severity.Should().Be(AlertSeverity.Warning); } [Fact] public void QsofaScreen_IsSuppressible() { AlertType.QsofaScreen.IsSuppressible().Should().BeTrue(); } [Fact] public async Task LegacySepsisWarning_StillQueryable() { using var scope = _fixture.Services.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); var alertService = scope.ServiceProvider.GetRequiredService(); db.ClinicalAlerts.Add(new ClinicalAlert { Id = Guid.NewGuid(), EncounterId = _encounterId, PatientId = _patientId, AlertType = AlertType.SepsisWarning, Severity = AlertSeverity.Critical, Details = "Legacy SIRS alert", Status = AlertStatus.Resolved, TriggeredAt = DateTimeOffset.UtcNow.AddDays(-1) }); await db.SaveChangesAsync(); var page = await alertService.ListByEncounterAsync(_encounterId, null, 1, 10); page.Items.Should().ContainSingle(a => a.AlertType == AlertType.SepsisWarning); } [Fact] public void CannotCreateNewSepsisWarning() { var act = () => AlertCreationGuard.EnsureAllowed(AlertType.SepsisWarning); act.Should().Throw() .WithMessage("*deprecated*"); } [Fact] public async Task SepsisBundleCompliance_StillTracked() { using var scope = _fixture.Services.CreateScope(); var handler = scope.ServiceProvider.GetRequiredService(); var db = scope.ServiceProvider.GetRequiredService(); var alertId = Guid.NewGuid(); db.ClinicalAlerts.Add(new ClinicalAlert { Id = alertId, EncounterId = _encounterId, PatientId = _patientId, AlertType = AlertType.SofaSepsis, Severity = AlertSeverity.Critical, Details = "SOFA delta +2", Status = AlertStatus.Open, TriggeredAt = DateTimeOffset.UtcNow }); await db.SaveChangesAsync(); await handler.OnSepsisAlertCreatedAsync( _encounterId, alertId, AlertType.SofaSepsis, CancellationToken.None); var bundle = await db.SepsisBundles.SingleAsync(); bundle.DeadlineAt = DateTimeOffset.UtcNow.AddHours(-1); await db.SaveChangesAsync(); var monitor = new SepsisBundleMonitorService( _fixture.Services, _fixture.Services.GetRequiredService(), _fixture.Services.GetRequiredService>()); await monitor.ScanOverdueBundlesAsync(CancellationToken.None); var updated = await db.SepsisBundles.AsNoTracking().SingleAsync(); updated.ComplianceStatus.Should().Be(SepsisBundleComplianceStatus.NonCompliant); } [Fact] public async Task QsofaScreen_IncludesLabRecommendation() { using var scope = _fixture.Services.CreateScope(); var detector = scope.ServiceProvider.GetRequiredService(); var db = scope.ServiceProvider.GetRequiredService(); await detector.ProcessObservationAsync(_encounterId, _patientId, "RESP_RATE", 24m); await detector.ProcessObservationAsync(_encounterId, _patientId, "SYSTOLIC_BP", 95m); var alert = await db.ClinicalAlerts.SingleAsync(); alert.Details.Should().Contain("order SOFA labs"); } }