Files
adas-core/adas-core.Test/Services/SchedulerServiceTest.cs
T

590 lines
22 KiB
C#

using System.Collections.Specialized;
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 adas_core.Domain.Models.Providers;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using Moq;
using Quartz;
using Quartz.Impl;
using Options = Microsoft.Extensions.Options.Options;
namespace adas_core.Test.Services;
[TestFixture]
public class SchedulerServiceTest
{
[OneTimeSetUp]
public async Task SetUp()
{
#region [Services Mock seUp]
_treatmentServiceMock = new Mock<ITreatmentService>();
_treatmentServiceLazy = new Lazy<ITreatmentService>(() => _treatmentServiceMock.Object);
_patientServiceMock = new Mock<IPatientService>();
_patientServiceLazy = new Lazy<IPatientService>(() => _patientServiceMock.Object);
_medicineServiceMock = new Mock<IMedicineService>();
_medicineServiceLazy = new Lazy<IMedicineService>(() => _medicineServiceMock.Object);
_observationServiceMock = new Mock<IObservationService>();
_observationServiceLazy = new Lazy<IObservationService>(() => _observationServiceMock.Object);
_configObservationServiceMock = new Mock<IConfigObservationService>();
var configObservationServiceLazy =
new Lazy<IConfigObservationService>(() => _configObservationServiceMock.Object);
_logger = new Mock<ILogger<SchedulerService>>();
_httpClientFactoryMock = new Mock<IHttpClientFactory>();
_httpMessageHandlerMock = new Mock<HttpMessageHandler>();
_calculatedObservationsServiceMock = new Mock<ICalculatedObservationsService>();
_calculatedObservationsServiceLazy =
new Lazy<ICalculatedObservationsService>(() => _calculatedObservationsServiceMock.Object);
_appointmentServiceServiceMock = new Mock<IAppointmentService>();
_appointmentServiceServiceLazy =
new Lazy<IAppointmentService>(() => _appointmentServiceServiceMock.Object);
_diagnosisServiceMock = new Mock<IDiagnosisService>();
_diagnosisServiceLazy =
new Lazy<IDiagnosisService>(() => _diagnosisServiceMock.Object);
var client = new HttpClient(_httpMessageHandlerMock.Object);
_httpClientFactoryMock.Setup(c => c.CreateClient(It.IsAny<string>())).Returns(client);
_optionsApiSettings = Options.Create(_apiSettings);
_optionsProvidersSettings = Options.Create(_providersSettings);
#endregion
var unused = new SchedulerService(
_optionsApiSettings,
_optionsProvidersSettings,
_patientServiceLazy,
_treatmentServiceLazy,
_appointmentServiceServiceLazy,
_diagnosisServiceLazy,
_medicineServiceLazy,
_observationServiceLazy,
configObservationServiceLazy,
_logger.Object,
_httpClientFactoryMock.Object,
_calculatedObservationsServiceLazy,
_patientCarePlanLazy
);
#region [Service item fill]
_sinceDate = Now.AddHours(-24);
_sinceDischargeTimeToArchive = 48;
_archivePatientsWithoutObservationsSinceHours = 28;
_jobDataMap = new JobDataMap
{
{ "sinceDate", _sinceDate },
{ "sinceDischargeTime", _sinceDischargeTimeToArchive },
{ "archivePatientsWithoutObservationsSinceHours", _archivePatientsWithoutObservationsSinceHours },
{ "checkNewsJobIntervalMinutes", 15 }
};
// Grab the Scheduler instance from the Factory
var properties = new NameValueCollection
{
{ "quartz.scheduler.instanceName", "MyUniqueSchedulerName" }
};
_factory = new StdSchedulerFactory(properties);
if (_scheduler == null)
{
var getFactory = await _factory.GetScheduler();
_scheduler = getFactory;
}
// Set up observation list
var itemList = new List<ConfigObservation>
{
new()
{
Name = "Resp_Rate_Calculated",
CodingSystem = "ADAS",
MinAlert = 14,
MaxAlert = 25,
Expires = 10,
ShowOnExpired = false
},
new()
{
Name = "SpO2",
Code = "150456",
OriginalName = "MDC_PULS_OXIM_SAT_O2",
CodingSystem = "MDC",
ParentCode = "69965",
ParentName = "MDC_DEV_MON_PHYSIO_MULTI_PARAM_MDS",
MinAlert = 94,
MaxAlert = 100,
ParentCodingSystem = "MDC",
Expires = 10,
ShowOnExpired = false
},
new()
{
Name = "Temperature",
Code = "386053000",
OriginalName = "Temperatura",
CodingSystem = "SNM",
ParentCode = "386053000",
ParentName = "Temperatura(ºC)",
MinAlert = 34.5,
MinWarn = 35.5,
MaxWarn = 37.4,
MaxAlert = 38,
ParentCodingSystem = "SNM",
Expires = 60
},
new()
{
CodingSystem = "MDC",
Code = "150033",
OriginalName = "MDC_PRESS_BLD_ART_SYS",
Name = "TAs",
Expires = 10
},
new()
{
Name = "FC",
Code = "149514",
OriginalName = "MDC_PULS_RATE",
CodingSystem = "MDC",
MinAlert = 60,
MaxAlert = 100,
Expires = 10,
ShowOnExpired = false
}
};
var observations = new List<PatientObservation>
{
new()
{
Name = "Resp_Rate_Calculated", Value = 18, Time = DateTime.UtcNow.AddMinutes(-60), PatientId = PatientId
},
new() { Name = "SpO2", Value = 93, Time = DateTime.UtcNow.AddMinutes(-60), PatientId = PatientId },
new() { Name = "Temperature", Value = 36.5, Time = DateTime.UtcNow, PatientId = PatientId },
new() { Name = "TAs", Value = 103, Time = DateTime.UtcNow, PatientId = PatientId },
new() { Name = "FC", Value = 80, Time = DateTime.UtcNow.AddMinutes(-60), PatientId = PatientId },
new()
{
Name = "Resp_Rate_Calculated", Value = 18, Time = DateTime.UtcNow.AddMinutes(-60),
PatientId = PatientId2
},
new() { Name = "SpO2", Value = 93, Time = DateTime.UtcNow.AddMinutes(-60), PatientId = PatientId2 },
new()
{
Name = "Temperature", Value = 36.5, Time = DateTime.UtcNow.AddMinutes(-60), PatientId = PatientId2
},
new() { Name = "TAs", Value = 103, Time = DateTime.UtcNow, PatientId = PatientId2 },
new() { Name = "FC", Value = 40, Time = DateTime.UtcNow, PatientId = PatientId2 }
};
// Set Up patientList
var patientList = new List<Patient>
{
new()
{
Id = PatientId,
UnitId = ObjectId.GenerateNewId(),
PointOfCareId = ObjectId.GenerateNewId(),
PatientNumber = "patientNumber1",
Person = new Person
{
FirstName = "firstName1",
LastName = "lastName1",
BirthDate = new DateTime(),
Gender = PatientEnum.Gender.Male
}
},
new()
{
Id = PatientId2,
UnitId = ObjectId.GenerateNewId(),
PointOfCareId = ObjectId.GenerateNewId(),
PatientNumber = "patientNumber2",
Person = new Person
{
FirstName = "firstName2",
LastName = "lastName2",
BirthDate = new DateTime(),
Gender = PatientEnum.Gender.Male
}
}
};
#endregion
#region [Service behavior]
// Set up configObservationServiceMock to return desire item
_configObservationServiceMock
.Setup(service => service.Get(It.IsAny<BasePatientObservation>(), It.IsAny<bool>()))
.ReturnsAsync((BasePatientObservation obs, bool _) =>
{
return itemList.FirstOrDefault(obsConfig => obsConfig.Name == obs.Name);
});
// Set up observationService behavior
_observationServiceMock
.Setup(service => service.FindLastObservations(It.IsAny<ObjectId>(), 1, It.IsAny<List<string>>()))
.ReturnsAsync((ObjectId patientId, int _, List<string>? filterObservations) =>
{
var filteredObservations = observations
.Where(obs =>
filterObservations != null && obs.Name != null && filterObservations.Contains(obs.Name) &&
obs.PatientId == patientId)
.ToList();
return filteredObservations;
});
// Set up patientServiceMock to return patientList for FindInActivePoC
_patientServiceMock.Setup(service => service.FindInActivePoC()).ReturnsAsync(patientList);
#endregion
// Asignación de dependencias estáticas para el job
CalculateNewsJob.PatientService = _patientServiceMock.Object;
CalculateNewsJob.ObservationService = _observationServiceMock.Object;
CheckExpiredAlertsJob.ObservationService = _observationServiceMock.Object;
CheckExpiredObservationsJob.ObservationService = _observationServiceMock.Object;
CalculateNewsJob.ConfigObservationService = _configObservationServiceMock.Object;
// and start it off
_scheduler?.Start();
}
//[TearDown]
[OneTimeTearDown]
public void TearDown()
{
// Detener el motor de Quartz.NET después de las pruebas
//scheduler.Shutdown().Wait();
_scheduler?.Shutdown();
}
private Mock<ITreatmentService>? _treatmentServiceMock;
private Mock<IPatientService>? _patientServiceMock;
private Mock<IMedicineService>? _medicineServiceMock;
private Mock<IObservationService>? _observationServiceMock;
private Mock<IConfigObservationService>? _configObservationServiceMock;
private Mock<IHttpClientFactory>? _httpClientFactoryMock;
private Mock<HttpMessageHandler>? _httpMessageHandlerMock;
private Mock<ICalculatedObservationsService>? _calculatedObservationsServiceMock;
private Mock<IAppointmentService>? _appointmentServiceServiceMock;
private Mock<IDiagnosisService>? _diagnosisServiceMock;
private Lazy<ITreatmentService>? _treatmentServiceLazy;
private Lazy<IPatientService>? _patientServiceLazy;
private Lazy<IMedicineService>? _medicineServiceLazy;
private Lazy<IObservationService>? _observationServiceLazy;
private Lazy<ICalculatedObservationsService> _calculatedObservationsServiceLazy;
private Lazy<IAppointmentService> _appointmentServiceServiceLazy;
private Lazy<IDiagnosisService> _diagnosisServiceLazy;
private readonly Lazy<IPatientCarePlanService> _patientCarePlanLazy = new();
private readonly ApiSettings _apiSettings = new();
private IOptions<ApiSettings>? _optionsApiSettings;
private readonly List<ProvidersSettings> _providersSettings =
[
new()
{
Name = "Adas",
Url = "http://localhost/info.html"
}
];
private IOptions<List<ProvidersSettings>>? _optionsProvidersSettings;
private Mock<ILogger<SchedulerService>>? _logger;
private JobDataMap _jobDataMap = new();
private DateTime _sinceDate;
private int _sinceDischargeTimeToArchive;
private int _archivePatientsWithoutObservationsSinceHours;
private StdSchedulerFactory? _factory;
private IScheduler? _scheduler;
private static readonly DateTime Now = DateTime.Now;
private static readonly ObjectId PatientId = ObjectId.GenerateNewId();
private static readonly ObjectId PatientId2 = ObjectId.GenerateNewId();
[Test]
public void CheckInactivePatientsJob_ShouldExecuteOnTrigger()
{
var checkInactivePatientSchedulerIntervalHours = 12;
// Arrange
var checkInactivePatientsJob = JobBuilder.Create<CheckInactivePatientsJob>()
.UsingJobData(_jobDataMap)
.Build();
// Crear un disparador personalizado que incremente el contador
var checkInactivePatientsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInHours(checkInactivePatientSchedulerIntervalHours)
.RepeatForever())
.Build();
_patientServiceMock?.Setup(p => p.DischargeInactivePatients(_sinceDate, _sinceDischargeTimeToArchive));
// Asociar el trabajo y el desencadenador en el motor de Quartz.NET
_scheduler?.ScheduleJob(checkInactivePatientsJob, checkInactivePatientsTrigger).Wait();
// Act
// Esperar un tiempo suficiente para que el trabajo se ejecute varias veces
Thread.Sleep(TimeSpan.FromSeconds(1));
_patientServiceMock?.Verify(p => p.DischargeInactivePatients(It.IsAny<DateTime>(), It.IsAny<int>()),
Times.AtLeastOnce());
}
[Test]
public void CheckActiveTreatmentsJob_ShouldExecuteOnTrigger()
{
var patient = new Patient
{
PatientId = PatientId.ToString(),
UnitString = "NEONATAL",
Bed = "CINA02",
PatientNumber = "123456",
Person = new Person
{
FirstName = "Jose",
LastName = "Luis",
BirthDate = new DateTime(),
Gender = PatientEnum.Gender.Male
}
};
const int checkActiveTreatmentsSchedulerIntervalMinutes = 10;
var treatmentsJob = JobBuilder.Create<CheckActiveTreatmentsJob>()
.Build();
// Trigger the job to run now, and then repeat every 10 seconds
var treatmentsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInMinutes(checkActiveTreatmentsSchedulerIntervalMinutes)
.RepeatForever())
.Build();
_patientServiceMock?.Setup(p => p.FindAll(It.IsAny<bool>())).ReturnsAsync([patient]);
// Create a mock of the singleton class subscribers
var mockSingleton = new Mock<ICalculatedObservationsService>();
// Set up the mock object to return a specific value when a method is called
var patientTreatmentList = new List<PatientTreatment?>
{
new()
{
Id = ObjectId.GenerateNewId(),
PatientId = PatientId,
OrderControl = OrderControlType.Nw,
PlacerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
FillerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
OrderStatus = "A",
OrderTime = Now,
Notes = [],
Routes = []
}
};
mockSingleton.Setup(x => x.GetActiveTreatmentsByPatient(PatientId)).ReturnsAsync(patientTreatmentList);
_medicineServiceMock?.Setup(m => m.GetMedicinesOfTreatments(It.IsAny<List<PatientTreatment>>()))
.ReturnsAsync(new List<Medicine>());
// Asociar el trabajo y el desencadenador en el motor de Quartz.NET
_scheduler?.ScheduleJob(treatmentsJob, treatmentsTrigger).Wait();
// Act
// Esperar un tiempo suficiente para que el trabajo se ejecute varias veces
Thread.Sleep(TimeSpan.FromSeconds(10));
_medicineServiceMock?.Verify(x => x.GetMedicinesOfTreatments(It.IsAny<IEnumerable<PatientTreatment>>()),
Times.Once());
}
[Test]
public void CheckExpiredObservationsJob_ShouldExecuteOnTrigger()
{
var checkExpiredObservationsIntervalMinutes = 3;
// Arrange
var checkExpiredObservationsJob = JobBuilder.Create<CheckExpiredObservationsJob>()
.UsingJobData(_jobDataMap)
.Build();
// Crear un disparador personalizado que incremente el contador
var checkExpiredObservationsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInHours(checkExpiredObservationsIntervalMinutes)
.RepeatForever())
.Build();
// Asociar el trabajo y el desencadenador en el motor de Quartz.NET
_scheduler?.ScheduleJob(checkExpiredObservationsJob, checkExpiredObservationsTrigger).Wait();
// Act
// Esperar un tiempo suficiente para que el trabajo se ejecute varias veces
Thread.Sleep(TimeSpan.FromSeconds(1));
_observationServiceMock?.Verify(p => p.ExpireObservationsAndRecalculateAsync(), Times.AtLeastOnce());
}
[Test]
public void CheckExpiredAlertsJob_ShouldExecuteOnTrigger()
{
var checkExpiredAlertsIntervalMinutes = 3;
// Arrange
var checkExpiredAlertsJob = JobBuilder.Create<CheckExpiredAlertsJob>()
.UsingJobData(_jobDataMap)
.Build();
// Crear un disparador personalizado que incremente el contador
var checkExpiredAlertsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInHours(checkExpiredAlertsIntervalMinutes)
.RepeatForever())
.Build();
// Asociar el trabajo y el desencadenador en el motor de Quartz.NET
_scheduler?.ScheduleJob(checkExpiredAlertsJob, checkExpiredAlertsTrigger).Wait();
// Act
// Esperar un tiempo suficiente para que el trabajo se ejecute varias veces
Thread.Sleep(TimeSpan.FromSeconds(1));
_observationServiceMock?.Verify(p => p.ExpireAlertsAndPowerOffAsync(), Times.AtLeastOnce());
}
[Test]
public void GetProvidersObservationsJob_ShouldExecuteOnTrigger_Result_GetType_null()
{
var getProviderObservationsIntervalMinutes = 5;
var patient = new Patient
{
PatientId = PatientId.ToString(),
UnitString = "NEONATAL",
Bed = "CINA02",
PatientNumber = "123456",
Person = new Person
{
FirstName = "Jose",
LastName = "Luis",
BirthDate = new DateTime(),
Gender = PatientEnum.Gender.Male
}
};
// Arrange
var getProvidersObservationsJob = JobBuilder.Create<GetProvidersObservationsJob>()
.UsingJobData(_jobDataMap)
.Build();
// Crear un disparador personalizado que incremente el contador
var getProvidersObservationsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInHours(getProviderObservationsIntervalMinutes)
.RepeatForever())
.Build();
_patientServiceMock?.Setup(p => p.FindAll(It.IsAny<bool>())).ReturnsAsync([patient]);
// Asociar el trabajo y el desencadenador en el motor de Quartz.NET
_scheduler?.ScheduleJob(getProvidersObservationsJob, getProvidersObservationsTrigger).Wait();
// Act
// Esperar un tiempo suficiente para que el trabajo se ejecute varias veces
Thread.Sleep(TimeSpan.FromSeconds(1));
//observationServiceMock.Verify(p => p.InsertObservation(It.IsAny<PatientObservation>(),true,true), Times.AtLeastOnce());
_observationServiceMock?.Verify(p => p.InsertObservation(
It.Is<PatientObservation>(obs => obs.Name != "NEWS"), true, true), Times.Never());
}
[Test]
public void CheckCalculateNewsJob_ShouldExecuteOnTrigger()
{
var checkExpiredAlertsIntervalMinutes = 3;
// Arrange
var calculateNewsJob = JobBuilder.Create<CalculateNewsJob>()
.UsingJobData(_jobDataMap)
.Build();
// Crear un disparador personalizado que incremente el contador
var checkExpiredAlertsTrigger = TriggerBuilder.Create()
.StartNow()
.WithSimpleSchedule(x => x
.WithIntervalInHours(checkExpiredAlertsIntervalMinutes)
.RepeatForever())
.Build();
// Asociar el trabajo y el desencadenador en el motor de Quartz.NET
_scheduler?.ScheduleJob(calculateNewsJob, checkExpiredAlertsTrigger).Wait();
// Act
// Esperar un tiempo suficiente para que el trabajo se ejecute varias veces
Thread.Sleep(TimeSpan.FromSeconds(6));
_observationServiceMock?.Verify(p => p.InsertObservation(It.IsAny<PatientObservation>(), true, true),
Times.AtLeastOnce());
}
[Test]
public async Task CalculateNewsJob_Insert_ObsFull_MultiplePatient_With_Correct_Value()
{
var job = new CalculateNewsJob();
// Act
await job.Execute(Mock.Of<IJobExecutionContext>());
// Assert
_observationServiceMock?.Verify(
service => service.InsertObservation(
It.Is<PatientObservation>(obs =>
obs.Name == "NEWS" && (int)obs.Value == 1 && obs.PatientId == PatientId),
true, true),
Times.Once);
_observationServiceMock?.Verify(
service => service.InsertObservation(
It.Is<PatientObservation>(obs =>
obs.Name == "NEWS" && (int)obs.Value == 4 && obs.PatientId == PatientId2),
true, true),
Times.Once);
}
//Se deshabilita el mensaje de warning porque lo detecta como no usado y sugiere suprimirlo siendo necesario
}