feature: Ward Gateway Service (Local-First Clinical Path)
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
using System.Net;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text.Json;
|
||||
using FluentAssertions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
[Collection("GatewayIntegration")]
|
||||
public class WardGatewayLocalPathTests : IAsyncLifetime
|
||||
{
|
||||
private readonly GatewayApiFixture _fixture;
|
||||
private readonly HttpClient _client;
|
||||
private Guid _encounterId;
|
||||
|
||||
public WardGatewayLocalPathTests(GatewayApiFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
_client = fixture.CreateClient();
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
(_, _encounterId) = await GatewayTestSeeder.SeedActiveEncounterAsync(_fixture.Services);
|
||||
}
|
||||
|
||||
public Task DisposeAsync() => Task.CompletedTask;
|
||||
|
||||
[Fact]
|
||||
public async Task CriticalObservation_CreatesAlertLocally()
|
||||
{
|
||||
var resp = await _client.PostAsJsonAsync(
|
||||
$"/api/v1/encounters/{_encounterId}/observations",
|
||||
new
|
||||
{
|
||||
observationCode = "HEART_RATE",
|
||||
value = 160,
|
||||
unit = "bpm",
|
||||
source = "DEVICE",
|
||||
recordedAt = DateTimeOffset.UtcNow,
|
||||
idempotencyKey = Guid.NewGuid().ToString()
|
||||
});
|
||||
|
||||
resp.StatusCode.Should().Be(HttpStatusCode.Created);
|
||||
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
|
||||
(await db.ClinicalAlerts.CountAsync()).Should().BeGreaterThan(0);
|
||||
(await db.BufferedSyncItems.CountAsync(b => !b.Synced)).Should().BeGreaterThan(0);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DuplicateIdempotencyKey_ReturnsExisting()
|
||||
{
|
||||
var key = Guid.NewGuid().ToString();
|
||||
var body = new
|
||||
{
|
||||
observationCode = "HEART_RATE",
|
||||
value = 80,
|
||||
unit = "bpm",
|
||||
source = "DEVICE",
|
||||
recordedAt = DateTimeOffset.UtcNow,
|
||||
idempotencyKey = key
|
||||
};
|
||||
await _client.PostAsJsonAsync($"/api/v1/encounters/{_encounterId}/observations", body);
|
||||
var dup = await _client.PostAsJsonAsync($"/api/v1/encounters/{_encounterId}/observations", body);
|
||||
dup.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
var json = await dup.Content.ReadFromJsonAsync<JsonDocument>();
|
||||
json!.RootElement.GetProperty("data").GetProperty("duplicate").GetBoolean().Should().BeTrue();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Acknowledge_WritesBufferedAck()
|
||||
{
|
||||
await _client.PostAsJsonAsync(
|
||||
$"/api/v1/encounters/{_encounterId}/observations",
|
||||
new
|
||||
{
|
||||
observationCode = "HEART_RATE",
|
||||
value = 160,
|
||||
unit = "bpm",
|
||||
source = "DEVICE",
|
||||
recordedAt = DateTimeOffset.UtcNow,
|
||||
idempotencyKey = Guid.NewGuid().ToString()
|
||||
});
|
||||
|
||||
var alertsResp = await _client.GetAsync($"/api/v1/encounters/{_encounterId}/alerts");
|
||||
alertsResp.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
var alertsDoc = await alertsResp.Content.ReadFromJsonAsync<JsonDocument>();
|
||||
var alertId = alertsDoc!.RootElement
|
||||
.GetProperty("data").GetProperty("items")[0].GetProperty("id").GetGuid();
|
||||
|
||||
var ackResp = await _client.PostAsJsonAsync(
|
||||
$"/api/v1/alerts/{alertId}/acknowledge",
|
||||
new AcknowledgeAlertRequest("Reviewing at bedside."));
|
||||
ackResp.StatusCode.Should().Be(HttpStatusCode.OK);
|
||||
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
|
||||
(await db.BufferedSyncItems.CountAsync(b =>
|
||||
b.ItemType == BufferedSyncItemType.Ack && !b.Synced)).Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CentralDown_ReachabilityReportsDegraded()
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(2));
|
||||
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var reachability = scope.ServiceProvider.GetRequiredService<CentralReachabilityService>();
|
||||
reachability.IsCentralReachable.Should().BeFalse();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WarningObservation_CreatesWarningNoPage()
|
||||
{
|
||||
var resp = await _client.PostAsJsonAsync(
|
||||
$"/api/v1/encounters/{_encounterId}/observations",
|
||||
new
|
||||
{
|
||||
observationCode = "HEART_RATE",
|
||||
value = 105,
|
||||
unit = "bpm",
|
||||
source = "DEVICE",
|
||||
recordedAt = DateTimeOffset.UtcNow,
|
||||
idempotencyKey = Guid.NewGuid().ToString()
|
||||
});
|
||||
|
||||
resp.StatusCode.Should().Be(HttpStatusCode.Created);
|
||||
|
||||
using var scope = _fixture.Services.CreateScope();
|
||||
var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
|
||||
var alert = await db.ClinicalAlerts.SingleAsync();
|
||||
alert.Severity.Should().Be(AlertSeverity.Warning);
|
||||
alert.AlertType.Should().Be(AlertType.WarningHeartRate);
|
||||
alert.Status.Should().Be(AlertStatus.Open);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user