feature: Simulator Scenarios + Clinical Validation: SOFA/GCS
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StackExchange.Redis;
|
||||
|
||||
[Collection("Integration")]
|
||||
public class ClinicalRefactorEndToEndTests : IAsyncLifetime
|
||||
{
|
||||
private readonly ApiFixture _fixture;
|
||||
private readonly HttpClient _client;
|
||||
|
||||
public ClinicalRefactorEndToEndTests(ApiFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_client = fixture.CreateClient();
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
await DbResetHelper.ResetAsync(db);
|
||||
|
||||
var redis = scope.ServiceProvider.GetRequiredService<IConnectionMultiplexer>();
|
||||
await DataSeeder.SeedThresholdsOnlyAsync(db, redis);
|
||||
}
|
||||
|
||||
public Task DisposeAsync() => Task.CompletedTask;
|
||||
|
||||
[Fact]
|
||||
public async Task SofaProgressionScenario_EndToEnd()
|
||||
{
|
||||
var scenario = ScenarioReplayHelper.Load("sepsis-sofa-progression-01.json");
|
||||
var (_, encounterId) = await ScenarioReplayHelper.ReplayObservationsAsync(_client, scenario);
|
||||
|
||||
await ScenarioReplayHelper.WaitForAlertTypeAsync(
|
||||
_fixture.Services, encounterId, AlertType.QsofaScreen, TimeSpan.FromSeconds(30));
|
||||
|
||||
await ScenarioReplayHelper.WaitForAlertTypeAsync(
|
||||
_fixture.Services, encounterId, AlertType.SofaSepsis, TimeSpan.FromSeconds(30));
|
||||
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
|
||||
var bundle = await db.SepsisBundles.SingleAsync(b => b.EncounterId == encounterId);
|
||||
bundle.TriggeringAlertType.Should().Be("SOFA_SEPSIS");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GcsDeclineScenario_EndToEnd()
|
||||
{
|
||||
var scenario = ScenarioReplayHelper.Load("neurological-decline-gcs-01.json");
|
||||
var (_, encounterId) = await ScenarioReplayHelper.ReplayObservationsAsync(_client, scenario);
|
||||
|
||||
await ScenarioReplayHelper.WaitForAlertTypeAsync(
|
||||
_fixture.Services, encounterId, AlertType.GcsWarning, TimeSpan.FromSeconds(30));
|
||||
|
||||
await ScenarioReplayHelper.WaitForAlertTypeAsync(
|
||||
_fixture.Services, encounterId, AlertType.GcsCritical, TimeSpan.FromSeconds(30));
|
||||
|
||||
await ScenarioReplayHelper.AssertNoAlertTypeAsync(
|
||||
_fixture.Services, encounterId, AlertType.SofaSepsis, TimeSpan.FromSeconds(5));
|
||||
|
||||
await ScenarioReplayHelper.AssertNoAlertTypeAsync(
|
||||
_fixture.Services, encounterId, AlertTypeExtensions.FromDbString("SEPSIS_WARNING"), TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task PartialSofaScenario_StalenessFlags()
|
||||
{
|
||||
var scenario = ScenarioReplayHelper.Load("sofa-partial-spo2-fallback-01.json");
|
||||
var (_, encounterId) = await ScenarioReplayHelper.ReplayObservationsAsync(_client, scenario);
|
||||
|
||||
var sofa = await ScenarioReplayHelper.WaitForSofaScoreAsync(
|
||||
_fixture.Services, encounterId, TimeSpan.FromSeconds(45));
|
||||
|
||||
sofa.StalenessFlags.Should().NotBeNullOrEmpty();
|
||||
var flags = JsonSerializer.Deserialize<SofaStalenessFlags>(
|
||||
sofa.StalenessFlags!,
|
||||
new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
|
||||
flags!.UsedSpO2Fallback.Should().BeTrue("expected SpO2/FiO2 proxy for respiratory SOFA");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("stable-baseline-01.json")]
|
||||
[InlineData("cardiac-arrest-post-mi-01.json")]
|
||||
[InlineData("post-op-hemorrhage-01.json")]
|
||||
[InlineData("respiratory-failure-asthma-01.json")]
|
||||
[InlineData("dka-electrolyte-01.json")]
|
||||
[InlineData("medication-false-alarm-01.json")]
|
||||
[InlineData("hypothermia-elderly-01.json")]
|
||||
[InlineData("uti-sepsis-elderly-01.json")]
|
||||
public void ExistingScenarios_ValidateWithoutErrors(string fileName)
|
||||
{
|
||||
var scenario = ScenarioReplayHelper.Load(fileName);
|
||||
var errors = ScenarioValidator.Validate(scenario);
|
||||
errors.Should().BeEmpty(string.Join("; ", errors));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UtiSepsisScenario_NowUsesSofa()
|
||||
{
|
||||
var scenario = ScenarioReplayHelper.Load("uti-sepsis-elderly-01.json");
|
||||
var (_, encounterId) = await ScenarioReplayHelper.ReplayObservationsAsync(_client, scenario);
|
||||
|
||||
await ScenarioReplayHelper.WaitForAlertTypeAsync(
|
||||
_fixture.Services, encounterId, AlertType.SofaSepsis, TimeSpan.FromSeconds(45));
|
||||
|
||||
await ScenarioReplayHelper.AssertNoAlertTypeAsync(
|
||||
_fixture.Services, encounterId, AlertTypeExtensions.FromDbString("SEPSIS_WARNING"), TimeSpan.FromSeconds(5));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user