feat(dcl): replace hand-rolled LmxProxy gRPC client with real LmxProxyClient library
Switches from v1 string-based proto stubs to the production LmxProxyClient (v2 native TypedValue protocol) via project reference. Deletes 6k+ lines of generated proto code. Preserves ILmxProxyClient adapter interface for testability.
This commit is contained in:
@@ -4,6 +4,8 @@ using NSubstitute.ExceptionExtensions;
|
||||
using ScadaLink.Commons.Interfaces.Protocol;
|
||||
using ScadaLink.Commons.Types.Enums;
|
||||
using ScadaLink.DataConnectionLayer.Adapters;
|
||||
using ZB.MOM.WW.LmxProxy.Client.Domain;
|
||||
using QualityCode = ScadaLink.Commons.Interfaces.Protocol.QualityCode;
|
||||
|
||||
namespace ScadaLink.DataConnectionLayer.Tests;
|
||||
|
||||
@@ -17,7 +19,7 @@ public class LmxProxyDataConnectionTests
|
||||
{
|
||||
_mockClient = Substitute.For<ILmxProxyClient>();
|
||||
_mockFactory = Substitute.For<ILmxProxyClientFactory>();
|
||||
_mockFactory.Create(Arg.Any<string>(), Arg.Any<int>(), Arg.Any<string?>(), Arg.Any<int>(), Arg.Any<bool>()).Returns(_mockClient);
|
||||
_mockFactory.Create(Arg.Any<string>(), Arg.Any<int>(), Arg.Any<string?>(), Arg.Any<bool>()).Returns(_mockClient);
|
||||
_adapter = new LmxProxyDataConnection(_mockFactory, NullLogger<LmxProxyDataConnection>.Instance);
|
||||
}
|
||||
|
||||
@@ -41,7 +43,7 @@ public class LmxProxyDataConnectionTests
|
||||
});
|
||||
|
||||
Assert.Equal(ConnectionHealth.Connected, _adapter.Status);
|
||||
_mockFactory.Received(1).Create("myhost", 5001, null, 0, false);
|
||||
_mockFactory.Received(1).Create("myhost", 5001, null, false);
|
||||
await _mockClient.Received(1).ConnectAsync(Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
@@ -57,7 +59,7 @@ public class LmxProxyDataConnectionTests
|
||||
["ApiKey"] = "my-secret-key"
|
||||
});
|
||||
|
||||
_mockFactory.Received(1).Create("server", 50051, "my-secret-key", 0, false);
|
||||
_mockFactory.Received(1).Create("server", 50051, "my-secret-key", false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -67,7 +69,7 @@ public class LmxProxyDataConnectionTests
|
||||
|
||||
await _adapter.ConnectAsync(new Dictionary<string, string>());
|
||||
|
||||
_mockFactory.Received(1).Create("localhost", 50051, null, 0, false);
|
||||
_mockFactory.Received(1).Create("localhost", 50051, null, false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -88,7 +90,7 @@ public class LmxProxyDataConnectionTests
|
||||
await ConnectAdapter();
|
||||
var now = DateTime.UtcNow;
|
||||
_mockClient.ReadAsync("Tag1", Arg.Any<CancellationToken>())
|
||||
.Returns(new LmxVtq(42.5, now, LmxQuality.Good));
|
||||
.Returns(new Vtq(42.5, now, Quality.Good));
|
||||
|
||||
var result = await _adapter.ReadAsync("Tag1");
|
||||
|
||||
@@ -102,7 +104,7 @@ public class LmxProxyDataConnectionTests
|
||||
{
|
||||
await ConnectAdapter();
|
||||
_mockClient.ReadAsync("Tag1", Arg.Any<CancellationToken>())
|
||||
.Returns(new LmxVtq(null, DateTime.UtcNow, LmxQuality.Bad));
|
||||
.Returns(new Vtq(null, DateTime.UtcNow, Quality.Bad));
|
||||
|
||||
var result = await _adapter.ReadAsync("Tag1");
|
||||
|
||||
@@ -116,7 +118,7 @@ public class LmxProxyDataConnectionTests
|
||||
{
|
||||
await ConnectAdapter();
|
||||
_mockClient.ReadAsync("Tag1", Arg.Any<CancellationToken>())
|
||||
.Returns(new LmxVtq("maybe", DateTime.UtcNow, LmxQuality.Uncertain));
|
||||
.Returns(new Vtq("maybe", DateTime.UtcNow, Quality.Uncertain));
|
||||
|
||||
var result = await _adapter.ReadAsync("Tag1");
|
||||
|
||||
@@ -130,10 +132,10 @@ public class LmxProxyDataConnectionTests
|
||||
await ConnectAdapter();
|
||||
var now = DateTime.UtcNow;
|
||||
_mockClient.ReadBatchAsync(Arg.Any<IEnumerable<string>>(), Arg.Any<CancellationToken>())
|
||||
.Returns(new Dictionary<string, LmxVtq>
|
||||
.Returns(new Dictionary<string, Vtq>
|
||||
{
|
||||
["Tag1"] = new(10, now, LmxQuality.Good),
|
||||
["Tag2"] = new(null, now, LmxQuality.Bad)
|
||||
["Tag1"] = new(10, now, Quality.Good),
|
||||
["Tag2"] = new(null, now, Quality.Bad)
|
||||
});
|
||||
|
||||
var results = await _adapter.ReadBatchAsync(["Tag1", "Tag2"]);
|
||||
@@ -153,14 +155,14 @@ public class LmxProxyDataConnectionTests
|
||||
var result = await _adapter.WriteAsync("Tag1", 42);
|
||||
|
||||
Assert.True(result.Success);
|
||||
await _mockClient.Received(1).WriteAsync("Tag1", 42, Arg.Any<CancellationToken>());
|
||||
await _mockClient.Received(1).WriteAsync("Tag1", Arg.Any<TypedValue>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Write_Failure_ReturnsError()
|
||||
{
|
||||
await ConnectAdapter();
|
||||
_mockClient.WriteAsync("Tag1", 42, Arg.Any<CancellationToken>())
|
||||
_mockClient.WriteAsync("Tag1", Arg.Any<TypedValue>(), Arg.Any<CancellationToken>())
|
||||
.Throws(new InvalidOperationException("Write failed for tag"));
|
||||
|
||||
var result = await _adapter.WriteAsync("Tag1", 42);
|
||||
@@ -184,7 +186,7 @@ public class LmxProxyDataConnectionTests
|
||||
public async Task WriteBatch_Failure_ReturnsAllErrors()
|
||||
{
|
||||
await ConnectAdapter();
|
||||
_mockClient.WriteBatchAsync(Arg.Any<IDictionary<string, object>>(), Arg.Any<CancellationToken>())
|
||||
_mockClient.WriteBatchAsync(Arg.Any<IDictionary<string, TypedValue>>(), Arg.Any<CancellationToken>())
|
||||
.Throws(new InvalidOperationException("Batch write failed"));
|
||||
|
||||
var results = await _adapter.WriteBatchAsync(new Dictionary<string, object?> { ["T1"] = 1, ["T2"] = 2 });
|
||||
@@ -201,7 +203,7 @@ public class LmxProxyDataConnectionTests
|
||||
{
|
||||
await ConnectAdapter();
|
||||
var mockSub = Substitute.For<ILmxSubscription>();
|
||||
_mockClient.SubscribeAsync(Arg.Any<IEnumerable<string>>(), Arg.Any<Action<string, LmxVtq>>(), Arg.Any<Action?>(), Arg.Any<CancellationToken>())
|
||||
_mockClient.SubscribeAsync(Arg.Any<IEnumerable<string>>(), Arg.Any<Action<string, Vtq>>(), Arg.Any<Action<Exception>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(mockSub);
|
||||
|
||||
var subId = await _adapter.SubscribeAsync("Tag1", (_, _) => { });
|
||||
@@ -209,7 +211,7 @@ public class LmxProxyDataConnectionTests
|
||||
Assert.NotNull(subId);
|
||||
Assert.NotEmpty(subId);
|
||||
await _mockClient.Received(1).SubscribeAsync(
|
||||
Arg.Any<IEnumerable<string>>(), Arg.Any<Action<string, LmxVtq>>(), Arg.Any<Action?>(), Arg.Any<CancellationToken>());
|
||||
Arg.Any<IEnumerable<string>>(), Arg.Any<Action<string, Vtq>>(), Arg.Any<Action<Exception>?>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -217,7 +219,7 @@ public class LmxProxyDataConnectionTests
|
||||
{
|
||||
await ConnectAdapter();
|
||||
var mockSub = Substitute.For<ILmxSubscription>();
|
||||
_mockClient.SubscribeAsync(Arg.Any<IEnumerable<string>>(), Arg.Any<Action<string, LmxVtq>>(), Arg.Any<Action?>(), Arg.Any<CancellationToken>())
|
||||
_mockClient.SubscribeAsync(Arg.Any<IEnumerable<string>>(), Arg.Any<Action<string, Vtq>>(), Arg.Any<Action<Exception>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(mockSub);
|
||||
|
||||
var subId = await _adapter.SubscribeAsync("Tag1", (_, _) => { });
|
||||
@@ -240,7 +242,7 @@ public class LmxProxyDataConnectionTests
|
||||
{
|
||||
await ConnectAdapter();
|
||||
var mockSub = Substitute.For<ILmxSubscription>();
|
||||
_mockClient.SubscribeAsync(Arg.Any<IEnumerable<string>>(), Arg.Any<Action<string, LmxVtq>>(), Arg.Any<Action?>(), Arg.Any<CancellationToken>())
|
||||
_mockClient.SubscribeAsync(Arg.Any<IEnumerable<string>>(), Arg.Any<Action<string, Vtq>>(), Arg.Any<Action<Exception>?>(), Arg.Any<CancellationToken>())
|
||||
.Returns(mockSub);
|
||||
await _adapter.SubscribeAsync("Tag1", (_, _) => { });
|
||||
|
||||
@@ -280,21 +282,6 @@ public class LmxProxyDataConnectionTests
|
||||
|
||||
// --- Configuration Parsing ---
|
||||
|
||||
[Fact]
|
||||
public async Task Connect_ParsesSamplingInterval()
|
||||
{
|
||||
_mockClient.IsConnected.Returns(true);
|
||||
|
||||
await _adapter.ConnectAsync(new Dictionary<string, string>
|
||||
{
|
||||
["Host"] = "server",
|
||||
["Port"] = "50051",
|
||||
["SamplingIntervalMs"] = "500"
|
||||
});
|
||||
|
||||
_mockFactory.Received(1).Create("server", 50051, null, 500, false);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Connect_ParsesUseTls()
|
||||
{
|
||||
@@ -307,16 +294,16 @@ public class LmxProxyDataConnectionTests
|
||||
["UseTls"] = "true"
|
||||
});
|
||||
|
||||
_mockFactory.Received(1).Create("server", 50051, null, 0, true);
|
||||
_mockFactory.Received(1).Create("server", 50051, null, true);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Connect_DefaultsSamplingAndTls()
|
||||
public async Task Connect_DefaultsHostPortAndTls()
|
||||
{
|
||||
_mockClient.IsConnected.Returns(true);
|
||||
|
||||
await _adapter.ConnectAsync(new Dictionary<string, string>());
|
||||
|
||||
_mockFactory.Received(1).Create("localhost", 50051, null, 0, false);
|
||||
_mockFactory.Received(1).Create("localhost", 50051, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user