fix(driver-modbus-cli): resolve Low code-review findings (Driver.Modbus.Cli-003,004,005,006,007,008)
- Driver.Modbus.Cli-003: ModbusCommandBase.ValidateEndpoint rejects --port outside 1..65535, non-positive --timeout-ms, and --unit-id outside 1..247. - Driver.Modbus.Cli-004: wrapped SubscribeCommand's OnDataChange handler body in a try/catch (warn-and-swallow) and serialised the console write through a lock. - Driver.Modbus.Cli-005: Probe / Read / Write now catch the cancellation-during-init OperationCanceledException and print 'Cancelled.' instead of dumping a stack trace. - Driver.Modbus.Cli-006: ProbeCommand.ComputeVerdict derives the headline from BOTH the driver state and the probe snapshot's OPC UA quality class so the headline can't disagree with the wire result. - Driver.Modbus.Cli-007: docs/Driver.Modbus.Cli.md carries an explicit 'CLI scope' callout — the address-string grammar is a DriverConfig JSON feature; the CLI takes the structured triple only. - Driver.Modbus.Cli-008: pinned BuildOptions, ValidateEndpoint, the region-validation guards, ComputeVerdict, and the cancellation-during- initialize paths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
using CliFx.Infrastructure;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.Modbus.Cli.Commands;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.Cli.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Covers Driver.Modbus.Cli-005: <c>probe</c> / <c>read</c> / <c>write</c> must swallow
|
||||
/// <see cref="OperationCanceledException"/> so a Ctrl+C during InitializeAsync exits
|
||||
/// cleanly instead of dumping a full stack trace through CliFx. <c>SubscribeCommand</c>
|
||||
/// already handles this around its <c>Task.Delay</c>; these tests pin the same behaviour
|
||||
/// to the connect/read/write commands.
|
||||
/// The test pre-cancels the CliFx <see cref="FakeInMemoryConsole"/>; the driver's
|
||||
/// <c>ConnectAsync</c> observes the token via <c>Dns.GetHostAddressesAsync</c> and throws
|
||||
/// OCE before any socket I/O happens, so the test is hermetic — no real PLC needed.
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class CommandCancellationTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ProbeCommand_swallows_cancellation_during_initialize()
|
||||
{
|
||||
using var console = new FakeInMemoryConsole();
|
||||
console.RequestCancellation(); // simulate Ctrl+C before ExecuteAsync runs
|
||||
|
||||
var sut = new ProbeCommand { Host = "127.0.0.1" };
|
||||
|
||||
await Should.NotThrowAsync(async () => await sut.ExecuteAsync(console));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ReadCommand_swallows_cancellation_during_initialize()
|
||||
{
|
||||
using var console = new FakeInMemoryConsole();
|
||||
console.RequestCancellation();
|
||||
|
||||
var sut = new ReadCommand
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
Region = ModbusRegion.HoldingRegisters,
|
||||
Address = 0,
|
||||
DataType = ModbusDataType.UInt16,
|
||||
};
|
||||
|
||||
await Should.NotThrowAsync(async () => await sut.ExecuteAsync(console));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task WriteCommand_swallows_cancellation_during_initialize()
|
||||
{
|
||||
using var console = new FakeInMemoryConsole();
|
||||
console.RequestCancellation();
|
||||
|
||||
var sut = new WriteCommand
|
||||
{
|
||||
Host = "127.0.0.1",
|
||||
Region = ModbusRegion.HoldingRegisters,
|
||||
Address = 0,
|
||||
DataType = ModbusDataType.UInt16,
|
||||
Value = "42",
|
||||
};
|
||||
|
||||
await Should.NotThrowAsync(async () => await sut.ExecuteAsync(console));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user