604bfe919c
Apply comprehensive fixes from code reviews including: - Extract shared utilities (SqlFormatHelper, CellValueConverter, DbDestinationBase) - Add interface abstractions (IAuthenticationService, IDatabaseMigrator, IMisQueryBuilder) - Implement SecureStore for encrypted secrets storage - Fix error handling with proper HTTP status codes and logging - Optimize double enumeration in DevEtlRegistry - Add DataSync.Dev README for developer onboarding - Extract filter panel base classes to reduce duplication - Update code review docs to mark all issues as fixed
115 lines
3.5 KiB
C#
115 lines
3.5 KiB
C#
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<StatusHub> _logger;
|
|
private readonly TimeProvider _timeProvider;
|
|
private readonly StatusHub _hub;
|
|
|
|
public StatusHubTests()
|
|
{
|
|
_cache = new MemoryCache(new MemoryCacheOptions());
|
|
_logger = Substitute.For<ILogger<StatusHub>>();
|
|
_timeProvider = TimeProvider.System;
|
|
_hub = new StatusHub(_cache, _logger, _timeProvider);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task SetStatus_CachesAndBroadcasts()
|
|
{
|
|
// Arrange
|
|
var clientProxy = Substitute.For<IClientProxy>();
|
|
var hubClients = Substitute.For<IHubCallerClients>();
|
|
hubClients.All.Returns(clientProxy);
|
|
|
|
var hubContext = Substitute.For<HubCallerContext>();
|
|
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<object?[]>(args => args.Length == 1 && args[0] == statusUpdate),
|
|
Arg.Any<CancellationToken>());
|
|
|
|
// 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<IClientProxy>();
|
|
var hubClients = Substitute.For<IHubCallerClients>();
|
|
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<object?[]>(args => args.Length == 1 && args[0] == searchUpdate),
|
|
Arg.Any<CancellationToken>());
|
|
}
|
|
}
|