@@ -0,0 +1,96 @@
|
||||
using System.IO;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests.S7_1500;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.S7.SymbolImport;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.S7.IntegrationTests.SymbolImport;
|
||||
|
||||
/// <summary>
|
||||
/// PR-S7-D3 / #301 — golden-fixture integration test for instance-DB / FB parameter
|
||||
/// resolution. Loads <c>Fixtures/sample_tia_export_with_fb_instance.csv</c>, materialises
|
||||
/// a driver-options object via <see cref="S7DriverFactoryExtensions.AddTiaCsvImport"/>,
|
||||
/// and exercises the runtime read path against the python-snap7 simulator using the
|
||||
/// resolved instance-DB addresses.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The fixture mixes three categories so a single import covers the full
|
||||
/// <c>DB type</c> column matrix:
|
||||
/// <list type="bullet">
|
||||
/// <item>Two global-DB tags (<c>DB type = Global DB</c>) — pre-existing D1 path.</item>
|
||||
/// <item>Five instance-DB tags (<c>DB type = Instance DB</c>) — new D3 path.</item>
|
||||
/// <item>One HMI-hidden row — must be filtered.</item>
|
||||
/// <item>One M-area probe (no <c>DB type</c>) — global by default.</item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The instance-DB tag addresses deliberately overlap with the snap7 seed offsets
|
||||
/// baked into <see cref="S7_1500Profile"/> so a successful round-trip proves the
|
||||
/// resolver normalises addresses identically to the global-DB path. The simulator
|
||||
/// doesn't know (or care) that a tag came from an FB-instance row — what we're
|
||||
/// testing is that the <em>importer</em> recognised it and the <em>driver</em>
|
||||
/// accepted the resolved address verbatim.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Auto-skips when no simulator is reachable (build-only on hosts without snap7).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Collection(Snap7ServerCollection.Name)]
|
||||
[Trait("Category", "Integration")]
|
||||
[Trait("Device", "S7_1500")]
|
||||
public sealed class InstanceDbImportIntegrationTests(Snap7ServerFixture sim)
|
||||
{
|
||||
private static string FixturePath(string name) =>
|
||||
Path.Combine(AppContext.BaseDirectory, "Fixtures", name);
|
||||
|
||||
[Fact]
|
||||
public async Task Driver_resolves_fb_instance_then_reads_seeded_member()
|
||||
{
|
||||
if (sim.SkipReason is not null) Assert.Skip(sim.SkipReason);
|
||||
|
||||
var baseOptions = new S7DriverOptions
|
||||
{
|
||||
Host = sim.Host,
|
||||
Port = sim.Port,
|
||||
CpuType = global::S7.Net.CpuType.S71500,
|
||||
Timeout = TimeSpan.FromSeconds(5),
|
||||
Probe = new S7ProbeOptions { Enabled = false },
|
||||
Tags = [],
|
||||
};
|
||||
|
||||
var options = baseOptions.AddTiaCsvImport(
|
||||
FixturePath("sample_tia_export_with_fb_instance.csv"),
|
||||
out var importResult);
|
||||
|
||||
// Fixture: 9 rows total = 1 probe + 2 global-DB + 5 instance-DB + 1 hidden.
|
||||
// Hidden filtered → SkippedCount = 1; everything else lands.
|
||||
importResult.ParsedCount.ShouldBe(8);
|
||||
importResult.SkippedCount.ShouldBe(1);
|
||||
importResult.InstanceDbCount.ShouldBe(5);
|
||||
importResult.UdtPlaceholderCount.ShouldBe(0);
|
||||
importResult.ErrorCount.ShouldBe(0);
|
||||
options.Tags.Count.ShouldBe(8);
|
||||
|
||||
await using var drv = new S7Driver(options, driverInstanceId: "s7-tia-import-fb");
|
||||
await drv.InitializeAsync("{}", TestContext.Current.CancellationToken);
|
||||
|
||||
// Read three resolved instance-DB members. Each address overlaps a snap7 seed in
|
||||
// S7_1500Profile, so a successful round-trip proves the resolver pointed the
|
||||
// driver at the right absolute byte offset.
|
||||
var snapshots = await drv.ReadAsync(
|
||||
["MotorFB_Inst.Speed", "MotorFB_Inst.Setpoint", "MotorFB_Inst.Enabled"],
|
||||
TestContext.Current.CancellationToken);
|
||||
|
||||
snapshots.Count.ShouldBe(3);
|
||||
foreach (var s in snapshots)
|
||||
s.StatusCode.ShouldBe(0u, "instance-DB resolved address must read end-to-end");
|
||||
|
||||
// Speed sits at DB1.DBW10 → SmokeI16Seed; Setpoint at DB1.DBD30 → SmokeF32Seed;
|
||||
// Enabled at DB1.DBX50.3 → SmokeBool.
|
||||
Convert.ToInt32(snapshots[0].Value).ShouldBe((int)S7_1500Profile.SmokeI16SeedValue);
|
||||
Convert.ToSingle(snapshots[1].Value).ShouldBe(S7_1500Profile.SmokeF32SeedValue, tolerance: 0.0001f);
|
||||
Convert.ToBoolean(snapshots[2].Value).ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user