using System.Net.Sockets; using NModbus; using Xunit; namespace Mbproxy.Tests.Sim; /// /// End-to-end smoke tests that verify the pymodbus DL205 simulator is reachable and /// serves the expected seeded register values from DL260/dl205.json. /// /// /// All three tests call when /// is non-null (Python or pymodbus /// unavailable). This is the expected "green" outcome on machines without Python. /// [Collection(nameof(DL205SimulatorCollection))] [Trait("Category", "E2E")] public sealed class SimulatorSmokeTests { private readonly DL205SimulatorFixture _sim; public SimulatorSmokeTests(DL205SimulatorFixture sim) { _sim = sim; } /// /// Verifies that the simulator process is running and accepts a plain TCP /// connection on its allocated port. /// [Fact(Timeout = 5_000)] public async Task Simulator_AcceptsTcpConnection() { if (_sim.SkipReason is not null) Assert.Skip(_sim.SkipReason); using var client = new TcpClient(); await client.ConnectAsync(_sim.Host, _sim.Port, TestContext.Current.CancellationToken); Assert.True(client.Connected, "TcpClient should be connected to the simulator."); } /// /// Reads holding register 0 via FC03 and expects the DL205 marker value /// 0xCAFE (51966 decimal). This proves that the dl205.json profile is /// actually loaded — a bare pymodbus server with no profile returns 0. /// [Fact(Timeout = 5_000)] public async Task Simulator_FC03_ReturnsSeededValue_AtHR0_0xCAFE() { if (_sim.SkipReason is not null) Assert.Skip(_sim.SkipReason); using var client = new TcpClient(); await client.ConnectAsync(_sim.Host, _sim.Port, TestContext.Current.CancellationToken); var factory = new ModbusFactory(); var master = factory.CreateMaster(client); // FC03: read 1 holding register at address 0, unit ID 1. ushort[] registers = master.ReadHoldingRegisters(slaveAddress: 1, startAddress: 0, numberOfPoints: 1); Assert.Equal(0xCAFE, registers[0]); } /// /// Reads holding register 1072 via FC03 and expects raw BCD value /// 0x1234 (4660 decimal). This register represents decimal 1234 stored as /// BCD nibbles. Phase 04's e2e test will read the same register through the proxy /// and assert binary 1234 — proving the proxy rewrote the response. /// [Fact(Timeout = 5_000)] public async Task Simulator_FC03_ReturnsBCD_RawValueAtHR1072_0x1234() { if (_sim.SkipReason is not null) Assert.Skip(_sim.SkipReason); using var client = new TcpClient(); await client.ConnectAsync(_sim.Host, _sim.Port, TestContext.Current.CancellationToken); var factory = new ModbusFactory(); var master = factory.CreateMaster(client); // FC03: read 1 holding register at address 1072, unit ID 1. // dl205.json seeds: addr 1072, value 4660 (= 0x1234). ushort[] registers = master.ReadHoldingRegisters(slaveAddress: 1, startAddress: 1072, numberOfPoints: 1); Assert.Equal(0x1234, registers[0]); // raw BCD nibbles, NOT binary 1234 } }