97 lines
4.4 KiB
C#
97 lines
4.4 KiB
C#
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();
|
|
}
|
|
}
|