424 lines
17 KiB
C#
424 lines
17 KiB
C#
using System.Security.Claims;
|
|
using adas_core.Application.Exceptions;
|
|
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.AppSettings;
|
|
using adas_core.Domain.Models.MongoModels;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.Extensions.Logging;
|
|
using MongoDB.Bson;
|
|
using Moq;
|
|
using static NUnit.Framework.Assert;
|
|
using Options = Microsoft.Extensions.Options.Options;
|
|
|
|
namespace adas_core.Test.Services;
|
|
|
|
[TestFixture]
|
|
public class DisplayServiceTest
|
|
{
|
|
private Mock<ICacheService> _mockCacheService = null!;
|
|
private Mock<IDisplayRepository> _mockDisplayRepository = null!;
|
|
private Mock<IPointOfCareService> _mockPointOfCareService = null!;
|
|
private Mock<IDisplayConfigService> _mockDisplayConfigService = null!;
|
|
private Mock<IUserRepository> _mockUserRepository = null!;
|
|
private Mock<IAuthService> _authServiceMock = null!;
|
|
private Mock<ISubscribersService> _mockSubscribersService = null!;
|
|
private Mock<IClientMessageService> _mockClientMessageService = null!;
|
|
private Mock<Lazy<IUnitService>> _mockUnitService = null!;
|
|
private Mock<IPermissionService> _mockPermissionService = null!;
|
|
private Lazy<IPermissionService> _lazyMockPermission = null!;
|
|
private Mock<ILogger<DisplayService>> _mockLogger = null!;
|
|
private readonly Mock<IHttpContextAccessor> _httpContextAccessorMock = new();
|
|
private readonly Mock<ILocalAuditService> _auditServiceMock = new();
|
|
|
|
private DisplayService _displayService = null!;
|
|
|
|
/// <summary>
|
|
/// Initializes mocked dependencies and configuration required to construct a <see cref="DisplayService"/> instance for unit tests.
|
|
/// Sets up the HTTP context with a test user claim, creates default cache settings, and wires all collaborators (repositories, services, logger, permissions) into the service under test.
|
|
/// </summary>
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
_mockCacheService = new Mock<ICacheService>();
|
|
_mockDisplayRepository = new Mock<IDisplayRepository>();
|
|
_mockPointOfCareService = new Mock<IPointOfCareService>();
|
|
_mockDisplayConfigService = new Mock<IDisplayConfigService>();
|
|
_mockUserRepository = new Mock<IUserRepository>();
|
|
_authServiceMock = new Mock<IAuthService>();
|
|
_mockSubscribersService = new Mock<ISubscribersService>();
|
|
_mockClientMessageService = new Mock<IClientMessageService>();
|
|
_mockUnitService = new Mock<Lazy<IUnitService>>();
|
|
_mockPermissionService = new Mock<IPermissionService>();
|
|
_lazyMockPermission = new Lazy<IPermissionService>(() => _mockPermissionService.Object);
|
|
_mockLogger = new Mock<ILogger<DisplayService>>();
|
|
|
|
var claims = new ClaimsPrincipal(
|
|
new ClaimsIdentity([new Claim(ClaimTypes.Name, "TestUser")], "mock"));
|
|
_httpContextAccessorMock.Setup(a => a.HttpContext).Returns(new DefaultHttpContext { User = claims });
|
|
|
|
var cacheSettings = Options.Create(new CacheSettings());
|
|
|
|
_displayService = new DisplayService(
|
|
_mockDisplayRepository.Object,
|
|
_mockPointOfCareService.Object,
|
|
_mockUnitService.Object,
|
|
_mockDisplayConfigService.Object,
|
|
_mockSubscribersService.Object,
|
|
_mockClientMessageService.Object,
|
|
_mockUserRepository.Object,
|
|
_authServiceMock.Object,
|
|
_mockLogger.Object,
|
|
_httpContextAccessorMock.Object,
|
|
_auditServiceMock.Object,
|
|
_lazyMockPermission,
|
|
_mockCacheService.Object,
|
|
cacheSettings
|
|
);
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// InsertOne
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that <see cref="DisplayService.InsertOne"/> inserts a display by resolving the default configuration for its type and persisting it through the repository's insert method.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task InsertOne_ShouldInsertDisplay()
|
|
{
|
|
var display = new Display
|
|
{
|
|
Name = "Test Display",
|
|
Type = DisplayConfigEnums.DisplayType.DisplayNurse
|
|
};
|
|
|
|
var defaultCfg = new DisplayConfig { Id = ObjectId.GenerateNewId(), Type = display.Type };
|
|
|
|
_mockDisplayConfigService.Setup(s => s.GetDefaultConfig(display.Type)).ReturnsAsync(defaultCfg);
|
|
|
|
_mockDisplayRepository.Setup(r => r.InsertOneAsync(display))
|
|
.Returns(Task.CompletedTask);
|
|
|
|
var result = await _displayService.InsertOne(display);
|
|
|
|
That(result, Is.EqualTo(display));
|
|
_mockDisplayRepository.Verify(r => r.InsertOneAsync(display), Times.Once);
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// GetById
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that the <see cref="DisplayService"/> returns the expected <see cref="Display"/> instance when a matching id is provided through the repository.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task GetById_ShouldReturnDisplay()
|
|
{
|
|
var id = ObjectId.GenerateNewId();
|
|
var d = new Display { Id = id, Name = "D1" };
|
|
|
|
_mockDisplayRepository.Setup(r => r.GetById(id)).ReturnsAsync(d);
|
|
|
|
var result = await _displayService.GetById(id);
|
|
|
|
That(result, Is.EqualTo(d));
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// GetAllByUser - userName null
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that _displayService.GetAllByUser returns an empty collection when the user name is null.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task GetAllByUser_ShouldReturnEmpty_WhenUserNameNull()
|
|
{
|
|
var result = await _displayService.GetAllByUser(null);
|
|
That(result, Is.Empty);
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// GetAllByUser - Admin case
|
|
// -----------------------------------------------------------
|
|
|
|
[Test]
|
|
public async Task GetAllByUser_ShouldReturnDisplays_WhenAdmin()
|
|
{
|
|
// Arrange
|
|
const string userName = "admin";
|
|
|
|
var adminId = ObjectId.GenerateNewId();
|
|
var unitId = ObjectId.GenerateNewId();
|
|
|
|
var user = new User
|
|
{
|
|
Id = adminId,
|
|
UserName = userName,
|
|
Authorization =
|
|
[
|
|
new Authorization { UnitId = unitId.ToString(), Rol = nameof(PermissionEnum.RolesType.AuthAdmin) }
|
|
]
|
|
};
|
|
|
|
// 1) Usuario + authorities
|
|
_mockUserRepository.Setup(r => r.GetByUserAndAuthoritesName(userName))
|
|
.ReturnsAsync(user);
|
|
|
|
_authServiceMock.Setup(a => a.GetUserAuthorities(adminId))
|
|
.ReturnsAsync(user.Authorization);
|
|
|
|
// 2) Displays por UnitId
|
|
var d1 = new Display { Id = ObjectId.GenerateNewId(), Name = "D1", UnitId = unitId };
|
|
var d2 = new Display { Id = ObjectId.GenerateNewId(), Name = "D2", UnitId = unitId };
|
|
var displays = new List<Display> { d1, d2 };
|
|
|
|
_mockDisplayRepository.Setup(r => r.GetByUnitId(unitId))
|
|
.ReturnsAsync(displays);
|
|
|
|
// 3) GetInfo (rama base) → caché debe devolver el display haciendo el factory
|
|
_mockDisplayRepository.Setup(r => r.GetById(d1.Id)).ReturnsAsync(d1);
|
|
_mockDisplayRepository.Setup(r => r.GetById(d2.Id)).ReturnsAsync(d2);
|
|
|
|
_mockCacheService
|
|
.Setup(c => c.GetOrSetObjectAsync(
|
|
It.IsAny<string>(),
|
|
It.IsAny<Func<Task<Display?>>>(),
|
|
It.IsAny<TimeSpan?>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.Returns((string _, Func<Task<Display?>> factory, TimeSpan? _, CancellationToken _) => factory());
|
|
|
|
|
|
// 4) Permisos (si es null, el servicio NO añade el display)
|
|
_mockPermissionService
|
|
.Setup(p => p.GetPermissionsForUnit(unitId.ToString(), user))
|
|
.ReturnsAsync(new DisplayPermissionTypes(
|
|
new UserActions(true, true, true, true, true),
|
|
new UserActions(true, true, true, true, true),
|
|
new UserActions(true, true, true, true, true),
|
|
new UserActions(true, true, true, true, true),
|
|
new UserActions(true, true, true, true, true),
|
|
new UserActions(true, true, true, true, true),
|
|
new UserActions(true, true, true, true, true),
|
|
true
|
|
));
|
|
|
|
// Act
|
|
var result = await _displayService.GetAllByUser(userName);
|
|
|
|
// Assert
|
|
That(result, Has.Count.EqualTo(2));
|
|
using (Assert.EnterMultipleScope())
|
|
{
|
|
That(result.Any(r => r.Display != null && r.Display.Id == d1.Id), Is.True);
|
|
That(result.Any(r => r.Display != null && r.Display.Id == d2.Id), Is.True);
|
|
}
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// GetByType
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that retrieving display configurations by type returns the associated displays
|
|
/// from the display repository, ensuring the service correctly resolves configurations and
|
|
/// their linked displays for the given display type.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task GetByType_ShouldReturnDisplays()
|
|
{
|
|
var cfgId = ObjectId.GenerateNewId();
|
|
var cfg = new DisplayConfig { Id = cfgId, Type = DisplayConfigEnums.DisplayType.DisplayNurse };
|
|
var display = new Display { Id = ObjectId.GenerateNewId(), DisplayConfigId = cfgId, Name = "D" };
|
|
|
|
_mockDisplayConfigService.Setup(s => s.GetByType(cfg.Type))
|
|
.ReturnsAsync([cfg]);
|
|
|
|
_mockDisplayRepository.Setup(r => r.GetByConfigId(cfgId))
|
|
.ReturnsAsync([display]);
|
|
|
|
var result = await _displayService.GetByType(cfg.Type);
|
|
|
|
That(result.Count, Is.EqualTo(1));
|
|
That(result[0], Is.EqualTo(display));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that <see cref="DisplayService.GetByType"/> returns an empty collection when no display configurations are found for the specified display type.
|
|
/// </summary>
|
|
/// <returns>A task that completes when the assertion confirming the empty result has been executed.</returns>
|
|
[Test]
|
|
public async Task GetByType_ShouldReturnEmpty_WhenNoConfigsFound()
|
|
{
|
|
_mockDisplayConfigService.Setup(s => s.GetByType(It.IsAny<DisplayConfigEnums.DisplayType>()))
|
|
.ReturnsAsync([]);
|
|
|
|
var result = await _displayService.GetByType(DisplayConfigEnums.DisplayType.DisplayNurse);
|
|
|
|
That(result, Is.Empty);
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// GetByPointOfCare
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Tests that GetByPointOfCare returns the displays associated with the specified point of care.
|
|
/// </summary>
|
|
/// <param name="poc">The point of care used to look up associated displays.</param>
|
|
/// <returns>A task representing the asynchronous test execution.</returns>
|
|
[Test]
|
|
public async Task GetByPointOfCare_ShouldReturnDisplays()
|
|
{
|
|
var poc = new PointOfCare { Id = ObjectId.GenerateNewId() };
|
|
var d = new Display { Id = ObjectId.GenerateNewId(), Name = "Display" };
|
|
|
|
_mockDisplayRepository.Setup(r => r.GetByPointOfCare(poc))
|
|
.ReturnsAsync([d]);
|
|
|
|
var result = await _displayService.GetByPointOfCare(poc);
|
|
|
|
That(result, Has.Count.EqualTo(1));
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// GetByConfigId
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that <see cref="DisplayService.GetByConfigId"/> returns the displays associated with the specified configuration ID retrieved from the repository.
|
|
/// </summary>
|
|
/// <returns>A task that completes when the assertion confirms the returned collection contains the expected number of displays.</returns>
|
|
[Test]
|
|
public async Task GetByConfigId_ShouldReturnDisplays()
|
|
{
|
|
var cfgId = ObjectId.GenerateNewId();
|
|
var d = new Display { Id = ObjectId.GenerateNewId(), DisplayConfigId = cfgId, Name = "display1" };
|
|
|
|
_mockDisplayRepository.Setup(r => r.GetByConfigId(cfgId))
|
|
.ReturnsAsync([d]);
|
|
|
|
var result = await _displayService.GetByConfigId(cfgId);
|
|
|
|
That(result, Has.Count.EqualTo(1));
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// GetByName
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that the <see cref="DisplayService.GetByName"/> method throws a <see cref="NotFoundException"/> when no display matching the specified name is found in the repository.
|
|
/// </summary>
|
|
[Test]
|
|
public void GetByName_ShouldThrow_WhenNotFound()
|
|
{
|
|
_mockDisplayRepository.Setup(r => r.GetByName("X"))
|
|
.ReturnsAsync((Display?)null);
|
|
|
|
Func<Task> act = () => _displayService.GetByName("X");
|
|
Assert.ThrowsAsync<NotFoundException>(act);
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// GetInfo
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that <c>GetInfo</c> returns a <see cref="Display"/> with its associated <c>PointOfCare</c> entries populated when invoked with the "with POC" flag enabled and a valid display identifier.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task GetInfo_ShouldReturnDisplayWithPoc()
|
|
{
|
|
var id = ObjectId.GenerateNewId();
|
|
var cfgId = ObjectId.GenerateNewId();
|
|
var pocId = ObjectId.GenerateNewId();
|
|
|
|
var display = new Display
|
|
{
|
|
Id = id,
|
|
Name = "Display",
|
|
DisplayConfigId = cfgId,
|
|
PointOfCareIdList = [pocId]
|
|
};
|
|
|
|
_mockCacheService
|
|
.Setup(c => c.GetOrSetObjectAsync(
|
|
It.IsAny<string>(),
|
|
It.IsAny<Func<Task<Display?>>>(),
|
|
It.IsAny<TimeSpan?>(),
|
|
It.IsAny<CancellationToken>()))
|
|
.Returns((string _, Func<Task<Display?>> factory, TimeSpan? _, CancellationToken _) => factory());
|
|
|
|
_mockDisplayRepository.Setup(r => r.GetById(id)).ReturnsAsync(display);
|
|
_mockDisplayConfigService.Setup(s => s.GetById(cfgId))
|
|
.ReturnsAsync(new DisplayConfig { Id = cfgId });
|
|
|
|
var poc = new PointOfCare { Id = pocId };
|
|
|
|
_mockPointOfCareService.Setup(s => s.GetInfo(pocId, null, true, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(poc);
|
|
|
|
var result = await _displayService.GetInfo(id, "user", [], null, true, true, false);
|
|
|
|
That(result, Is.Not.Null);
|
|
That(result!.PointOfCares.First(), Is.EqualTo(poc));
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// GetByUnitId
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that <see cref="IDisplayService.GetByUnitId"/> returns the displays associated with the specified unit identifier when the repository contains matching records.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task GetByUnitId_ShouldReturnDisplays()
|
|
{
|
|
var id = ObjectId.GenerateNewId();
|
|
var d = new Display { Id = ObjectId.GenerateNewId(), UnitId = id, Name = "display1" };
|
|
|
|
_mockDisplayRepository.Setup(r => r.GetByUnitId(id))
|
|
.ReturnsAsync([d]);
|
|
|
|
var result = await _displayService.GetByUnitId(id);
|
|
|
|
That(result, Has.Count.EqualTo(1));
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// UpdatePointOfCareList
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that UpdatePointOfCareList throws a <see cref="NotFoundException"/> when the display with the specified identifier does not exist.
|
|
/// </summary>
|
|
/// <exception cref="NotFoundException">Thrown when no display is found for the given id.</exception>
|
|
[Test]
|
|
public void UpdatePointOfCareList_ShouldThrow_WhenDisplayNotFound()
|
|
{
|
|
var id = ObjectId.GenerateNewId();
|
|
|
|
_mockDisplayRepository.Setup(r => r.GetById(id))
|
|
.ReturnsAsync((Display?)null);
|
|
|
|
Func<Task> act = () => _displayService.UpdatePointOfCareList(id, []);
|
|
Assert.ThrowsAsync<NotFoundException>(act);
|
|
}
|
|
|
|
// -----------------------------------------------------------
|
|
// UpdateConfigPreset
|
|
// -----------------------------------------------------------
|
|
/// <summary>
|
|
/// Verifies that <see cref="DisplayService.UpdateConfigPreset"/> throws a <see cref="NotFoundException"/> when the repository update operation returns a null result, indicating the display or configuration preset could not be found.
|
|
/// </summary>
|
|
/// <param name="id">The unique identifier of the display whose configuration preset is being updated.</param>
|
|
/// <param name="cfgId">The unique identifier of the configuration preset to associate with the display.</param>
|
|
[Test]
|
|
public void UpdateConfigPreset_ShouldThrow_WhenUpdateFails()
|
|
{
|
|
var id = ObjectId.GenerateNewId();
|
|
var cfgId = ObjectId.GenerateNewId();
|
|
|
|
_mockDisplayRepository.Setup(r => r.UpdateConfigPreset(id, cfgId))
|
|
.ReturnsAsync((Display?)null);
|
|
|
|
Func<Task> act = () => _displayService.UpdateConfigPreset(id, cfgId);
|
|
Assert.ThrowsAsync<NotFoundException>(act);
|
|
}
|
|
} |