Side-by-side fixture that boots both backends against the same dev Galaxy: - Legacy GalaxyProxyDriver against an out-of-process Galaxy.Host EXE (skipped when ZB SQL on localhost:1433 isn't reachable or when the EXE hasn't been built). - New in-process GalaxyDriver against an mxaccessgw gateway at http://localhost:5120 by default (skipped when the gateway isn't reachable). Endpoint, API key, and client name are env-var overridable for the central parity host. Per-backend availability is independent — each scenario decides whether to RequireBoth, GetDriver(specific), or use RunOnAvailableAsync to drive both with the same closure and diff snapshots. PR 5.2–5.8 land scenarios on top of this shell. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
60 lines
2.7 KiB
C#
60 lines
2.7 KiB
C#
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.ParityTests;
|
|
|
|
/// <summary>
|
|
/// Same shape as <c>Driver.Galaxy.E2E.RecordingAddressSpaceBuilder</c>; duplicated
|
|
/// here so the parity-tests project doesn't take a hard project reference on the
|
|
/// E2E project (which would double-register E2E test classes during discovery).
|
|
/// </summary>
|
|
public sealed class RecordingAddressSpaceBuilder : IAddressSpaceBuilder
|
|
{
|
|
public List<RecordedFolder> Folders { get; } = new();
|
|
public List<RecordedVariable> Variables { get; } = new();
|
|
public List<RecordedProperty> Properties { get; } = new();
|
|
public List<RecordedAlarmCondition> AlarmConditions { get; } = new();
|
|
public List<RecordedAlarmTransition> AlarmTransitions { get; } = new();
|
|
|
|
public IAddressSpaceBuilder Folder(string browseName, string displayName)
|
|
{
|
|
Folders.Add(new RecordedFolder(browseName, displayName));
|
|
return this;
|
|
}
|
|
|
|
public IVariableHandle Variable(string browseName, string displayName, DriverAttributeInfo attributeInfo)
|
|
{
|
|
Variables.Add(new RecordedVariable(browseName, displayName, attributeInfo));
|
|
return new RecordedVariableHandle(attributeInfo.FullName, AlarmConditions, AlarmTransitions);
|
|
}
|
|
|
|
public void AddProperty(string browseName, DriverDataType dataType, object? value)
|
|
=> Properties.Add(new RecordedProperty(browseName, dataType, value));
|
|
|
|
public sealed record RecordedFolder(string BrowseName, string DisplayName);
|
|
public sealed record RecordedVariable(string BrowseName, string DisplayName, DriverAttributeInfo AttributeInfo);
|
|
public sealed record RecordedProperty(string BrowseName, DriverDataType DataType, object? Value);
|
|
public sealed record RecordedAlarmCondition(string SourceNodeId, AlarmConditionInfo Info);
|
|
public sealed record RecordedAlarmTransition(string SourceNodeId, AlarmEventArgs Args);
|
|
|
|
private sealed class RecordedVariableHandle(
|
|
string fullReference,
|
|
List<RecordedAlarmCondition> conditions,
|
|
List<RecordedAlarmTransition> transitions) : IVariableHandle
|
|
{
|
|
public string FullReference => fullReference;
|
|
|
|
public IAlarmConditionSink MarkAsAlarmCondition(AlarmConditionInfo info)
|
|
{
|
|
conditions.Add(new RecordedAlarmCondition(fullReference, info));
|
|
return new RecordingSink(fullReference, transitions);
|
|
}
|
|
|
|
private sealed class RecordingSink(
|
|
string sourceNodeId, List<RecordedAlarmTransition> transitions) : IAlarmConditionSink
|
|
{
|
|
public void OnTransition(AlarmEventArgs args)
|
|
=> transitions.Add(new RecordedAlarmTransition(sourceNodeId, args));
|
|
}
|
|
}
|
|
}
|