Files
lmxopcua/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/HistorianWonderwareDriverPageFormSerializationTests.cs
T
Joseph Doherty c4086c243c fix(adminui): S7 typed page no longer wipes Tags on save
- S7DriverPage.FormModel now preserves Tags through Form ↔ Options
  translation (was hard-coding Tags = [] on every save, silently
  destroying any tag list that operators had configured).
- Add FormModel_RoundTrip tests for OpcUaClient and Historian
  mirror classes — both were translating Options ↔ form-model
  entirely untested.
- Surface S7 Tags in the round-trip test so this regression
  can't reach merge again.
2026-05-28 10:06:43 -04:00

113 lines
4.1 KiB
C#

using System.Text.Json;
using System.Text.Json.Serialization;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Pages.Clusters.Drivers;
using ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Client;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests;
public sealed class HistorianWonderwareDriverPageFormSerializationTests
{
private static readonly JsonSerializerOptions _opts = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = false,
};
[Fact]
public void RoundTrip_PreservesKnownFields()
{
var original = new WonderwareHistorianClientOptions(
PipeName: "otopcua-historian-prod",
SharedSecret: "t0ps3cr3t",
PeerName: "OtOpcUa-Primary",
ConnectTimeout: TimeSpan.FromSeconds(20),
CallTimeout: TimeSpan.FromSeconds(60))
{
ProbeTimeoutSeconds = 25,
};
var json = JsonSerializer.Serialize(original, _opts);
var back = JsonSerializer.Deserialize<WonderwareHistorianClientOptions>(json, _opts);
back.ShouldNotBeNull();
back.PipeName.ShouldBe("otopcua-historian-prod");
back.SharedSecret.ShouldBe("t0ps3cr3t");
back.PeerName.ShouldBe("OtOpcUa-Primary");
back.ConnectTimeout.ShouldBe(TimeSpan.FromSeconds(20));
back.CallTimeout.ShouldBe(TimeSpan.FromSeconds(60));
back.EffectiveConnectTimeout.ShouldBe(TimeSpan.FromSeconds(20));
back.EffectiveCallTimeout.ShouldBe(TimeSpan.FromSeconds(60));
back.ProbeTimeoutSeconds.ShouldBe(25);
}
[Fact]
public void RoundTrip_NullTimeouts_UsesDefaults()
{
var original = new WonderwareHistorianClientOptions(
PipeName: "otopcua-historian",
SharedSecret: "secret");
var json = JsonSerializer.Serialize(original, _opts);
var back = JsonSerializer.Deserialize<WonderwareHistorianClientOptions>(json, _opts);
back.ShouldNotBeNull();
back.ConnectTimeout.ShouldBeNull();
back.CallTimeout.ShouldBeNull();
back.EffectiveConnectTimeout.ShouldBe(TimeSpan.FromSeconds(10));
back.EffectiveCallTimeout.ShouldBe(TimeSpan.FromSeconds(30));
}
[Fact]
public void Deserialize_DropsUnknownFields()
{
var jsonWithExtra = """
{
"unknownField": "old-value",
"pipeName": "otopcua-historian",
"sharedSecret": "s3cr3t",
"probeTimeoutSeconds": 20
}
""";
var optsWithSkip = new JsonSerializerOptions(_opts)
{
UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip,
};
var back = JsonSerializer.Deserialize<WonderwareHistorianClientOptions>(jsonWithExtra, optsWithSkip);
back.ShouldNotBeNull();
back.ProbeTimeoutSeconds.ShouldBe(20);
back.PipeName.ShouldBe("otopcua-historian");
}
[Fact]
public void FormModel_RoundTrip_PreservesAllFields()
{
// Construct a record with non-default values for every property and verify
// that WonderwareHistorianClientFormModel.FromRecord → ToRecord is lossless.
var original = new WonderwareHistorianClientOptions(
PipeName: "otopcua-historian-prod",
SharedSecret: "sup3rs3cr3t",
PeerName: "OtOpcUa-Redundant",
ConnectTimeout: TimeSpan.FromSeconds(18),
CallTimeout: TimeSpan.FromSeconds(45))
{
ProbeTimeoutSeconds = 30,
};
var form = HistorianWonderwareDriverPage.WonderwareHistorianClientFormModel.FromRecord(original);
var result = form.ToRecord();
result.PipeName.ShouldBe("otopcua-historian-prod");
result.SharedSecret.ShouldBe("sup3rs3cr3t");
result.PeerName.ShouldBe("OtOpcUa-Redundant");
result.ConnectTimeout.ShouldBe(TimeSpan.FromSeconds(18));
result.CallTimeout.ShouldBe(TimeSpan.FromSeconds(45));
result.EffectiveConnectTimeout.ShouldBe(TimeSpan.FromSeconds(18));
result.EffectiveCallTimeout.ShouldBe(TimeSpan.FromSeconds(45));
result.ProbeTimeoutSeconds.ShouldBe(30);
}
}