using adas_core.Domain.Enums; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.Pumps; using adas_core.Infrastructure.Repositories; using Microsoft.Extensions.Options; using MongoDB.Bson; using MongoDB.Driver; namespace adas_core.Test.Repositories; [TestFixture] [Category("Integration")] public class PumpAlarmEventRepositoryTest { private PumpAlarmEventRepository _repo; private IOptions _apiSettings; private static readonly DateTime Now = DateTime.UtcNow; private const string DeviceA = "Device-A"; private const string DeviceB = "Device-B"; private static readonly ObjectId PatientId = ObjectId.GenerateNewId(); // ------------------------------------------------------------------- // INIT – Setup inicial de colección con índices y datos de prueba // ------------------------------------------------------------------- [OneTimeSetUp] public async Task Init() { _apiSettings = Options.Create(new ApiSettings { PumpAlarmEvent = "pump_alarm_event" }); await IntegrationDb.Database.DropCollectionAsync("pump_alarm_event"); await IntegrationDb.Database.CreateCollectionAsync("pump_alarm_event"); _repo = new PumpAlarmEventRepository( _apiSettings, IntegrationDb.Database ); await _repo.CreateIndexes(); var initialEvents = new List { new() { Id = ObjectId.GenerateNewId(), DeviceId = DeviceA, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Attention, Time = Now.AddSeconds(-1) }, new() { Id = ObjectId.GenerateNewId(), DeviceId = DeviceA, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Occlusion, Time = Now.AddSeconds(-3) }, new() { Id = ObjectId.GenerateNewId(), DeviceId = DeviceB, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Occlusion, Time = Now.AddSeconds(-2) } }; await IntegrationDb.Database .GetCollection("pump_alarm_event") .InsertManyAsync(initialEvents); var count = await _repo.Collection.CountDocumentsAsync(_ => true); Assert.That(count, Is.EqualTo(3)); } // ------------------------------------------------------------------- // INSERT // ------------------------------------------------------------------- [Test] public async Task InsertAsync_Works() { var evt = new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = "Device-C", PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Occlusion, Time = Now }; await _repo.InsertAsync(evt); var found = await _repo.Collection.FindAsync(x => x.Id == evt.Id); Assert.That(found.FirstOrDefault(), Is.Not.Null); } // ------------------------------------------------------------------- // FIND BY DEVICE ID // ------------------------------------------------------------------- [Test] public async Task FindByDeviceIdAsync_ReturnsOrdered() { var result = await _repo.FindByDeviceIdAsync(DeviceA); var list = result.ToList(); using (Assert.EnterMultipleScope()) { Assert.That(list, Is.Not.Empty); Assert.That(list.First().Time, Is.GreaterThanOrEqualTo(list.Last().Time)); } } [Test] public async Task FindByDeviceIdAsync_WithDateRange_Works() { var from = Now.AddSeconds(-2); var to = Now; var result = await _repo.FindByDeviceIdAsync(DeviceA, from, to); using (Assert.EnterMultipleScope()) { var pumpAlarmEvents = result.ToList(); Assert.That(pumpAlarmEvents, Is.Not.Empty); Assert.That(pumpAlarmEvents.All(x => x.Time >= from && x.Time <= to), Is.True); } } [Test] public async Task FindByDeviceIdAsync_WithLimit_Works() { var result = await _repo.FindByDeviceIdAsync(DeviceA, limit: 1); var list = result.ToList(); Assert.That(list, Has.Count.EqualTo(1)); } // ------------------------------------------------------------------- // FIND LAST BY DEVICE // ------------------------------------------------------------------- [Test] public async Task FindLastByDeviceIdAsync_Works() { // Arrange: dataset ya insertado en Init() var events = await _repo.FindByDeviceIdAsync("Device-A"); var expected = events.OrderByDescending(e => e.Time).First(); // Act var evt = await _repo.FindLastByDeviceIdAsync("Device-A"); // Assert Assert.That(evt, Is.Not.Null); Assert.That(evt!.Id, Is.EqualTo(expected.Id)); // comparación robusta } // ------------------------------------------------------------------- // DELETE BY PATIENT ID // ------------------------------------------------------------------- [Test] public async Task DeleteByPatientId_Works() { var patient2 = ObjectId.GenerateNewId(); var evt = new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = "Device-X", PatientId = patient2, AlarmType = PumpEnum.AlarmType.Occlusion, Time = Now }; await _repo.InsertAsync(evt); await _repo.DeleteByPatientId(patient2); var found = await _repo.Collection.FindAsync(x => x.PatientId == patient2); Assert.That(await found.AnyAsync(), Is.False); } // ------------------------------------------------------------------- // UPDATE MANY (CAMBIO DE PATIENTID O SIMILAR) // ------------------------------------------------------------------- [Test] public async Task UpdateManyObjectIdByFiledNameAsync_Works() { var oldId = ObjectId.GenerateNewId(); var newId = ObjectId.GenerateNewId(); var evt = new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = "Device-U", PatientId = oldId, AlarmType = PumpEnum.AlarmType.Attention, Time = Now }; await _repo.InsertAsync(evt); var updated = await _repo.UpdateManyObjectIdByFiledNameAsync("PatientId", newId, oldId); Assert.That(updated, Is.EqualTo(1)); var found = await _repo.Collection.FindAsync(x => x.PatientId == newId); Assert.That(await found.AnyAsync(), Is.True); } [Test] public async Task FindByDeviceIdAsync_ReturnsEmpty_WhenOutOfRange() { var from = Now.AddYears(-2); var to = Now.AddYears(-2).AddDays(1); var result = await _repo.FindByDeviceIdAsync("Device-A", from, to); Assert.That(result, Is.Empty); } [Test] public async Task FindByDeviceIdAsync_RespectsLimitAndOrder() { // Semilla adicional para asegurar > 1 var events = new[] { new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = DeviceA, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.AirInLine, Time = Now.AddMilliseconds(-10) }, new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = DeviceA, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Occlusion, Time = Now.AddMilliseconds(-5) } }; await _repo.Collection.InsertManyAsync(events); var result = await _repo.FindByDeviceIdAsync(DeviceA, limit: 1); var list = result.ToList(); using (Assert.EnterMultipleScope()) { Assert.That(list, Has.Count.EqualTo(1)); var last = await _repo.FindLastByDeviceIdAsync(DeviceA); Assert.That(list[0].Id, Is.EqualTo(last!.Id)); } } [Test] public async Task InsertAsync_AllowsNullOptionalFields() { var evt = new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = "Device-Nulls", PatientId = null, // opcional AlarmType = null, // opcional Time = Now }; await _repo.InsertAsync(evt); var found = await _repo.Collection.FindAsync(x => x.Id == evt.Id); Assert.That(found.FirstOrDefault(), Is.Not.Null); } [Test] public async Task DeleteByPatientId_DeletesMany_AndIsIdempotent() { var pid = ObjectId.GenerateNewId(); var docs = Enumerable.Range(0, 3).Select(i => new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = "Device-Del", PatientId = pid, AlarmType = PumpEnum.AlarmType.Attention, Time = Now.AddSeconds(-i) }); await _repo.Collection.InsertManyAsync(docs); // Primera vez: borra 3 await _repo.DeleteByPatientId(pid); var left = await _repo.Collection.FindAsync(x => x.PatientId == pid); Assert.That(left.ToList(), Is.Empty); Func act = async () => await _repo.DeleteByPatientId(pid); Assert.That(act, Throws.Nothing); } [Test] public async Task UpdateManyObjectIdByFiledNameAsync_UpdatesMultiple() { var oldId = ObjectId.GenerateNewId(); var newId = ObjectId.GenerateNewId(); var events = Enumerable.Range(0, 4).Select(i => new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = "Device-U", PatientId = oldId, AlarmType = PumpEnum.AlarmType.AirInLine, Time = Now.AddMilliseconds(-i) }); await _repo.Collection.InsertManyAsync(events); var modified = await _repo.UpdateManyObjectIdByFiledNameAsync("PatientId", newId, oldId); using (Assert.EnterMultipleScope()) { Assert.That(modified, Is.EqualTo(4)); var foundNew = await _repo.Collection.FindAsync(x => x.PatientId == newId); Assert.That(foundNew.ToList(), Has.Count.EqualTo(4)); } } [Test] public async Task FindByDeviceIdAsync_InclusiveRange_BoundsRespected() { var start = Now.AddMinutes(-30); var end = Now.AddMinutes(-29); var exactEvt = new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = "Device-Range", PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Attention, Time = end // exactamente igual al to }; await _repo.InsertAsync(exactEvt); var result = await _repo.FindByDeviceIdAsync("Device-Range", from: start, to: end); using (Assert.EnterMultipleScope()) { var pumpAlarmEvents = result as PumpAlarmEvent[] ?? result.ToArray(); Assert.That(pumpAlarmEvents, Is.Not.Empty); Assert.That(pumpAlarmEvents.All(r => r.Time >= start && r.Time <= end), Is.True); } } [Test] public async Task FindLastByDeviceIdAsync_TracksNewest() { const string dev = "Device-LastCheck"; var e1 = new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = dev, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.AirInLine, Time = Now.AddSeconds(-10) }; var e2 = new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = dev, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Occlusion, Time = Now.AddSeconds(-5) }; await _repo.Collection.InsertManyAsync([e1, e2]); var last1 = await _repo.FindLastByDeviceIdAsync(dev); Assert.That(last1!.Id, Is.EqualTo(e2.Id)); var e3 = new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = dev, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Attention, Time = Now }; await _repo.InsertAsync(e3); var last2 = await _repo.FindLastByDeviceIdAsync(dev); Assert.That(last2!.Id, Is.EqualTo(e3.Id)); } [Test] public async Task FindByDeviceIdAsync_MultipleOverlappingRanges() { const string dev = "Device-Timeline"; var batch = new[] { new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = dev, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.AirInLine, Time = Now.AddMinutes(-20) }, new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = dev, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Occlusion, Time = Now.AddMinutes(-10) }, new PumpAlarmEvent { Id = ObjectId.GenerateNewId(), DeviceId = dev, PatientId = PatientId, AlarmType = PumpEnum.AlarmType.Attention, Time = Now.AddMinutes(-5) } }; await _repo.Collection.InsertManyAsync(batch); var r1 = await _repo.FindByDeviceIdAsync(dev, from: Now.AddMinutes(-30), to: Now.AddMinutes(-15)); var r2 = await _repo.FindByDeviceIdAsync(dev, from: Now.AddMinutes(-12), to: Now.AddMinutes(-8)); var r3 = await _repo.FindByDeviceIdAsync(dev, from: Now.AddMinutes(-6), to: Now); using (Assert.EnterMultipleScope()) { var r1List = r1.ToList(); Assert.That(r1List, Has.Count.EqualTo(1)); // -20 var r2List = r2.ToList(); Assert.That(r2List, Has.Count.EqualTo(1)); // -10 var r3List = r3.ToList(); Assert.That(r3List, Has.Count.EqualTo(1)); // -5 } } }