using System.Text.Json; using System.Text.Json.Serialization; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Config; namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests; public sealed class GalaxyDriverPageFormSerializationTests { private static readonly JsonSerializerOptions _opts = new() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase, WriteIndented = false, }; [Fact] public void RoundTrip_PreservesKnownFields() { var original = new GalaxyDriverOptions( Gateway: new GalaxyGatewayOptions( Endpoint: "https://gw.internal:5001", ApiKeySecretRef: "env:MY_API_KEY", UseTls: true, CaCertificatePath: "C:\\certs\\ca.pem", ConnectTimeoutSeconds: 15, DefaultCallTimeoutSeconds: 45, StreamTimeoutSeconds: 0), MxAccess: new GalaxyMxAccessOptions( ClientName: "OtOpcUa-Primary", PublishingIntervalMs: 500, WriteUserId: 1, EventPumpChannelCapacity: 100_000), Repository: new GalaxyRepositoryOptions( DiscoverPageSize: 2000, WatchDeployEvents: false), Reconnect: new GalaxyReconnectOptions( InitialBackoffMs: 1000, MaxBackoffMs: 60_000, ReplayOnSessionLost: false)) { ProbeTimeoutSeconds = 45, }; var json = JsonSerializer.Serialize(original, _opts); var back = JsonSerializer.Deserialize(json, _opts); back.ShouldNotBeNull(); back.Gateway.Endpoint.ShouldBe("https://gw.internal:5001"); back.Gateway.ApiKeySecretRef.ShouldBe("env:MY_API_KEY"); back.Gateway.UseTls.ShouldBeTrue(); back.Gateway.CaCertificatePath.ShouldBe("C:\\certs\\ca.pem"); back.Gateway.ConnectTimeoutSeconds.ShouldBe(15); back.Gateway.DefaultCallTimeoutSeconds.ShouldBe(45); back.Gateway.StreamTimeoutSeconds.ShouldBe(0); back.MxAccess.ClientName.ShouldBe("OtOpcUa-Primary"); back.MxAccess.PublishingIntervalMs.ShouldBe(500); back.MxAccess.WriteUserId.ShouldBe(1); back.MxAccess.EventPumpChannelCapacity.ShouldBe(100_000); back.Repository.DiscoverPageSize.ShouldBe(2000); back.Repository.WatchDeployEvents.ShouldBeFalse(); back.Reconnect.InitialBackoffMs.ShouldBe(1000); back.Reconnect.MaxBackoffMs.ShouldBe(60_000); back.Reconnect.ReplayOnSessionLost.ShouldBeFalse(); back.ProbeTimeoutSeconds.ShouldBe(45); } [Fact] public void Deserialize_DropsUnknownFields() { // Minimal JSON that sets only ProbeTimeoutSeconds and an unknown field. // The nested records must supply their required positional args for JSON deserialization // to succeed — provide them here so the test exercises the Unknown-field skip path. var jsonWithExtra = """ { "unknownField": "old-value", "gateway": { "endpoint": "https://localhost:5001", "apiKeySecretRef": "dev:test" }, "mxAccess": { "clientName": "OtOpcUa" }, "repository": {}, "reconnect": {}, "probeTimeoutSeconds": 20 } """; var optsWithSkip = new JsonSerializerOptions(_opts) { UnmappedMemberHandling = JsonUnmappedMemberHandling.Skip, }; var back = JsonSerializer.Deserialize(jsonWithExtra, optsWithSkip); back.ShouldNotBeNull(); back.ProbeTimeoutSeconds.ShouldBe(20); back.Gateway.Endpoint.ShouldBe("https://localhost:5001"); } }