87a7414df7
The init-time tag guards THREW: one mis-authored tag (DB1.DBZ0, DB1.DBW0 typed Float64, T5 typed Int32, a writable Bool array) faulted the whole driver and the actor retried the same init every 10 s forever, darkening every tag on the PLC. Neither the editor nor the deploy gate checked any of it. - S7AddressParser moves to S7.Contracts (same namespace) and a new S7TagShapeRules there is the single authority on servable shapes. - S7TagDefinitionFactory.FromTagConfig applies it, so the AdminUI editor, the deploy gate (Inspect, with the specific reason) and the driver init refuse the same tags. Init now skips a refused tag (ISkippedTagReporter) instead of throwing; the throwing RejectUnsupportedTagConfigs is gone. - New rules on top of the old guards: a narrow type at the wrong access width (every read failed) and a Bool array not starting at bit 0 (U4: DB1.DBX0.3 silently read bit 0 of bytes 0..n). - AdminUI test fixtures that used addresses the driver could never serve (DB1.DBS0, a browse "SomeAddress", Int32/Float32 on DBW) now use real ones. Refs #742 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
47 lines
2.2 KiB
C#
47 lines
2.2 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Tests;
|
|
|
|
/// <summary>
|
|
/// Unit tests for <see cref="S7Driver"/>'s <c>IReadable</c>/<c>IWritable</c> surface
|
|
/// that don't require a live PLC — covers error paths (not-initialized, unknown tag,
|
|
/// read-only write rejection, unsupported data types). Wire-level round-trip tests
|
|
/// against a live S7 or a mock-server land in a follow-up PR since S7.Net doesn't ship
|
|
/// an in-process fake and an adequate mock is non-trivial.
|
|
/// </summary>
|
|
[Trait("Category", "Unit")]
|
|
public sealed class S7DriverReadWriteTests
|
|
{
|
|
/// <summary>Verifies that initialization rejects invalid tag addresses and fails fast.</summary>
|
|
[Fact]
|
|
public async Task Initialize_rejects_invalid_tag_address_and_fails_fast()
|
|
{
|
|
// A bad address is refused PER TAG at every gate (mapper/editor, deploy gate, driver init):
|
|
// it reads BadNodeIdUnknown while its neighbours keep working. It used to throw at init and
|
|
// fault every tag on the PLC, with the actor retrying the same init every 10 s forever.
|
|
await S7TagSkipAssert.RefusedPerTagAsync(
|
|
new S7TagDefinition("BadTag", "NOT-AN-S7-ADDRESS", S7DataType.Int16), "does not parse");
|
|
}
|
|
|
|
/// <summary>Verifies that ReadAsync without initialize throws InvalidOperationException.</summary>
|
|
[Fact]
|
|
public async Task ReadAsync_without_initialize_throws_InvalidOperationException()
|
|
{
|
|
using var drv = new S7Driver(new S7DriverOptions { Host = "192.0.2.1" }, "s7-uninit");
|
|
await Should.ThrowAsync<InvalidOperationException>(async () =>
|
|
await drv.ReadAsync(["Any"], TestContext.Current.CancellationToken));
|
|
}
|
|
|
|
/// <summary>Verifies that WriteAsync without initialize throws InvalidOperationException.</summary>
|
|
[Fact]
|
|
public async Task WriteAsync_without_initialize_throws_InvalidOperationException()
|
|
{
|
|
using var drv = new S7Driver(new S7DriverOptions { Host = "192.0.2.1" }, "s7-uninit");
|
|
await Should.ThrowAsync<InvalidOperationException>(async () =>
|
|
await drv.WriteAsync(
|
|
[new(FullReference: "Any", Value: (short)0)],
|
|
TestContext.Current.CancellationToken));
|
|
}
|
|
}
|