using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests.S7_1500; /// /// End-to-end coverage for the S7 driver's diagnostics surface against the python-snap7 /// S7-1500 simulator. The simulator runs the upstream Snap7 server which negotiates a /// fixed 240-byte PDU during the COTP handshake; this suite asserts the driver captures /// and surfaces that value through DriverHealth.Diagnostics["S7.NegotiatedPduSize"] /// so the Admin UI driver-diagnostics panel can render it. /// [Collection(Snap7ServerCollection.Name)] [Trait("Category", "Integration")] [Trait("Device", "S7_1500")] public sealed class S7_1500DiagnosticsTests(Snap7ServerFixture sim) { [Fact] public async Task Driver_exposes_negotiated_pdu_size_post_init() { if (sim.SkipReason is not null) Assert.Skip(sim.SkipReason); var options = S7_1500Profile.BuildOptions(sim.Host, sim.Port); await using var drv = new S7Driver(options, driverInstanceId: "s7-pdu-diag"); await drv.InitializeAsync("{}", TestContext.Current.CancellationToken); // Issue a read so BuildDiagnostics() flows into _health.Diagnostics through the // Healthy state-transition (the post-OpenAsync construction also seeds it, but we // exercise the read path too so the assertion is robust against future refactors // that move the seed point). var snapshots = await drv.ReadAsync( [S7_1500Profile.ProbeTag], TestContext.Current.CancellationToken); snapshots[0].StatusCode.ShouldBe(0u, "probe read must succeed before checking diagnostics"); var diagnostics = drv.GetHealth().DiagnosticsOrEmpty; diagnostics.ContainsKey("S7.NegotiatedPduSize").ShouldBeTrue( "S7 driver must surface negotiated PDU size as S7.NegotiatedPduSize"); diagnostics["S7.NegotiatedPduSize"].ShouldBeGreaterThan(0, "Snap7 negotiates a 240-byte PDU on every COTP handshake — anything ≤ 0 means the snapshot was missed"); } }