✨ feat(*): 重构PCB放行流程并接入双扫码校验
- 将流程改为 OMRON FINS + TCP 双扫码 + SFTP 文件校验 - 新增文件校验与扫码结果汇总实现,补充对应单测 - 同步更新流程设计文档、配置和系统设置页面文案
This commit is contained in:
@@ -7,7 +7,7 @@ using Xunit;
|
||||
namespace AxiOmron.PcbCheck.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// 验证流程后台服务的 SFTP 启动探活行为。
|
||||
/// 验证流程后台服务的文件校验启动探活行为。
|
||||
/// </summary>
|
||||
public sealed class WorkflowHostedServiceTests
|
||||
{
|
||||
@@ -16,15 +16,15 @@ public sealed class WorkflowHostedServiceTests
|
||||
/// </summary>
|
||||
/// <returns>异步测试任务。</returns>
|
||||
[Fact]
|
||||
public async Task ProbeSftpOnStartupAsync_ShouldUpdateSnapshot_WhenConnectionFails()
|
||||
public async Task ProbeFileCheckOnStartupAsync_ShouldUpdateSnapshot_WhenConnectionFails()
|
||||
{
|
||||
var stateStore = new AppStateStore();
|
||||
var service = new WorkflowHostedService(
|
||||
new FakePlcService(),
|
||||
new FakeScannerService(),
|
||||
new FakeSftpLookupService
|
||||
new FakeFileCheckService
|
||||
{
|
||||
TestOutcome = new SftpConnectionTestOutcome
|
||||
TestOutcome = new FileCheckTestOutcome
|
||||
{
|
||||
IsSuccess = false,
|
||||
IsSystemError = true,
|
||||
@@ -36,7 +36,7 @@ public sealed class WorkflowHostedServiceTests
|
||||
new AppConfig(),
|
||||
new FakeAppLogger<WorkflowHostedService>());
|
||||
|
||||
await service.ProbeSftpOnStartupAsync(CancellationToken.None);
|
||||
await service.ProbeFileCheckOnStartupAsync(CancellationToken.None);
|
||||
|
||||
Assert.Equal("异常", stateStore.GetSnapshot().SftpStatus);
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public sealed class WorkflowHostedServiceTests
|
||||
var service = new WorkflowHostedService(
|
||||
plcService,
|
||||
new FakeScannerService(),
|
||||
new FakeSftpLookupService(),
|
||||
new FakeFileCheckService(),
|
||||
new FakeAndonService(),
|
||||
stateStore,
|
||||
new AppConfig(),
|
||||
@@ -78,7 +78,7 @@ public sealed class WorkflowHostedServiceTests
|
||||
var service = new WorkflowHostedService(
|
||||
new FailingPlcService(),
|
||||
new FakeScannerService(),
|
||||
new FakeSftpLookupService(),
|
||||
new FakeFileCheckService(),
|
||||
new FakeAndonService(),
|
||||
stateStore,
|
||||
new AppConfig(),
|
||||
@@ -111,9 +111,9 @@ public sealed class WorkflowHostedServiceTests
|
||||
Barcode = "PCB-001"
|
||||
}
|
||||
};
|
||||
var sftpService = new FakeSftpLookupService
|
||||
var fileCheckService = new FakeFileCheckService
|
||||
{
|
||||
CheckOutcome = new SftpCheckOutcome
|
||||
CheckOutcome = new FileCheckOutcome
|
||||
{
|
||||
Exists = true,
|
||||
ConnectionSucceeded = true,
|
||||
@@ -124,7 +124,7 @@ public sealed class WorkflowHostedServiceTests
|
||||
var service = new WorkflowHostedService(
|
||||
plcService,
|
||||
scannerService,
|
||||
sftpService,
|
||||
fileCheckService,
|
||||
new FakeAndonService(),
|
||||
stateStore,
|
||||
new AppConfig
|
||||
@@ -135,11 +135,7 @@ public sealed class WorkflowHostedServiceTests
|
||||
ReleaseAckTimeoutMs = 100,
|
||||
ReleasePulseMs = 10
|
||||
},
|
||||
Scanner = new ScannerOptions
|
||||
{
|
||||
MaxScanAttempts = 1
|
||||
},
|
||||
Sftp = new SftpOptions
|
||||
FileCheck = new FileCheckOptions
|
||||
{
|
||||
MaxRetryCount = 0
|
||||
}
|
||||
@@ -161,6 +157,69 @@ public sealed class WorkflowHostedServiceTests
|
||||
Assert.All(snapshot.PlcMonitorItems, item => Assert.NotEqual(default, item.LastUpdatedAt));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 双扫码汇总后,应使用汇总条码继续执行统一文件校验。
|
||||
/// </summary>
|
||||
/// <returns>异步测试任务。</returns>
|
||||
[Fact]
|
||||
public async Task ExecuteAsync_ShouldCheckFileWithMergedBarcode_WhenScannerServiceReturnsMergedBarcode()
|
||||
{
|
||||
var stateStore = new AppStateStore();
|
||||
var plcService = new SequencedPlcService(new[]
|
||||
{
|
||||
new PlcSignalSnapshot { PcbArrived = true, PlcAckRelease = true },
|
||||
new PlcSignalSnapshot { PcbArrived = false, PlcAckRelease = true }
|
||||
});
|
||||
var scannerService = new CountingScannerService
|
||||
{
|
||||
Result = new ScanOperationResult
|
||||
{
|
||||
IsSuccess = true,
|
||||
DeviceConnected = true,
|
||||
Barcode = "PCB-MERGED",
|
||||
RawMessage = "使用扫码枪2"
|
||||
}
|
||||
};
|
||||
var fileCheckService = new FakeFileCheckService
|
||||
{
|
||||
CheckOutcome = new FileCheckOutcome
|
||||
{
|
||||
Exists = true,
|
||||
ConnectionSucceeded = true,
|
||||
MatchedFilePath = "/pcb/PCB-MERGED.txt"
|
||||
}
|
||||
};
|
||||
|
||||
var service = new WorkflowHostedService(
|
||||
plcService,
|
||||
scannerService,
|
||||
fileCheckService,
|
||||
new FakeAndonService(),
|
||||
stateStore,
|
||||
new AppConfig
|
||||
{
|
||||
Plc = new PlcOptions
|
||||
{
|
||||
PollIntervalMs = 20,
|
||||
ReleaseAckTimeoutMs = 100,
|
||||
ReleasePulseMs = 10
|
||||
},
|
||||
FileCheck = new FileCheckOptions
|
||||
{
|
||||
MaxRetryCount = 0
|
||||
}
|
||||
},
|
||||
new FakeAppLogger<WorkflowHostedService>());
|
||||
|
||||
await service.StartAsync(CancellationToken.None);
|
||||
await Task.Delay(200);
|
||||
await service.StopAsync(CancellationToken.None);
|
||||
|
||||
Assert.Equal(1, scannerService.TriggerCount);
|
||||
Assert.Equal("PCB-MERGED", fileCheckService.LastBarcode);
|
||||
Assert.Contains(plcService.WrittenStates, state => state.ResultCode == (ushort)WorkflowResultCode.Passed);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当到位信号保持高电平时,即使执行软件复位,也不应被视为新的上升沿重复触发流程。
|
||||
/// </summary>
|
||||
@@ -189,9 +248,9 @@ public sealed class WorkflowHostedServiceTests
|
||||
var service = new WorkflowHostedService(
|
||||
plcService,
|
||||
scannerService,
|
||||
new FakeSftpLookupService
|
||||
new FakeFileCheckService
|
||||
{
|
||||
CheckOutcome = new SftpCheckOutcome
|
||||
CheckOutcome = new FileCheckOutcome
|
||||
{
|
||||
Exists = true,
|
||||
ConnectionSucceeded = true,
|
||||
@@ -208,11 +267,7 @@ public sealed class WorkflowHostedServiceTests
|
||||
ReleaseAckTimeoutMs = 100,
|
||||
ReleasePulseMs = 10
|
||||
},
|
||||
Scanner = new ScannerOptions
|
||||
{
|
||||
MaxScanAttempts = 1
|
||||
},
|
||||
Sftp = new SftpOptions
|
||||
FileCheck = new FileCheckOptions
|
||||
{
|
||||
MaxRetryCount = 0
|
||||
}
|
||||
@@ -266,7 +321,7 @@ public sealed class WorkflowHostedServiceTests
|
||||
var service = new WorkflowHostedService(
|
||||
new FakePlcService(),
|
||||
new FakeScannerService(),
|
||||
new FakeSftpLookupService(),
|
||||
new FakeFileCheckService(),
|
||||
new FakeAndonService(),
|
||||
stateStore,
|
||||
new AppConfig
|
||||
@@ -321,9 +376,9 @@ public sealed class WorkflowHostedServiceTests
|
||||
var service = new WorkflowHostedService(
|
||||
plcService,
|
||||
scannerService,
|
||||
new FakeSftpLookupService
|
||||
new FakeFileCheckService
|
||||
{
|
||||
CheckOutcome = new SftpCheckOutcome
|
||||
CheckOutcome = new FileCheckOutcome
|
||||
{
|
||||
Exists = true,
|
||||
ConnectionSucceeded = true,
|
||||
@@ -340,11 +395,7 @@ public sealed class WorkflowHostedServiceTests
|
||||
ReleaseAckTimeoutMs = 100,
|
||||
ReleasePulseMs = 10
|
||||
},
|
||||
Scanner = new ScannerOptions
|
||||
{
|
||||
MaxScanAttempts = 1
|
||||
},
|
||||
Sftp = new SftpOptions
|
||||
FileCheck = new FileCheckOptions
|
||||
{
|
||||
MaxRetryCount = 0
|
||||
}
|
||||
@@ -504,15 +555,21 @@ public sealed class WorkflowHostedServiceTests
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class FakeSftpLookupService : ISftpLookupService
|
||||
private sealed class FakeFileCheckService : IFileCheckService
|
||||
{
|
||||
public SftpConnectionTestOutcome TestOutcome { get; set; } = new();
|
||||
public FileCheckTestOutcome TestOutcome { get; set; } = new();
|
||||
|
||||
public SftpCheckOutcome CheckOutcome { get; set; } = new();
|
||||
public FileCheckOutcome CheckOutcome { get; set; } = new();
|
||||
|
||||
public Task<SftpCheckOutcome> CheckFileAsync(string barcode, CancellationToken cancellationToken) => Task.FromResult(CheckOutcome);
|
||||
public string LastBarcode { get; private set; } = string.Empty;
|
||||
|
||||
public Task<SftpConnectionTestOutcome> TestConnectionAsync(SftpOptions? options, CancellationToken cancellationToken)
|
||||
public Task<FileCheckOutcome> CheckFileAsync(string barcode, CancellationToken cancellationToken)
|
||||
{
|
||||
LastBarcode = barcode;
|
||||
return Task.FromResult(CheckOutcome);
|
||||
}
|
||||
|
||||
public Task<FileCheckTestOutcome> TestConnectionAsync(AppConfig? config, CancellationToken cancellationToken)
|
||||
{
|
||||
return Task.FromResult(TestOutcome);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user