using JdeScoping.Api.Hubs; using JdeScoping.Core.ViewModels; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using NSubstitute; using Shouldly; namespace JdeScoping.Api.Tests.Hubs; public class StatusHubTests { private readonly IMemoryCache _cache; private readonly ILogger _logger; private readonly TimeProvider _timeProvider; private readonly StatusHub _hub; public StatusHubTests() { _cache = new MemoryCache(new MemoryCacheOptions()); _logger = Substitute.For>(); _timeProvider = TimeProvider.System; _hub = new StatusHub(_cache, _logger, _timeProvider); } [Fact] public async Task SetStatus_CachesAndBroadcasts() { // Arrange var clientProxy = Substitute.For(); var hubClients = Substitute.For(); hubClients.All.Returns(clientProxy); var hubContext = Substitute.For(); hubContext.ConnectionId.Returns("test-connection-id"); // Use reflection to set the Clients property since Hub properties are typically set by the framework var clientsProperty = typeof(Hub).GetProperty("Clients"); clientsProperty?.SetValue(_hub, hubClients); var statusUpdate = new StatusUpdateViewModel { Message = "Processing", Timestamp = DateTime.UtcNow }; // Act await _hub.SetStatus(statusUpdate); // Assert - verify broadcast was called await clientProxy.Received(1).SendCoreAsync( "statusUpdate", Arg.Is(args => args.Length == 1 && args[0] == statusUpdate), Arg.Any()); // Assert - verify status was cached var cachedStatus = _hub.GetCachedStatus(); cachedStatus.Message.ShouldBe("Processing"); } [Fact] public void GetCachedStatus_ReturnsLastSetStatus() { // Act var status = _hub.GetCachedStatus(); // Assert status.ShouldNotBeNull(); // Initial message is "Unknown" status.Message.ShouldBe("Unknown"); } [Fact] public void GetCachedStatus_InitialStatusIsUnknown() { // Act var status = _hub.GetCachedStatus(); // Assert status.ShouldNotBeNull(); status.Message.ShouldBe("Unknown"); // The timestamp should be set status.Timestamp.ShouldNotBe(default); } [Fact] public async Task PublishSearchUpdate_BroadcastsToAll() { // Arrange var clientProxy = Substitute.For(); var hubClients = Substitute.For(); hubClients.All.Returns(clientProxy); var clientsProperty = typeof(Hub).GetProperty("Clients"); clientsProperty?.SetValue(_hub, hubClients); var searchUpdate = new SearchUpdateViewModel { Id = 42, UserName = "testuser", Name = "Test Search", Status = "Running" }; // Act await _hub.PublishSearchUpdate(searchUpdate); // Assert await clientProxy.Received(1).SendCoreAsync( "searchUpdate", Arg.Is(args => args.Length == 1 && args[0] == searchUpdate), Arg.Any()); } }