Files
lmxopcua/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests/S7_1500/S7_1500ArrayWriteTests.cs
T
Joseph Doherty e77bca385a fix(galaxy,s7): R2 review minors — subscribe-once deadline, probe vs backoff, write-fault ownership, null array elements, write opt-in
- Galaxy: deadline bounds the wait, not the subscribe RPC; BadTimeout for all tags and late handles unsubscribed; doc comment relocated
- S7: probe connect runs on the connect deadline so a timeout opens the backoff window
- S7: a successful write only retires a Faulted the write side owns
- S7: null array elements rejected (BadTypeMismatch); multi-PDU array writes documented non-atomic
- S7 integration: array write test gated on S7_SIM_ALLOW_WRITES=1

Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
2026-10-08 07:31:22 -04:00

57 lines
2.5 KiB
C#

using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
namespace ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests.S7_1500;
/// <summary>
/// #610 item 2 (S7-016): array write round trip against the python-snap7 S7-1500 profile. Skips
/// cleanly when the sim is absent. Uses DB1 bytes 700+ (the profile's 1024-byte DB1 has no seed
/// there), so the writes cannot disturb another test's seeds. Writes also require
/// <c>S7_SIM_ALLOW_WRITES=1</c>.
/// </summary>
[Collection(Snap7ServerCollection.Name)]
[Trait("Category", "Integration")]
[Trait("Device", "S7_1500")]
public sealed class S7_1500ArrayWriteTests(Snap7ServerFixture sim)
{
private static S7DriverOptions Options(string host, int port) => new()
{
Host = host,
Port = port,
CpuType = S7CpuType.S71500,
Rack = 0,
Slot = 0,
Timeout = TimeSpan.FromSeconds(5),
Probe = new S7ProbeOptions { Enabled = false },
RawTags = S7RawTags.Entries(
new S7TagDefinition("I16Arr", "DB1.DBW700", S7DataType.Int16, Writable: true, ArrayCount: 4),
new S7TagDefinition("F32Arr", "DB1.DBD720", S7DataType.Float32, Writable: true, ArrayCount: 3)),
};
/// <summary>Writes a non-trivial Int16[4] and Float32[3], then reads each back element-for-element.</summary>
[Fact]
public async Task Array_write_then_read_round_trips_through_real_S7comm()
{
if (sim.SkipReason is not null) Assert.Skip(sim.SkipReason);
// S7_SIM_ENDPOINT may point at a real CPU; writing needs an explicit opt-in (simulator runs only).
if (Environment.GetEnvironmentVariable("S7_SIM_ALLOW_WRITES") != "1")
Assert.Skip("Write test: set S7_SIM_ALLOW_WRITES=1 to allow writes to the endpoint under test (simulator only).");
await using var drv = new S7Driver(Options(sim.Host, sim.Port), "s7-arr-write");
await drv.InitializeAsync("{}", TestContext.Current.CancellationToken);
var i16 = new short[] { 111, -222, 3333, -4444 };
var f32 = new[] { 1.5f, -2.25f, 1234.5f };
var res = await drv.WriteAsync(
[new WriteRequest("I16Arr", i16), new WriteRequest("F32Arr", f32)],
TestContext.Current.CancellationToken);
res.Select(r => r.StatusCode).ShouldAllBe(c => c == 0u);
var read = await drv.ReadAsync(["I16Arr", "F32Arr"], TestContext.Current.CancellationToken);
read.Select(r => r.StatusCode).ShouldAllBe(c => c == 0u);
((short[])read[0].Value!).ShouldBe(i16);
((float[])read[1].Value!).ShouldBe(f32);
}
}