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];
}