Files
lmxopcua/tests/ZB.MOM.WW.OtOpcUa.Driver.Galaxy.ParityTests/RecordingAddressSpaceBuilder.cs
Joseph Doherty 82cdf460c5 PR 5.1 — Driver.Galaxy.ParityTests project shell + ParityHarness
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>
2026-04-29 16:22:04 -04:00

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