using AxiOmron.PcbCheck.Models; using AxiOmron.PcbCheck.Options; using AxiOmron.PcbCheck.Services.Implementations; using AxiOmron.PcbCheck.Services.Interfaces; namespace AxiOmron.PcbCheck.Tests; /// /// 验证流程后台服务的 SFTP 启动探活行为。 /// public sealed class WorkflowHostedServiceTests { /// /// 启动探活失败时,不应抛出异常,且应写入运行态状态。 /// /// 异步测试任务。 [Fact] public async Task ProbeSftpOnStartupAsync_ShouldUpdateSnapshot_WhenConnectionFails() { var stateStore = new AppStateStore(); var service = new WorkflowHostedService( new FakePlcService(), new FakeScannerService(), new FakeSftpLookupService { TestOutcome = new SftpConnectionTestOutcome { IsSuccess = false, IsSystemError = true, StatusMessage = "启动探活失败" } }, new FakeAndonService(), stateStore, new AppConfig(), new FakeAppLogger()); await service.ProbeSftpOnStartupAsync(CancellationToken.None); Assert.Equal("异常", stateStore.GetSnapshot().SftpStatus); } private sealed class FakePlcService : IPlcService { public Task ForceReconnectAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task ReadSignalsAsync(CancellationToken cancellationToken) => Task.FromResult(new PlcSignalSnapshot()); public Task WriteStateAsync(PlcProcessState state, CancellationToken cancellationToken) => Task.CompletedTask; } private sealed class FakeScannerService : IScannerService { public Task ForceReconnectAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task TestConnectionAsync(CancellationToken cancellationToken) => Task.FromResult(true); public Task TriggerScanAsync(CancellationToken cancellationToken) => Task.FromResult(new ScanOperationResult()); } private sealed class FakeSftpLookupService : ISftpLookupService { public SftpConnectionTestOutcome TestOutcome { get; set; } = new(); public Task CheckFileAsync(string barcode, CancellationToken cancellationToken) => Task.FromResult(new SftpCheckOutcome()); public Task TestConnectionAsync(SftpOptions? options, CancellationToken cancellationToken) { return Task.FromResult(TestOutcome); } } private sealed class FakeAndonService : IAndonService { public Task RaiseAlarmAsync(AndonAlarmRequest request, CancellationToken cancellationToken) => Task.FromResult(new AndonOperationResult()); public Task TestAsync(CancellationToken cancellationToken) => Task.FromResult(new AndonOperationResult()); } private sealed class FakeAppLogger : IAppLogger { public void LogError(string message, bool showInUi = false, params object?[] args) { } public void LogError(Exception exception, string message, bool showInUi = false, params object?[] args) { } public void LogInformation(string message, bool showInUi = false, params object?[] args) { } public void LogWarning(string message, bool showInUi = false, params object?[] args) { } public void LogWarning(Exception exception, string message, bool showInUi = false, params object?[] args) { } } }