You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

445 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;
using Moq;
using Microsoft.AspNetCore.SignalR;
using Haoliang.Core.Services;
using Haoliang.Models.Models.Device;
using Haoliang.Models.Models.Production;
using Haoliang.Models.Models.System;
namespace Haoliang.Tests.Services
{
public class RealTimeServiceTests
{
private readonly Mock<IHubContext<RealTimeHub>> _mockHubContext;
private readonly Mock<IDeviceCollectionService> _mockDeviceCollectionService;
private readonly Mock<IProductionService> _mockProductionService;
private readonly Mock<IAlarmService> _mockAlarmService;
private readonly Mock<ICacheService> _mockCacheService;
private readonly RealTimeService _realTimeService;
public RealTimeServiceTests()
{
_mockHubContext = new Mock<IHubContext<RealTimeHub>>();
_mockDeviceCollectionService = new Mock<IDeviceCollectionService>();
_mockProductionService = new Mock<IProductionService>();
_mockAlarmService = new Mock<IAlarmService>();
_mockCacheService = new Mock<ICacheService>();
_realTimeService = new RealTimeService(
_mockHubContext.Object,
_mockDeviceCollectionService.Object,
_mockProductionService.Object,
_mockAlarmService.Object,
_mockCacheService.Object
);
}
[Fact]
public async Task ConnectClientAsync_ValidConnection_ConnectsClient()
{
// Arrange
var connectionId = "test-connection-id";
var userId = "test-user-id";
var clientType = "web";
// Act
await _realTimeService.ConnectClientAsync(connectionId, userId, clientType);
// Assert
_mockHubContext.Verify(hub => hub.Clients.Client(connectionId)
.SendAsync("ClientConnected",
It.Is<object>(o =>
dynamic obj = o &&
obj.GetType().GetProperty("ClientId").GetValue(obj) == connectionId &&
obj.GetType().GetProperty("UserId").GetValue(obj) == userId &&
obj.GetType().GetProperty("ClientType").GetValue(obj) == clientType),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task DisconnectClientAsync_ValidConnection_DisconnectsClient()
{
// Arrange
var connectionId = "test-connection-id";
// Act
await _realTimeService.DisconnectClientAsync(connectionId);
// Assert
_mockHubContext.Verify(hub => hub.Clients.AllExcept(connectionId)
.SendAsync("ClientDisconnected",
It.IsAny<object>(),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task JoinDeviceGroupAsync_ValidConnection_JoinsGroup()
{
// Arrange
var connectionId = "test-connection-id";
var deviceId = 1;
var deviceStatus = new DeviceCurrentStatus {
DeviceId = deviceId,
Status = DeviceStatus.Online,
CurrentProgram = "Test Program"
};
_mockDeviceCollectionService.Setup(service => service.GetDeviceCurrentStatusAsync(deviceId))
.ReturnsAsync(deviceStatus);
// Act
await _realTimeService.JoinDeviceGroupAsync(connectionId, deviceId);
// Assert
_mockHubContext.Verify(hub => hub.Groups.AddToGroupAsync(connectionId, $"device_{deviceId}", It.IsAny<CancellationToken>()), Times.Once);
_mockHubContext.Verify(hub => hub.Clients.Client(connectionId)
.SendAsync("DeviceStatusUpdated",
It.Is<object>(o =>
dynamic obj = o &&
obj.GetType().GetProperty("DeviceId").GetValue(obj) == deviceId),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task LeaveDeviceGroupAsync_ValidConnection_LeavesGroup()
{
// Arrange
var connectionId = "test-connection-id";
var deviceId = 1;
// Act
await _realTimeService.LeaveDeviceGroupAsync(connectionId, deviceId);
// Assert
_mockHubContext.Verify(hub => hub.Groups.RemoveFromGroupAsync(connectionId, $"device_{deviceId}", It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task JoinDashboardGroupAsync_ValidConnection_JoinsGroup()
{
// Arrange
var connectionId = "test-connection-id";
var dashboardId = "dashboard-1";
var dashboardUpdate = new DashboardUpdate {
Timestamp = DateTime.UtcNow,
TotalDevices = 10,
ActiveDevices = 8,
TotalProductionToday = 1000
};
_mockCacheService.Setup(cache => cache.GetOrSetDashboardSummaryAsync(It.IsAny<DateTime>(), It.IsAny<Func<Task<DashboardSummary>>>()))
.ReturnsAsync(new DashboardSummary {
TotalDevices = 10,
ActiveDevices = 8,
TotalProductionToday = 1000
});
// Act
await _realTimeService.JoinDashboardGroupAsync(connectionId, dashboardId);
// Assert
_mockHubContext.Verify(hub => hub.Groups.AddToGroupAsync(connectionId, $"dashboard_{dashboardId}", It.IsAny<CancellationToken>()), Times.Once);
_mockHubContext.Verify(hub => hub.Clients.Client(connectionId)
.SendAsync("DashboardUpdated",
It.Is<object>(o =>
dynamic obj = o &&
obj.GetType().GetProperty("DashboardId").GetValue(obj)?.ToString() == dashboardId),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task LeaveDashboardGroupAsync_ValidConnection_LeavesGroup()
{
// Arrange
var connectionId = "test-connection-id";
var dashboardId = "dashboard-1";
// Act
await _realTimeService.LeaveDashboardGroupAsync(connectionId, dashboardId);
// Assert
_mockHubContext.Verify(hub => hub.Groups.RemoveFromGroupAsync(connectionId, $"dashboard_{dashboardId}", It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task BroadcastDeviceStatusAsync_ValidStatus_BroadcastsToGroups()
{
// Arrange
var statusUpdate = new DeviceStatusUpdate
{
DeviceId = 1,
DeviceName = "Test Device",
Status = DeviceStatus.Running,
CurrentProgram = "Test Program",
Runtime = TimeSpan.FromHours(1),
Timestamp = DateTime.UtcNow
};
// Act
await _realTimeService.BroadcastDeviceStatusAsync(statusUpdate);
// Assert
_mockHubContext.Verify(hub => hub.Clients.Group($"device_1")
.SendAsync("DeviceStatusUpdated",
It.Is<DeviceStatusUpdate>(s => s.DeviceId == 1 && s.Status == DeviceStatus.Running),
It.IsAny<CancellationToken>()), Times.Once);
_mockHubContext.Verify(hub => hub.Clients.Group("dashboard")
.SendAsync("DeviceStatusUpdated",
It.Is<DeviceStatusUpdate>(s => s.DeviceId == 1 && s.Status == DeviceStatus.Running),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task BroadcastProductionUpdateAsync_ValidUpdate_BroadcastsToGroups()
{
// Arrange
var productionUpdate = new ProductionUpdate
{
DeviceId = 1,
DeviceName = "Test Device",
Quantity = 100,
Timestamp = DateTime.UtcNow
};
// Act
await _realTimeService.BroadcastProductionUpdateAsync(productionUpdate);
// Assert
_mockHubContext.Verify(hub => hub.Clients.Group($"device_1")
.SendAsync("ProductionUpdated",
It.Is<ProductionUpdate>(p => p.DeviceId == 1 && p.Quantity == 100),
It.IsAny<CancellationToken>()), Times.Once);
_mockHubContext.Verify(hub => hub.Clients.Group("dashboard")
.SendAsync("ProductionUpdated",
It.Is<ProductionUpdate>(p => p.DeviceId == 1 && p.Quantity == 100),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task BroadcastAlertAsync_ValidAlert_BroadcastsToRelevantGroups()
{
// Arrange
var alertUpdate = new AlertUpdate
{
DeviceId = 1,
DeviceName = "Test Device",
AlertType = "DeviceError",
Message = "Device error occurred",
Timestamp = DateTime.UtcNow,
IsResolved = false
};
// Act
await _realTimeService.BroadcastAlertAsync(alertUpdate);
// Assert
_mockHubContext.Verify(hub => hub.Clients.Group("dashboard")
.SendAsync("AlertUpdated",
It.Is<AlertUpdate>(a => a.DeviceId == 1 && a.AlertType == "DeviceError"),
It.IsAny<CancellationToken>()), Times.Once);
_mockHubContext.Verify(hub => hub.Clients.Group("alerts")
.SendAsync("AlertUpdated",
It.Is<AlertUpdate>(a => a.DeviceId == 1 && a.AlertType == "DeviceError"),
It.IsAny<CancellationToken>()), Times.Once);
_mockHubContext.Verify(hub => hub.Clients.Group($"device_1")
.SendAsync("AlertUpdated",
It.Is<AlertUpdate>(a => a.DeviceId == 1 && a.AlertType == "DeviceError"),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task SendSystemNotificationAsync_ValidNotification_SendsToNotificationGroup()
{
// Arrange
var notification = new SystemNotification
{
NotificationType = "Info",
Title = "System Update",
Message = "System maintenance scheduled",
Timestamp = DateTime.UtcNow
};
// Act
await _realTimeService.SendSystemNotificationAsync(notification);
// Assert
_mockHubContext.Verify(hub => hub.Clients.Group("notifications")
.SendAsync("SystemNotification",
It.Is<SystemNotification>(n =>
n.NotificationType == "Info" &&
n.Title == "System Update"),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task SendDashboardUpdateAsync_ValidUpdate_SendsToDashboardGroup()
{
// Arrange
var dashboardUpdate = new DashboardUpdate
{
Timestamp = DateTime.UtcNow,
TotalDevices = 10,
ActiveDevices = 8,
TotalProductionToday = 1000
};
// Act
await _realTimeService.SendDashboardUpdateAsync(dashboardUpdate);
// Assert
_mockHubContext.Verify(hub => hub.Clients.Group("dashboard")
.SendAsync("DashboardUpdated",
It.Is<DashboardUpdate>(d =>
d.TotalDevices == 10 &&
d.ActiveDevices == 8),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task SendCommandToClientAsync_ValidCommand_SendsToClient()
{
// Arrange
var connectionId = "test-connection-id";
var command = new RealTimeCommand
{
Command = "RefreshData",
Parameters = new { Interval = 5000 },
Timestamp = DateTime.UtcNow
};
// Act
await _realTimeService.SendCommandToClientAsync(connectionId, command);
// Assert
_mockHubContext.Verify(hub => hub.Clients.Client(connectionId)
.SendAsync("Command",
It.Is<RealTimeCommand>(c =>
c.Command == "RefreshData" &&
c.Parameters.ToString().Contains("Interval")),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task BroadcastCommandAsync_ValidCommand_BroadcastsToAllClients()
{
// Arrange
var command = new RealTimeCommand
{
Command = "SystemShutdown",
Parameters = new { DelayMinutes = 5 },
Timestamp = DateTime.UtcNow
};
// Act
await _realTimeService.BroadcastCommandAsync(command);
// Assert
_mockHubContext.Verify(hub => hub.Clients.All
.SendAsync("Command",
It.Is<RealTimeCommand>(c =>
c.Command == "SystemShutdown"),
It.IsAny<CancellationToken>()), Times.Once);
}
[Fact]
public async Task GetConnectedClientsCountAsync_ValidClients_ReturnsCount()
{
// Arrange
// This test would need to mock the internal client tracking
// For now, we'll verify the method exists and doesn't throw
var result = await _realTimeService.GetConnectedClientsCountAsync();
// Assert
Assert.True(result >= 0); // Should return a non-negative number
}
[Fact]
public async Task GetConnectedClientsByTypeAsync_ValidType_ReturnsClients()
{
// Arrange
var clientType = "web";
// This test would need to mock the internal client tracking
// For now, we'll verify the method exists and doesn't throw
var result = await _realTimeService.GetConnectedClientsByTypeAsync(clientType);
// Assert
Assert.NotNull(result);
}
[Fact]
public async Task GetDeviceMonitoringStatusAsync_ValidDevice_ReturnsStatus()
{
// Arrange
var deviceId = 1;
var streamingInfo = new DeviceStreamingInfo
{
DeviceId = deviceId,
IntervalMs = 1000,
StartedAt = DateTime.UtcNow.AddMinutes(-5),
LastUpdate = DateTime.UtcNow.AddMinutes(-1),
IsRunning = true
};
// This test would need to mock the internal device streaming tracking
// For now, we'll verify the method exists and doesn't throw
var result = await _realTimeService.GetDeviceMonitoringStatusAsync(deviceId);
// Assert
Assert.NotNull(result);
Assert.Equal(deviceId, result.DeviceId);
Assert.True(result.IsStreaming);
}
[Fact]
public async Task StartDeviceStreamingAsync_ValidDevice_StartsStreaming()
{
// Arrange
var deviceId = 1;
var intervalMs = 1000;
// This test would need to mock the internal device streaming tracking
// and verify that streaming starts
// For now, we'll verify the method exists and doesn't throw
await _realTimeService.StartDeviceStreamingAsync(deviceId, intervalMs);
// Assert - would need to verify streaming started
Assert.True(true); // Placeholder assertion
}
[Fact]
public async Task StopDeviceStreamingAsync_ValidDevice_StopsStreaming()
{
// Arrange
var deviceId = 1;
// This test would need to mock the internal device streaming tracking
// and verify that streaming stops
// For now, we'll verify the method exists and doesn't throw
await _realTimeService.StopDeviceStreamingAsync(deviceId);
// Assert - would need to verify streaming stopped
Assert.True(true); // Placeholder assertion
}
[Fact]
public async Task GetActiveStreamingDevicesAsync_ReturnsStreamingDevices()
{
// This test would need to mock the internal device streaming tracking
// For now, we'll verify the method exists and doesn't throw
var result = await _realTimeService.GetActiveStreamingDevicesAsync();
// Assert
Assert.NotNull(result);
Assert.IsType<List<int>>(result);
}
}
}