1e26b9ab58
Rename S7EquipmentTagParser -> S7TagDefinitionFactory; TryParse(reference)
-> FromTagConfig(tagConfig, rawPath, out def) (drops the leading-{ heuristic,
keys the def by RawPath, adds inverse ToTagConfig). Replace S7DriverOptions.Tags
(pre-declared S7TagDefinition list) with RawTags (IReadOnlyList<RawTagEntry>);
the driver builds its RawPath->def table from RawTags at Initialize via the
factory (skip+log on miss), resolver is byName-only, DiscoverAsync + init guards
+ address pre-parse now run off that table. Factory retires the pre-declared DTO
tag path (RawTags binding only). Cli BuildOptions serialises typed defs to
RawTagEntry. Tests migrated to a S7RawTags helper + FromTagConfig; parser test
files renamed. Coordinator's EquipmentTagConfigInspector S7 rename left to Wave-B
coordinator; Driver.S7.IntegrationTests (Docker-gated) left red per scope.
Driver.S7 + Cli build green; Driver.S7.Tests 264/264, S7.Cli.Tests 49/49.
58 lines
2.8 KiB
C#
58 lines
2.8 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()
|
|
{
|
|
// Bad address at init time must throw; the alternative (deferring the parse to the
|
|
// first read) would surface the config bug as BadInternalError on every subsequent
|
|
// Read which is impossible for an operator to diagnose from the OPC UA client.
|
|
var opts = new S7DriverOptions
|
|
{
|
|
Host = "192.0.2.1", // reserved — will never complete TCP handshake
|
|
Timeout = TimeSpan.FromMilliseconds(250),
|
|
RawTags = S7RawTags.Entries(new S7TagDefinition("BadTag", "NOT-AN-S7-ADDRESS", S7DataType.Int16)),
|
|
};
|
|
using var drv = new S7Driver(opts, "s7-bad-tag");
|
|
|
|
// Either the TCP connect fails first (Exception) or the parser fails (FormatException)
|
|
// — both are acceptable since both are init-time fail-fast. What matters is that we
|
|
// don't return a "healthy" driver with a latent bad tag.
|
|
await Should.ThrowAsync<Exception>(async () =>
|
|
await drv.InitializeAsync("{}", TestContext.Current.CancellationToken));
|
|
}
|
|
|
|
/// <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));
|
|
}
|
|
}
|