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.
haoliang-net/tests/CncService.Tests/DashboardServiceTests.cs

201 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using Xunit;
using CncModels.Dto.Dashboard;
using CncModels.Entity;
using CncRepository.Interface;
using CncService.Interface;
using CncService.Impl;
namespace CncService.Tests
{
// Fake repositories to isolate DashboardService.GetCollectorStatus tests
public class FakeDashboardRepository : IDashboardRepository
{
public DashboardSummaryResponse GetSummary() => new DashboardSummaryResponse();
public List<WorkshopProductionResponse> GetWorkshopProduction(DateTime startDate, DateTime endDate) => new List<WorkshopProductionResponse>();
public List<MachineRankResponse> GetMachineRank(DateTime startDate, DateTime endDate, int top, string sortOrder = "desc") => new List<MachineRankResponse>();
public List<WorkerRankResponse> GetWorkerRank(DateTime startDate, DateTime endDate, int top, string sortOrder = "desc") => new List<WorkerRankResponse>();
public List<dynamic> GetProductionTrend(int days) => new List<dynamic>();
public object GetMachineStatusDistribution() => new object();
public List<AlertListItem> GetRecentAlerts(int count) => new List<AlertListItem>();
public List<ProgramRankItem> GetProgramRank(DateTime startDate, DateTime endDate, int top, string sortOrder = "desc") => new List<ProgramRankItem>();
public List<ProgramDistributionItem> GetProgramDistribution(DateTime startDate, DateTime endDate, int top = 10) => new List<ProgramDistributionItem>();
}
public class FakeCollectorHeartbeatRepository : ICollectorHeartbeatRepository
{
private readonly CollectorHeartbeat _latest;
public FakeCollectorHeartbeatRepository(CollectorHeartbeat latest) { _latest = latest; }
public long Create(CollectorHeartbeat entity) => 1;
public CollectorHeartbeat GetLatest(string serviceId) => _latest;
public int DeleteBeforeDate(DateTime date) => 0;
}
public class FakeWindowsServiceChecker : IWindowsServiceChecker
{
private readonly ServiceStatusEnum _status;
public FakeWindowsServiceChecker(ServiceStatusEnum status) { _status = status; }
public ServiceStatusEnum GetServiceStatus(string serviceName) => _status;
public (bool, string) TryStartService(string serviceName, int timeoutSeconds) => (
_status == ServiceStatusEnum.NotInstalled ? false : true,
_status == ServiceStatusEnum.NotInstalled ? "NotInstalled" : "Started");
public (bool, string) TryStopService(string serviceName, int timeoutSeconds) => (
true, "Stopped");
}
public class FakeSysConfigRepository : ISysConfigRepository
{
public SysConfig GetByKey(string configKey) => new SysConfig { ConfigKey = configKey, ConfigValue = "300" };
public List<SysConfig> GetAll() => new List<SysConfig>();
public bool UpdateValue(int id, string value) => true;
}
[Collection("Database")]
public class DashboardServiceTests : IDisposable
{
private readonly DashboardService _service;
public DashboardServiceTests()
{
TestDb.TruncateAll();
_service = ServiceFactory.CreateDashboardService();
}
public void Dispose()
{
TestDb.TruncateAll();
}
[Fact]
public void GetCollectorStatus_With_NotInstalled_Service_Returns_NotInstalled_State()
{
// Arrange
var latest = new CollectorHeartbeat { Id = 1, ServiceId = "collector-service", Status = "running", UptimeSeconds = 120, LastCollectTime = DateTime.Now, CreatedAt = DateTime.Now };
var dashboardRepo = new FakeDashboardRepository();
var heartbeatRepo = new FakeCollectorHeartbeatRepository(latest);
var checker = new FakeWindowsServiceChecker(CncService.Interface.ServiceStatusEnum.NotInstalled);
var svc = new DashboardService(dashboardRepo, heartbeatRepo, new FakeSysConfigRepository(), checker);
// Act
var resultObj = svc.GetCollectorStatus();
var t = resultObj.GetType();
var statusProp = t.GetProperty("status");
var serviceStatusProp = t.GetProperty("serviceStatus");
var uptimeProp = t.GetProperty("uptimeSeconds");
var lastCollectTimeProp = t.GetProperty("lastCollectTime");
Assert.NotNull(statusProp);
Assert.NotNull(serviceStatusProp);
var statusVal = statusProp.GetValue(resultObj) as string;
var serviceStatusVal = serviceStatusProp.GetValue(resultObj) as string;
Assert.Equal("not_installed", statusVal);
Assert.Equal("NotInstalled", serviceStatusVal);
}
[Fact]
public void GetCollectorStatus_With_Running_Heartbeats_Returns_Running_State()
{
var latest = new CollectorHeartbeat { Id = 1, ServiceId = "collector-service", Status = "running", UptimeSeconds = 60, LastCollectTime = DateTime.Now, CreatedAt = DateTime.Now };
var dashboardRepo = new FakeDashboardRepository();
var heartbeatRepo = new FakeCollectorHeartbeatRepository(latest);
var checker = new FakeWindowsServiceChecker(CncService.Interface.ServiceStatusEnum.Running);
var svc = new DashboardService(dashboardRepo, heartbeatRepo, new FakeSysConfigRepository(), checker);
var resultObj = svc.GetCollectorStatus();
var t = resultObj.GetType();
var serviceStatusProp = t.GetProperty("serviceStatus");
var statusProp = t.GetProperty("status");
var serviceStatusVal = serviceStatusProp.GetValue(resultObj) as string;
var statusVal = statusProp.GetValue(resultObj) as string;
Assert.Equal("Running", serviceStatusVal);
Assert.Equal("running", statusVal);
}
[Fact]
public void GetCollectorStatus_With_Starting_ServiceStatus_Returns_Starting_State()
{
var latest = new CollectorHeartbeat { Id = 2, ServiceId = "collector-service", Status = "running", UptimeSeconds = 120, LastCollectTime = DateTime.Now, CreatedAt = DateTime.Now };
var dashboardRepo = new FakeDashboardRepository();
var heartbeatRepo = new FakeCollectorHeartbeatRepository(latest);
var checker = new FakeWindowsServiceChecker(CncService.Interface.ServiceStatusEnum.Starting);
var svc = new DashboardService(dashboardRepo, heartbeatRepo, new FakeSysConfigRepository(), checker);
var resultObj = svc.GetCollectorStatus();
var t = resultObj.GetType();
var serviceStatusProp = t.GetProperty("serviceStatus");
var statusProp = t.GetProperty("status");
var serviceStatusVal = serviceStatusProp.GetValue(resultObj) as string;
var statusVal = statusProp.GetValue(resultObj) as string;
Assert.Equal("Starting", serviceStatusVal);
Assert.Equal("running", statusVal);
}
// ======== GetProgramRank ========
[Fact]
public void GetProgramRank__()
{
var result = _service.GetProgramRank(null, null);
Assert.NotNull(result);
Assert.Empty(result);
}
[Fact]
public void GetProgramRank__()
{
// 插入测试数据
TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
VALUES ('测试地址', 'http://test', 1, 30, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES ('M001', '机床1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES ('M002', '机床2', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at)
VALUES (1, CURDATE(), 'O0001', NOW(), 0, 100, 100, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at)
VALUES (2, CURDATE(), 'O0001', NOW(), 0, 50, 50, 1, NOW(), NOW())");
var result = _service.GetProgramRank(DateTime.Today, DateTime.Today);
Assert.NotEmpty(result);
Assert.Equal("O0001", result[0].ProgramName);
Assert.Equal(150, result[0].TotalQuantity);
Assert.Equal(2, result[0].MachineCount);
Assert.Equal(1, result[0].Rank);
}
// ======== GetProgramDistribution ========
[Fact]
public void GetProgramDistribution__()
{
var result = _service.GetProgramDistribution(null, null);
Assert.NotNull(result);
Assert.Empty(result);
}
[Fact]
public void GetProgramDistribution__()
{
// 插入测试数据
TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
VALUES ('测试地址', 'http://test', 1, 30, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES ('M001', '机床1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at)
VALUES (1, CURDATE(), 'O0001', NOW(), 0, 80, 80, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_production_segment (machine_id, production_date, program_name, start_time, start_part_count, end_part_count, quantity, is_settled, created_at, updated_at)
VALUES (1, CURDATE(), 'O0002', NOW(), 0, 20, 20, 1, NOW(), NOW())");
var result = _service.GetProgramDistribution(DateTime.Today, DateTime.Today);
Assert.NotEmpty(result);
Assert.Equal(2, result.Count);
Assert.Equal("O0001", result[0].ProgramName);
Assert.Equal(80, result[0].TotalQuantity);
Assert.Equal(80m, result[0].Percentage);
Assert.Equal("O0002", result[1].ProgramName);
Assert.Equal(20, result[1].TotalQuantity);
Assert.Equal(20m, result[1].Percentage);
}
}
}