using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers; /// /// A minimal + that accepts every acknowledge and raises /// nothing — the host's own running driver for tests that route a client acknowledge but drive the alarm /// transitions themselves. Since lmxopcua#765 an ack to a driver that is not running (or is stubbed) is /// reverted, so such a test must start the owning driver for the ack to stand. /// internal sealed class AckingAlarmDriver : IDriver, IAlarmSource { private int _acks; private bool _alarmsSubscribed; /// public string DriverInstanceId { get; private set; } = string.Empty; /// public string DriverType { get; private set; } = string.Empty; /// How many acknowledge requests the driver accepted. public int Acks => Volatile.Read(ref _acks); /// True once the driver child reached Connected and opened its alarm subscription. public bool AlarmsSubscribed => Volatile.Read(ref _alarmsSubscribed); /// Sets the identity once the factory is asked to create it. /// The driver instance id. /// The driver type. public void Bind(string id, string type) { DriverInstanceId = id; DriverType = type; } /// public Task InitializeAsync(string driverConfigJson, CancellationToken cancellationToken) => Task.CompletedTask; /// public Task ReinitializeAsync(string driverConfigJson, CancellationToken cancellationToken) => Task.CompletedTask; /// public Task ShutdownAsync(CancellationToken cancellationToken) => Task.CompletedTask; /// public DriverHealth GetHealth() => new(DriverState.Healthy, DateTime.UtcNow, LastError: null); /// public Task SubscribeAlarmsAsync( IReadOnlyList sourceNodeIds, CancellationToken cancellationToken) { Volatile.Write(ref _alarmsSubscribed, true); return Task.FromResult(new Handle()); } /// public Task UnsubscribeAlarmsAsync(IAlarmSubscriptionHandle handle, CancellationToken cancellationToken) => Task.CompletedTask; /// public Task AcknowledgeAsync( IReadOnlyList acknowledgements, CancellationToken cancellationToken) { Interlocked.Add(ref _acks, acknowledgements.Count); return Task.CompletedTask; } /// public event EventHandler? OnAlarmEvent { add { } remove { } } private sealed class Handle : IAlarmSubscriptionHandle { public string DiagnosticId => "acking-alarm-sub"; } } /// Factory handing the host one shared for a single driver type. /// The driver type this factory creates. internal sealed class AckingAlarmDriverFactory(string supportedType) : IDriverFactory { /// The driver every spawn of receives. public AckingAlarmDriver Driver { get; } = new(); /// public IDriver? TryCreate(string driverType, string driverInstanceId, string driverConfigJson) { if (!string.Equals(driverType, supportedType, StringComparison.Ordinal)) return null; Driver.Bind(driverInstanceId, driverType); return Driver; } /// public IReadOnlyCollection SupportedTypes => [supportedType]; }