Move subscribe/unsubscribe I/O outside lock(Lock) in SyncAddressSpace to avoid blocking all OPC UA operations during rebuilds. Replace blocking ReadAsync calls for alarm priority/description in dispatch loop with cached subscription values. Extract IHistorianConnectionFactory so EnsureConnected can be tested without the SDK runtime — adds 5 connection lifecycle tests (failure, timeout, reconnect, state resilience, dispose-after-failure). All stability review findings and test coverage gaps are now fully resolved. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
50 lines
1.7 KiB
C#
50 lines
1.7 KiB
C#
using System;
|
|
using ArchestrA;
|
|
using ZB.MOM.WW.LmxOpcUa.Host.Configuration;
|
|
using ZB.MOM.WW.LmxOpcUa.Host.Historian;
|
|
|
|
namespace ZB.MOM.WW.LmxOpcUa.Tests.Helpers
|
|
{
|
|
/// <summary>
|
|
/// Fake Historian connection factory for tests. Controls whether connections
|
|
/// succeed, fail, or timeout without requiring the real Historian SDK runtime.
|
|
/// </summary>
|
|
internal sealed class FakeHistorianConnectionFactory : IHistorianConnectionFactory
|
|
{
|
|
/// <summary>
|
|
/// When set, <see cref="CreateAndConnect"/> throws this exception.
|
|
/// </summary>
|
|
public Exception? ConnectException { get; set; }
|
|
|
|
/// <summary>
|
|
/// Number of times <see cref="CreateAndConnect"/> has been called.
|
|
/// </summary>
|
|
public int ConnectCallCount { get; private set; }
|
|
|
|
/// <summary>
|
|
/// When set, called on each <see cref="CreateAndConnect"/> to determine behavior.
|
|
/// Receives the call count (1-based). Return null to succeed, or throw to fail.
|
|
/// </summary>
|
|
public Action<int>? OnConnect { get; set; }
|
|
|
|
public HistorianAccess CreateAndConnect(HistorianConfiguration config, HistorianConnectionType type)
|
|
{
|
|
ConnectCallCount++;
|
|
|
|
if (OnConnect != null)
|
|
{
|
|
OnConnect(ConnectCallCount);
|
|
}
|
|
else if (ConnectException != null)
|
|
{
|
|
throw ConnectException;
|
|
}
|
|
|
|
// Return a HistorianAccess that is not actually connected.
|
|
// ReadRawAsync etc. will fail when they try to use it, which exercises
|
|
// the HandleConnectionError → reconnect path.
|
|
return new HistorianAccess();
|
|
}
|
|
}
|
|
}
|