feat(commons): MxGatewayEndpointConfig serializer + tests
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.DataConnections;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.Commons.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// Serializes <see cref="MxGatewayEndpointConfig"/> to/from the typed JSON stored in
|
||||
/// <c>DataConnection.PrimaryConfiguration</c> / <c>BackupConfiguration</c>, and flattens
|
||||
/// it to the <c>IDictionary<string,string></c> shape <c>IDataConnection.ConnectAsync</c>
|
||||
/// expects. MxGateway is net-new, so there is no legacy shape to recover — a row that
|
||||
/// fails to parse yields a default config.
|
||||
/// </summary>
|
||||
public static class MxGatewayEndpointConfigSerializer
|
||||
{
|
||||
private static readonly JsonSerializerOptions JsonOpts = new()
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
WriteIndented = false,
|
||||
};
|
||||
|
||||
/// <summary>Serializes a config to the typed JSON shape.</summary>
|
||||
/// <param name="config">The endpoint configuration to serialize.</param>
|
||||
public static string Serialize(MxGatewayEndpointConfig config)
|
||||
=> JsonSerializer.Serialize(config, JsonOpts);
|
||||
|
||||
/// <summary>Parses stored config JSON; null/blank/malformed yields a default config.</summary>
|
||||
/// <param name="json">The stored JSON string.</param>
|
||||
public static MxGatewayEndpointConfig Deserialize(string? json)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json)) return new MxGatewayEndpointConfig();
|
||||
try { return JsonSerializer.Deserialize<MxGatewayEndpointConfig>(json, JsonOpts) ?? new MxGatewayEndpointConfig(); }
|
||||
catch (JsonException) { return new MxGatewayEndpointConfig(); }
|
||||
}
|
||||
|
||||
/// <summary>Flattens the typed config to the key-value shape the adapter consumes.</summary>
|
||||
/// <param name="c">The endpoint configuration to flatten.</param>
|
||||
public static IDictionary<string, string> ToFlatDict(MxGatewayEndpointConfig c) => new Dictionary<string, string>
|
||||
{
|
||||
["Endpoint"] = c.Endpoint,
|
||||
["ApiKey"] = c.ApiKey,
|
||||
["ClientName"] = c.ClientName,
|
||||
["WriteUserId"] = c.WriteUserId.ToString(CultureInfo.InvariantCulture),
|
||||
["UseTls"] = c.UseTls.ToString(),
|
||||
["CaFile"] = c.CaFile,
|
||||
["ServerName"] = c.ServerName,
|
||||
["ReadTimeoutMs"] = c.ReadTimeoutMs.ToString(CultureInfo.InvariantCulture),
|
||||
};
|
||||
|
||||
/// <summary>Reconstructs a config from the flat key-value shape; invalid numerics fall back to defaults.</summary>
|
||||
/// <param name="d">The flat dictionary.</param>
|
||||
public static MxGatewayEndpointConfig FromFlatDict(IDictionary<string, string> d)
|
||||
{
|
||||
var c = new MxGatewayEndpointConfig();
|
||||
if (d.TryGetValue("Endpoint", out var ep) && !string.IsNullOrWhiteSpace(ep)) c.Endpoint = ep;
|
||||
if (d.TryGetValue("ApiKey", out var ak)) c.ApiKey = ak;
|
||||
if (d.TryGetValue("ClientName", out var cn)) c.ClientName = cn;
|
||||
if (d.TryGetValue("WriteUserId", out var wu) && int.TryParse(wu, out var wuv)) c.WriteUserId = wuv;
|
||||
if (d.TryGetValue("UseTls", out var tls) && bool.TryParse(tls, out var tlsv)) c.UseTls = tlsv;
|
||||
if (d.TryGetValue("CaFile", out var ca)) c.CaFile = ca;
|
||||
if (d.TryGetValue("ServerName", out var sn)) c.ServerName = sn;
|
||||
if (d.TryGetValue("ReadTimeoutMs", out var rt) && int.TryParse(rt, out var rtv)) c.ReadTimeoutMs = rtv;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Serialization;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Types.DataConnections;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Types.DataConnections;
|
||||
|
||||
public class MxGatewayEndpointConfigSerializerTests
|
||||
{
|
||||
[Fact]
|
||||
public void Serialize_then_Deserialize_round_trips_all_fields()
|
||||
{
|
||||
var original = new MxGatewayEndpointConfig
|
||||
{
|
||||
Endpoint = "https://gw:5001",
|
||||
ApiKey = "secret-key",
|
||||
ClientName = "client-a",
|
||||
WriteUserId = 7,
|
||||
UseTls = true,
|
||||
CaFile = "/certs/ca.pem",
|
||||
ServerName = "gw.local",
|
||||
ReadTimeoutMs = 1234
|
||||
};
|
||||
|
||||
var json = MxGatewayEndpointConfigSerializer.Serialize(original);
|
||||
var round = MxGatewayEndpointConfigSerializer.Deserialize(json);
|
||||
|
||||
Assert.Equal(original.Endpoint, round.Endpoint);
|
||||
Assert.Equal(original.ApiKey, round.ApiKey);
|
||||
Assert.Equal(original.ClientName, round.ClientName);
|
||||
Assert.Equal(original.WriteUserId, round.WriteUserId);
|
||||
Assert.Equal(original.UseTls, round.UseTls);
|
||||
Assert.Equal(original.CaFile, round.CaFile);
|
||||
Assert.Equal(original.ServerName, round.ServerName);
|
||||
Assert.Equal(original.ReadTimeoutMs, round.ReadTimeoutMs);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
[InlineData("{ not valid json")]
|
||||
public void Deserialize_null_blank_or_malformed_returns_default(string? json)
|
||||
{
|
||||
var def = new MxGatewayEndpointConfig();
|
||||
var result = MxGatewayEndpointConfigSerializer.Deserialize(json);
|
||||
Assert.Equal(def.Endpoint, result.Endpoint);
|
||||
Assert.Equal(def.ReadTimeoutMs, result.ReadTimeoutMs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ToFlatDict_FromFlatDict_round_trips()
|
||||
{
|
||||
var original = new MxGatewayEndpointConfig
|
||||
{
|
||||
Endpoint = "http://x:5000",
|
||||
ApiKey = "k",
|
||||
ClientName = "c",
|
||||
WriteUserId = 3,
|
||||
UseTls = true,
|
||||
CaFile = "/ca",
|
||||
ServerName = "s",
|
||||
ReadTimeoutMs = 999
|
||||
};
|
||||
|
||||
var dict = MxGatewayEndpointConfigSerializer.ToFlatDict(original);
|
||||
var round = MxGatewayEndpointConfigSerializer.FromFlatDict(dict);
|
||||
|
||||
Assert.Equal(original.Endpoint, round.Endpoint);
|
||||
Assert.Equal(original.ApiKey, round.ApiKey);
|
||||
Assert.Equal(original.ClientName, round.ClientName);
|
||||
Assert.Equal(original.WriteUserId, round.WriteUserId);
|
||||
Assert.Equal(original.UseTls, round.UseTls);
|
||||
Assert.Equal(original.CaFile, round.CaFile);
|
||||
Assert.Equal(original.ServerName, round.ServerName);
|
||||
Assert.Equal(original.ReadTimeoutMs, round.ReadTimeoutMs);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FromFlatDict_invalid_numeric_falls_back_to_default()
|
||||
{
|
||||
var back = MxGatewayEndpointConfigSerializer.FromFlatDict(
|
||||
new Dictionary<string, string> { ["ReadTimeoutMs"] = "not-a-number" });
|
||||
Assert.Equal(new MxGatewayEndpointConfig().ReadTimeoutMs, back.ReadTimeoutMs);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user