using adas_core.Application.Services.Caching; using adas_core.Application.Services.Interfaces; using adas_core.Domain.Enums; using adas_core.Domain.Models.AppSettings; using adas_core.Domain.Models.GroupedObservations; using adas_core.Domain.Utils; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MongoDB.Bson; using Moq; namespace adas_core.Test.Services; public class FakeLockProvider : ILockProvider { public Task AcquireAsync(string key, TimeSpan timeout) => Task.FromResult(true); public Task ReleaseAsync(string key) => Task.CompletedTask; } public class FakeLockManagerService : LockManagerService { public FakeLockManagerService() : base( Mock.Of>(), new FakeLockProvider()) { } } public class FakeRedisService : RedisService, ICacheService { public bool WasCalled { get; private set; } public string? LastKey { get; private set; } public FakeRedisService() : base( Options.Create(new CacheSettings()), Mock.Of>(), new FakeLockManagerService()) { } Task ICacheService.GetOrSetObjectAsync( string key, Func> factory, TimeSpan? ttl, CancellationToken cancellationToken) { WasCalled = true; LastKey = key; return factory(); } Task ICacheService.GetOrSetObjectAsync( GroupedField groupedField, ObjectId patientId, Func> factory, TimeSpan? ttl, CancellationToken cancellationToken) { WasCalled = true; return factory(); } } public class FakeCacheService : CacheService, ICacheService { public bool WasCalled { get; private set; } public string? LastKey { get; private set; } public FakeCacheService() : base(new FakeLockManagerService()) { } Task ICacheService.GetOrSetObjectAsync( string key, Func> factory, TimeSpan? ttl, CancellationToken cancellationToken) { WasCalled = true; LastKey = key; return factory(); } Task ICacheService.GetOrSetObjectAsync( GroupedField groupedField, ObjectId patientId, Func> factory, TimeSpan? ttl, CancellationToken cancellationToken) { WasCalled = true; return factory(); } } public class FakeNoCacheService : NoCacheService, ICacheService { public bool WasCalled { get; private set; } public string? LastKey { get; private set; } Task ICacheService.GetOrSetObjectAsync( string key, Func> factory, TimeSpan? ttl, CancellationToken cancellationToken) { WasCalled = true; LastKey = key; return factory(); } Task ICacheService.GetOrSetObjectAsync( GroupedField groupedField, ObjectId patientId, Func> factory, TimeSpan? ttl, CancellationToken cancellationToken) { WasCalled = true; return factory(); } } [TestFixture] public class CacheDispatcherTest { private FakeRedisService _redisServiceFake = null!; private FakeCacheService _memoryServiceFake = null!; private FakeNoCacheService _noopServiceFake = null!; private CacheSettings _cacheSettings = null!; private CacheDispatcher _cacheDispatcher = null!; [SetUp] public void SetUp() { _redisServiceFake = new FakeRedisService(); _memoryServiceFake = new FakeCacheService(); _noopServiceFake = new FakeNoCacheService(); _cacheSettings = new CacheSettings(); _cacheDispatcher = new CacheDispatcher( _redisServiceFake, _memoryServiceFake, _noopServiceFake, _cacheSettings); } #region TC-23 [Test] public async Task GetOrSetObjectAsync_UsesRedisService_WhenPatientsModeIsRedis() { // Arrange var key = "patients:latestObs:abc"; var expectedResult = new { Name = "TestPatient" }; Func> factory = () => Task.FromResult(expectedResult); _cacheSettings.Patients = CacheEnum.Mode.Redis; // Act var result = await _cacheDispatcher.GetOrSetObjectAsync(key, factory); // Assert Assert.That(_redisServiceFake.WasCalled, Is.True, "RedisService debería haber sido invocado"); Assert.That(_redisServiceFake.LastKey, Is.EqualTo(key)); Assert.That(_memoryServiceFake.WasCalled, Is.False, "CacheService NO debería haber sido invocado"); Assert.That(_noopServiceFake.WasCalled, Is.False, "NoCacheService NO debería haber sido invocado"); } #endregion #region TC-24 [Test] public async Task GetOrSetObjectAsync_UsesCacheService_WhenAppointmentsModeIsCache() { // Arrange var key = "appointments:patient:id:20260224"; var expectedResult = new { Name = "TestAppointment" }; Func> factory = () => Task.FromResult(expectedResult); _cacheSettings.Appointments = CacheEnum.Mode.Cache; // Act var result = await _cacheDispatcher.GetOrSetObjectAsync(key, factory); // Assert Assert.That(_memoryServiceFake.WasCalled, Is.True, "CacheService debería haber sido invocado"); Assert.That(_memoryServiceFake.LastKey, Is.EqualTo(key)); Assert.That(_redisServiceFake.WasCalled, Is.False, "RedisService NO debería haber sido invocado"); Assert.That(_noopServiceFake.WasCalled, Is.False, "NoCacheService NO debería haber sido invocado"); } #endregion #region TC-25 [Test] public async Task GetOrSetObjectAsync_UsesNoCacheService_WhenPumpObservationsModeIsNone() { // Arrange var key = "pumpObs:latest:abc:10"; var expectedResult = new { Name = "TestPump" }; Func> factory = () => Task.FromResult(expectedResult); _cacheSettings.PumpObservations = CacheEnum.Mode.None; // Act var result = await _cacheDispatcher.GetOrSetObjectAsync(key, factory); // Assert Assert.That(_noopServiceFake.WasCalled, Is.True, "NoCacheService debería haber sido invocado"); Assert.That(_noopServiceFake.LastKey, Is.EqualTo(key)); Assert.That(_redisServiceFake.WasCalled, Is.False, "RedisService NO debería haber sido invocado"); Assert.That(_memoryServiceFake.WasCalled, Is.False, "CacheService NO debería haber sido invocado"); } #endregion #region TC-26 [Test] public async Task GetOrSetObjectAsync_UsesCacheService_WhenKeyIsUnrecognized() { // Arrange var key = "unknown:prefix:key"; var expectedResult = new { Name = "TestUnknown" }; Func> factory = () => Task.FromResult(expectedResult); // Act var result = await _cacheDispatcher.GetOrSetObjectAsync(key, factory); // Assert - Unknown keys fallback to InMemory (Cache) Assert.That(_memoryServiceFake.WasCalled, Is.True, "CacheService debería haber sido invocado como fallback"); Assert.That(_memoryServiceFake.LastKey, Is.EqualTo(key)); Assert.That(_redisServiceFake.WasCalled, Is.False, "RedisService NO debería haber sido invocado"); Assert.That(_noopServiceFake.WasCalled, Is.False, "NoCacheService NO debería haber sido invocado"); } [Test] public void Classify_ReturnsUnknown_ForUnrecognizedPrefix() { // Arrange var key = "unknown:prefix:key"; // Act var result = CacheKeyClassifier.Classify(key); // Assert Assert.That(result, Is.EqualTo(CacheEnum.EntityType.Unknown)); } #endregion }