84 lines
3.9 KiB
C#
84 lines
3.9 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-D1 / #299 — golden-fixture integration test. Loads the canonical TIA Portal
|
|
/// CSV export shipped under <c>Fixtures/sample_tia_export.csv</c>, materialises a
|
|
/// driver-options object via <c>AddTiaCsvImport</c>, then exercises the runtime read
|
|
/// path against the python-snap7 simulator.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// The fixture's address layout (<c>%MW0</c>, <c>%DB1.DBW10</c>, <c>%DB1.DBD20</c>,
|
|
/// <c>%DB1.DBD30</c>, <c>%DB1.DBX50.3</c>) is deliberately aligned with the seed
|
|
/// offsets baked into the snap7 S7-1500 profile (<see cref="S7_1500Profile"/>) so
|
|
/// a successful round-trip proves the importer's address normalisation lands at
|
|
/// exactly the offsets the simulator seeds — a regression in <c>%</c>-stripping or
|
|
/// decimal-comma rewriting surfaces here as a read-mismatch, not a flaky timeout.
|
|
/// </para>
|
|
/// <para>
|
|
/// The test is build-only by default (the assertions run only when the simulator
|
|
/// fixture reports <c>SkipReason is null</c>) — local dev invokes it with snap7
|
|
/// running; CI relies on the fixture's auto-skip when no simulator is reachable.
|
|
/// </para>
|
|
/// </remarks>
|
|
[Collection(Snap7ServerCollection.Name)]
|
|
[Trait("Category", "Integration")]
|
|
[Trait("Device", "S7_1500")]
|
|
public sealed class TiaCsvImportIntegrationTests(Snap7ServerFixture sim)
|
|
{
|
|
private static string FixturePath(string name) =>
|
|
Path.Combine(AppContext.BaseDirectory, "Fixtures", name);
|
|
|
|
[Fact]
|
|
public async Task Driver_imports_csv_then_reads_seeded_tags()
|
|
{
|
|
if (sim.SkipReason is not null) Assert.Skip(sim.SkipReason);
|
|
|
|
// Start with an empty options object pinned at the simulator's endpoint, then
|
|
// layer the fixture CSV's tags on top via AddTiaCsvImport. The merge keeps the
|
|
// endpoint config (Host, Port, CpuType) untouched and adds the imported tags.
|
|
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.csv"), out var importResult);
|
|
|
|
// Fixture has 8 rows: 6 importable + 1 UDT placeholder + 1 HMI-hidden (skipped).
|
|
importResult.ParsedCount.ShouldBe(7);
|
|
importResult.SkippedCount.ShouldBe(1);
|
|
importResult.UdtPlaceholderCount.ShouldBe(1);
|
|
options.Tags.Count.ShouldBe(7);
|
|
|
|
await using var drv = new S7Driver(options, driverInstanceId: "s7-tia-import");
|
|
await drv.InitializeAsync("{}", TestContext.Current.CancellationToken);
|
|
|
|
// Read the seed-aligned tags by their browse-name references. ProbeWord at MW0
|
|
// doesn't have a snap7 seed (the simulator profile seeds DB1.DBW0 instead), so
|
|
// we focus on the DB-anchored tags whose offsets match the S7_1500Profile seeds.
|
|
var snapshots = await drv.ReadAsync(
|
|
["SmokeI16", "SmokeI32", "SmokeF32", "SmokeBool"],
|
|
TestContext.Current.CancellationToken);
|
|
|
|
snapshots.Count.ShouldBe(4);
|
|
foreach (var s in snapshots) s.StatusCode.ShouldBe(0u, "imported-then-read must succeed end-to-end");
|
|
|
|
Convert.ToInt32(snapshots[0].Value).ShouldBe((int)S7_1500Profile.SmokeI16SeedValue);
|
|
Convert.ToInt32(snapshots[1].Value).ShouldBe(S7_1500Profile.SmokeI32SeedValue);
|
|
Convert.ToSingle(snapshots[2].Value).ShouldBe(S7_1500Profile.SmokeF32SeedValue, tolerance: 0.0001f);
|
|
Convert.ToBoolean(snapshots[3].Value).ShouldBeTrue();
|
|
}
|
|
}
|