Files
lmxopcua/tests/ZB.MOM.WW.LmxOpcUa.Tests/Helpers/FakeHistorianConnectionFactory.cs
Joseph Doherty 9e1a180ce3 Resolve blocking I/O finding and complete Historian lifecycle test coverage
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>
2026-04-07 16:16:03 -04:00

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();
}
}
}