using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests.S7_1500; /// /// PR-S7-C5 — integration coverage for the post-OpenAsync pre-flight /// PUT/GET enablement probe. Snap7 always allows reads (no PUT/GET gating /// in the simulator), so the integration scope is limited to the happy /// path: pre-flight succeeds against the seeded MW0/DBW0 fingerprint and /// the driver reaches . The "PUT/GET /// disabled" failure path is unit-tested via /// S7PreflightClassifier and documented as a follow-up live-firmware /// test in docs/drivers/S7-Test-Fixture.md. /// [Collection(Snap7ServerCollection.Name)] [Trait("Category", "Integration")] [Trait("Device", "S7_1500")] public sealed class S7_1500PreflightTests(Snap7ServerFixture sim) { [Fact] public async Task Driver_preflight_passes_when_probe_address_seeded() { if (sim.SkipReason is not null) Assert.Skip(sim.SkipReason); // Use the standard S7-1500 profile — DB1.DBW0 / DB1.DBW10 / etc are seeded // by the snap7 profile so the default MW0 probe (or DB1.DBW0 fallback) // exists at read time. var options = S7_1500Profile.BuildOptions(sim.Host, sim.Port); // Override the probe loop knob set by S7_1500Profile: the loop stays // disabled, but Probe.ProbeAddress + SkipPreflight are what RunPreflightAsync // consults. ProbeAddress defaults to MW0 which python-snap7 zeros at startup; // any successful read (zeros included) satisfies the pre-flight. var preflightOptions = new S7DriverOptions { Host = options.Host, Port = options.Port, CpuType = options.CpuType, Rack = options.Rack, Slot = options.Slot, Timeout = options.Timeout, Tags = options.Tags, // ProbeAddress = "MW0" (default); SkipPreflight = false (default). // Background probe loop disabled to avoid mailbox contention with the test. Probe = new S7ProbeOptions { Enabled = false }, }; await using var drv = new S7Driver(preflightOptions, driverInstanceId: "s7-preflight-pass"); await drv.InitializeAsync("{}", TestContext.Current.CancellationToken); // If pre-flight tripped the typed exception, InitializeAsync would have thrown // before reaching this line. Healthy state proves the probe succeeded. drv.GetHealth().State.ShouldBe(DriverState.Healthy, "pre-flight probe must succeed against the seeded snap7 fingerprint"); } [Fact] public async Task Driver_preflight_skipped_when_SkipPreflight_set() { if (sim.SkipReason is not null) Assert.Skip(sim.SkipReason); // Skipping the pre-flight is opt-in. The driver must still reach Healthy state // because the connect path itself succeeds; the only thing different is that no // probe read fires before _health flips. var options = S7_1500Profile.BuildOptions(sim.Host, sim.Port); var skipOptions = new S7DriverOptions { Host = options.Host, Port = options.Port, CpuType = options.CpuType, Rack = options.Rack, Slot = options.Slot, Timeout = options.Timeout, Tags = options.Tags, Probe = new S7ProbeOptions { Enabled = false, SkipPreflight = true }, }; await using var drv = new S7Driver(skipOptions, driverInstanceId: "s7-preflight-skipped"); await drv.InitializeAsync("{}", TestContext.Current.CancellationToken); drv.GetHealth().State.ShouldBe(DriverState.Healthy); } }