using ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Adapters; namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests.Adapters; /// /// In-memory fake for adapter unit tests. Lets tests /// drive the event loop (push updates / fault the stream) and stub read/write/browse. /// public sealed class FakeMxGatewayClient : IMxGatewayClient, IMxGatewayClientFactory { public MxGatewayConnectionOptions? ConnectedWith; public readonly List Subscribed = new(); public readonly List Unsubscribed = new(); public readonly TaskCompletionSource EventLoopGate = new(TaskCreationOptions.RunContinuationsAsynchronously); public Action? OnUpdate; public Func, IReadOnlyList>? ReadHandler; public Func, IReadOnlyList>? WriteHandler; public Func, bool)>? BrowseHandler; private int _nextHandle; public IMxGatewayClient Create() => this; public Task ConnectAsync(MxGatewayConnectionOptions o, CancellationToken ct = default) { ConnectedWith = o; return Task.CompletedTask; } public Task DisconnectAsync(CancellationToken ct = default) => Task.CompletedTask; public Task SubscribeAsync(string tag, CancellationToken ct = default) { var id = (++_nextHandle).ToString(); Subscribed.Add(tag); return Task.FromResult(id); } public Task UnsubscribeAsync(string id, CancellationToken ct = default) { Unsubscribed.Add(id); return Task.CompletedTask; } public Task> ReadAsync(IReadOnlyList tags, CancellationToken ct = default) => Task.FromResult(ReadHandler!(tags)); public Task> WriteAsync(IReadOnlyList<(string TagPath, object? Value)> w, CancellationToken ct = default) => Task.FromResult(WriteHandler!(w)); public Task<(IReadOnlyList Children, bool Truncated)> BrowseChildrenAsync(string? p, CancellationToken ct = default) => Task.FromResult(BrowseHandler!(p)); public async Task RunEventLoopAsync(Action onUpdate, CancellationToken ct = default) { OnUpdate = onUpdate; using var reg = ct.Register(() => EventLoopGate.TrySetResult()); await EventLoopGate.Task; // test completes this to end the loop… ct.ThrowIfCancellationRequested(); // …or FaultEventLoop() faults it to simulate a stream break } public Task RunAlarmStreamAsync( string? alarmFilterPrefix, Action onTransition, CancellationToken ct = default) => Task.CompletedTask; // no alarm feed in the fake public ValueTask DisposeAsync() => ValueTask.CompletedTask; /// Simulate a stream break so the adapter raises Disconnected. public void FaultEventLoop() => EventLoopGate.TrySetException(new Exception("stream broke")); }