267 lines
11 KiB
C#
267 lines
11 KiB
C#
using System.Security.Claims;
|
|
using adas_core.Application.Repositories.Interfaces;
|
|
using adas_core.Application.Services;
|
|
using adas_core.Application.Services.Interfaces;
|
|
using adas_core.Domain.Enums;
|
|
using adas_core.Domain.Models;
|
|
using adas_core.Domain.Models.AppSettings;
|
|
using adas_core.Domain.Models.MongoModels;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Logging;
|
|
using MongoDB.Bson;
|
|
using Moq;
|
|
using Options = Microsoft.Extensions.Options.Options;
|
|
|
|
namespace adas_core.Test.Services;
|
|
|
|
/// <summary>
|
|
/// Contains unit tests for verifying the behavior and functionality of the <see cref="AlarmService"/> class.
|
|
/// </summary>
|
|
public class AlarmServiceTest
|
|
{
|
|
private readonly Mock<IAlarmRepository> _alarmRepositoryMock;
|
|
private readonly AlarmService _alarmService;
|
|
|
|
|
|
private readonly ApiSettings _apiSettings = new()
|
|
{
|
|
ConfigObservation = new ConfigObservationSettings
|
|
{
|
|
IgnoreUnknownObservation = false
|
|
},
|
|
IntravenousLinesCode = ["10546003"],
|
|
AllergiesCode = ["473011001"],
|
|
DrainageCode = ["56868008"],
|
|
IsolationCode = ["302147001"],
|
|
PositionCode = ["386053000"]
|
|
};
|
|
|
|
private readonly Mock<ICalculatedObservationsService> _calculatedObservationsServiceMock;
|
|
private readonly Mock<IConfigObservationService> _configObservationServiceMock;
|
|
private readonly Mock<IObservationService> _observationServiceMock;
|
|
private readonly Mock<IPatientService> _patientServiceMock;
|
|
|
|
private readonly RecordingSettings _recordingSettings = new();
|
|
private readonly Mock<IUnitService> _unitServiceMock;
|
|
|
|
public AlarmServiceTest()
|
|
{
|
|
var optionsApiSettings = Options.Create(_apiSettings);
|
|
Options.Create(_recordingSettings);
|
|
|
|
_observationServiceMock = new Mock<IObservationService>();
|
|
var observationServiceMockLazy = new Lazy<IObservationService>(() => _observationServiceMock.Object);
|
|
|
|
_patientServiceMock = new Mock<IPatientService>();
|
|
_configObservationServiceMock = new Mock<IConfigObservationService>();
|
|
_unitServiceMock = new Mock<IUnitService>();
|
|
var pocServiceMock = new Mock<IPointOfCareService>();
|
|
|
|
var beaconServiceMock = new Mock<ILightBeaconService>();
|
|
var beaconServiceMockLazy = new Lazy<ILightBeaconService>(() => beaconServiceMock.Object);
|
|
|
|
var relayServiceMock = new Mock<IRelayService>();
|
|
var relayServiceMockLazy = new Lazy<IRelayService>(() => relayServiceMock.Object);
|
|
|
|
var recordingServiceMock = new Mock<IRecordingService>();
|
|
var recordingServiceMockLazy = new Lazy<IRecordingService>(() => recordingServiceMock.Object);
|
|
|
|
var clientMessageServiceMock = new Mock<IClientMessageService>();
|
|
|
|
var subscribersServiceMock = new Mock<ISubscribersService>();
|
|
|
|
var httpContextAccessorMock = new Mock<IHttpContextAccessor>();
|
|
var auditServiceMock = new Mock<ILocalAuditService>();
|
|
|
|
_calculatedObservationsServiceMock = new Mock<ICalculatedObservationsService>();
|
|
var calculatedObservationsServiceLazy =
|
|
new Lazy<ICalculatedObservationsService>(() => _calculatedObservationsServiceMock.Object);
|
|
|
|
|
|
var logger = new Mock<ILogger<AlarmService>>();
|
|
|
|
_alarmRepositoryMock = new Mock<IAlarmRepository>();
|
|
var userClaims = new ClaimsPrincipal(new ClaimsIdentity([
|
|
new Claim(ClaimTypes.Name, "TestUser")
|
|
], "mock"));
|
|
|
|
var httpContextMock = new DefaultHttpContext
|
|
{
|
|
User = userClaims
|
|
};
|
|
|
|
httpContextAccessorMock.Setup(accessor => accessor.HttpContext)
|
|
.Returns(httpContextMock);
|
|
_alarmService = new AlarmService(
|
|
_alarmRepositoryMock.Object,
|
|
logger.Object,
|
|
_patientServiceMock.Object,
|
|
_configObservationServiceMock.Object,
|
|
observationServiceMockLazy,
|
|
clientMessageServiceMock.Object,
|
|
subscribersServiceMock.Object,
|
|
calculatedObservationsServiceLazy,
|
|
beaconServiceMockLazy,
|
|
recordingServiceMockLazy,
|
|
relayServiceMockLazy,
|
|
optionsApiSettings,
|
|
_unitServiceMock.Object,
|
|
pocServiceMock.Object,
|
|
httpContextAccessorMock.Object,
|
|
auditServiceMock.Object,
|
|
false // Disable the timer for testing
|
|
);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Verifies that when an ORU_R40 type request is processed without any alarms, the patient is located but the observation is not persisted.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task SaveRequest_Oru_R40_Type_Without_Alarms_Dont_Insert()
|
|
{
|
|
// Arrange
|
|
var apiRequest = new ApiRequest
|
|
{
|
|
Type = "ORU_R40",
|
|
PatientNumber = "12345",
|
|
Observation = new PatientObservation { Value = "Test" },
|
|
Alarms = [],
|
|
Location = new PatientLocation { Bed = "Bed1", Room = "Bed1", UnitName = "Unit1" }
|
|
};
|
|
var unit = new Unit { Configuration = new UnitConfiguration { AutoAdt = true } };
|
|
var patient = new Patient { Id = ObjectId.GenerateNewId(), Bed = "Bed1" };
|
|
_unitServiceMock.Setup(u => u.FindByUnitNameOrPocName(It.IsAny<string>(), It.IsAny<string>()))
|
|
.ReturnsAsync(unit);
|
|
_patientServiceMock.Setup(p => p.FindPatientByApiRequest(apiRequest)).ReturnsAsync(patient);
|
|
_observationServiceMock.Setup(o => o.SaveRequestAsync(It.IsAny<ApiRequest>())).Returns(Task.CompletedTask);
|
|
|
|
// Act
|
|
await _alarmService.SaveRequest(apiRequest);
|
|
|
|
// Assert
|
|
_patientServiceMock.Verify(p => p.FindPatientByApiRequest(apiRequest), Times.Once);
|
|
_observationServiceMock.Verify(o => o.SaveRequestAsync(It.IsAny<ApiRequest>()), Times.Never);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that <see cref="AlarmService.ProcessAlarmObservations"/> inserts the provided alarm observations into the alarm repository.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task ProcessAlarmObservations_Should_Insert_Alarm_Observations()
|
|
{
|
|
// Arrange
|
|
var patient = new Patient { Id = ObjectId.GenerateNewId(), Bed = "Bed1" };
|
|
var alarmObservations = new List<PatientObservationAlarm>
|
|
{
|
|
new() { Value = "Alarm1", Time = DateTime.UtcNow}
|
|
};
|
|
var observations = new List<PatientObservation>
|
|
{
|
|
new() { Value = "Alarm1", Time = DateTime.MinValue}
|
|
};
|
|
|
|
_configObservationServiceMock.Setup(o => o.Map(It.IsAny<PatientObservationAlarm>(), It.IsAny<bool>()))
|
|
.ReturnsAsync((PatientObservationAlarm obs, bool _) => obs); // Correct setup
|
|
|
|
_calculatedObservationsServiceMock.Setup(o => o.Map(It.IsAny<PatientObservationAlarm>(), It.IsAny<bool>()))
|
|
.ReturnsAsync((PatientObservationAlarm obs, bool _) => obs); // Correct setup
|
|
|
|
// Act
|
|
await _alarmService.ProcessAlarmObservations(alarmObservations, observations, patient, DateTime.UtcNow);
|
|
|
|
// Assert
|
|
_alarmRepositoryMock.Verify(a => a.InsertOneAsync(It.IsAny<PatientObservationAlarm>()), Times.Once);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that when checking observation alarms for a patient observation with an "Event_PEEP_Low" configuration
|
|
/// (coding system "ADAS_EVENT", description "EVT_LO and EVT_EXTR_LO"), the alarm service does not insert a new observation,
|
|
/// as indicated by the verification that <c>InsertObservation</c> is never invoked.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task CheckObservationAlarm_Alarm_EventPEEP_PEEP_bajo_create_Event()
|
|
{
|
|
var obs = new PatientObservation();
|
|
|
|
var configs = new ConfigObservation
|
|
{
|
|
Id = ObjectId.GenerateNewId(),
|
|
Name = "Event_PEEP_Low",
|
|
CodingSystem = "ADAS_EVENT",
|
|
Description = "EVT_LO and EVT_EXTR_LO"
|
|
};
|
|
|
|
_configObservationServiceMock.Setup(c => c.Get(It.IsAny<PatientObservation>(), false))
|
|
.ReturnsAsync(configs);
|
|
|
|
await _alarmService.CheckObservationAlarm(obs);
|
|
|
|
|
|
_observationServiceMock.Verify(o => o.InsertObservation(obs, true, true), Times.Never);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that <see cref="AlarmService.CheckObservationAlarm"/> processes a patient observation
|
|
/// matching a configured rule (name "EVT_LO" with required value "PEEP") by inserting a new
|
|
/// observation with the original value preserved (e.g., "PEEP High") while the alarm
|
|
/// configuration handles the red beacon signaling.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task CheckObservationAlarm_Should_Launch_Red_Alarm_And_Set_BeaconColor_Red()
|
|
{
|
|
var alarmConfig = new AlarmConfig
|
|
{
|
|
Enabled = true,
|
|
Priority = 10,
|
|
Beacon = new AlarmItem
|
|
{
|
|
Enabled = true,
|
|
BeaconColor = AlarmEnum.BeaconColor.Red, // Using the enum value
|
|
EndAfter = 60 // Assuming the alarm should end after 60 seconds
|
|
}
|
|
};
|
|
|
|
var configs = new ConfigObservation
|
|
{
|
|
Id = ObjectId.GenerateNewId(),
|
|
Name = "Event_PEEP_Low",
|
|
CodingSystem = "ADAS_EVENT",
|
|
Description = "logs an event. No generate an alarm.",
|
|
Alarm = alarmConfig,
|
|
RequiredValue = "PEEP"
|
|
};
|
|
|
|
var obsConfig = new ConfigObservation
|
|
{
|
|
Id = ObjectId.GenerateNewId(),
|
|
Name = "EVT_LO",
|
|
CheckObservations = true,
|
|
CreateObservation = [configs]
|
|
};
|
|
var patId = ObjectId.GenerateNewId();
|
|
// Arrange
|
|
var obs = new PatientObservation
|
|
{
|
|
Id = ObjectId.GenerateNewId(),
|
|
Name = "EVT_LO",
|
|
PatientId = patId,
|
|
Value = "PEEP High",
|
|
Time = DateTime.UtcNow,
|
|
CheckObservations = true,
|
|
CreateObservation = [configs]
|
|
};
|
|
|
|
_configObservationServiceMock.Setup(c => c.Get(It.IsAny<PatientObservation>(), false))
|
|
.ReturnsAsync(obsConfig);
|
|
|
|
|
|
// Act
|
|
await _alarmService.CheckObservationAlarm(obs);
|
|
|
|
_observationServiceMock.Verify(
|
|
o => o.InsertObservation(
|
|
It.Is<PatientObservation>(ob => ob.Value.ToString() == "PEEP High"), true, true),
|
|
Times.Once);
|
|
}
|
|
} |