Files
lmxopcua/tests/ZB.MOM.WW.LmxOpcUa.Historian.Aveva.Tests/FakeHistorianConnectionFactory.cs

64 lines
2.5 KiB
C#

using System;
using System.Collections.Generic;
using ArchestrA;
using ZB.MOM.WW.LmxOpcUa.Historian.Aveva;
using ZB.MOM.WW.LmxOpcUa.Host.Configuration;
namespace ZB.MOM.WW.LmxOpcUa.Historian.Aveva.Tests
{
/// <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>
/// Exception thrown on every CreateAndConnect call unless a more specific rule in
/// <see cref="ServerBehaviors"/> or <see cref="OnConnect"/> fires first.
/// </summary>
public Exception? ConnectException { get; set; }
public int ConnectCallCount { get; private set; }
public Action<int>? OnConnect { get; set; }
/// <summary>
/// Per-server-name override: if the requested <c>config.ServerName</c> has an entry
/// whose value is non-null, that exception is thrown instead of the global
/// <see cref="ConnectException"/>. Lets tests script cluster failover behavior like
/// "node A always fails; node B always succeeds".
/// </summary>
public Dictionary<string, Exception?> ServerBehaviors { get; } =
new Dictionary<string, Exception?>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Ordered history of server names passed to CreateAndConnect so tests can assert the
/// picker's iteration order and failover sequence.
/// </summary>
public List<string> ConnectHistory { get; } = new List<string>();
public HistorianAccess CreateAndConnect(HistorianConfiguration config, HistorianConnectionType type)
{
ConnectCallCount++;
ConnectHistory.Add(config.ServerName);
if (ServerBehaviors.TryGetValue(config.ServerName, out var serverException) && serverException != null)
throw serverException;
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();
}
}
}