Files
vigilcare-clinical/VigilCare.WardGateway.Tests/WardGatewayLocalPathTests.cs
T
2026-06-24 03:01:00 +08:00

174 lines
6.4 KiB
C#

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 Acknowledge_WithClinicianId_UsesScenarioAttribution()
{
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");
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("Calcium gluconate ordered.", "RN-Wu"));
ackResp.StatusCode.Should().Be(HttpStatusCode.OK);
using var scope = _fixture.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<GatewayDbContext>();
var alert = await db.ClinicalAlerts.SingleAsync(a => a.Id == alertId);
alert.AcknowledgedBy.Should().Be("RN-Wu");
var bufferedAck = await db.BufferedSyncItems.SingleAsync(b =>
b.ItemType == BufferedSyncItemType.Ack && !b.Synced);
bufferedAck.Payload.Should().Contain("RN-Wu");
}
[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);
}
}