147 lines
6.0 KiB
PowerShell
147 lines
6.0 KiB
PowerShell
#Requires -Version 7.0
|
|
<#
|
|
.SYNOPSIS
|
|
End-to-end CLI test for the OPC UA Client (gateway) driver bridged through
|
|
the OtOpcUa server. Stages: probe, read, subscribe, topology-change.
|
|
|
|
.DESCRIPTION
|
|
The OPC UA Client driver reads from an upstream OPC UA server (default:
|
|
Microsoft's opc-plc simulator on opc.tcp://localhost:50000) and re-exposes
|
|
its address space through the local OtOpcUa server. This script drives
|
|
the bridged path end-to-end via `otopcua-cli`.
|
|
|
|
Four stages:
|
|
|
|
1. Probe — otopcua-cli connect succeeds against the OtOpcUa
|
|
server; confirms the gateway is up.
|
|
2. Bridged read — otopcua-cli read on the bridged NodeId returns a
|
|
Good value with a non-null payload; proves the
|
|
IReadable.ReadAsync path round-trips through the
|
|
driver to the upstream simulator.
|
|
3. Subscribe — otopcua-cli subscribe observes a data change within
|
|
N seconds (opc-plc's StepUp ticks once per second by
|
|
default, so this should always see a change).
|
|
4. Topology change — assert the auto-reimport-on-ModelChangeEvent path
|
|
is wired up. We can't easily fire a real upstream
|
|
model change without elevated opc-plc access, so
|
|
this stage prints the option settings + asserts the
|
|
driver's diagnostic surface reflects WatchModelChanges
|
|
is enabled (or skips with INFO when the upstream
|
|
doesn't expose ModelChangeEventType).
|
|
|
|
Requires:
|
|
- a running OtOpcUa server whose config DB has an OpcUaClient
|
|
DriverInstance bound to opc-plc (or another upstream server)
|
|
- the upstream OPC UA simulator reachable at $UpstreamUrl
|
|
- a Tag bridged from upstream NodeId $UpstreamNodeId to local
|
|
$BridgedNodeId
|
|
|
|
.PARAMETER OpcUaUrl
|
|
Endpoint URL of the OtOpcUa server. Default opc.tcp://localhost:4840.
|
|
|
|
.PARAMETER UpstreamUrl
|
|
Endpoint URL of the upstream OPC UA server (for documentation; the bridge
|
|
itself is wired in the OtOpcUa server config). Default opc.tcp://localhost:50000.
|
|
|
|
.PARAMETER BridgedNodeId
|
|
Local NodeId the OtOpcUa server exposes for the upstream tag. Required —
|
|
set per your server config (e.g. 'ns=2;s=/warsaw/opc-plc/StepUp').
|
|
|
|
.PARAMETER UpstreamNodeId
|
|
The upstream NodeId being bridged (informational only; default
|
|
'ns=3;s=StepUp' which is opc-plc's monotonically-increasing UInt32).
|
|
|
|
.PARAMETER ChangeWaitSec
|
|
How long the subscribe stage waits for a data-change. Default 10s.
|
|
|
|
.EXAMPLE
|
|
.\test-opcuaclient.ps1 -BridgedNodeId "ns=2;s=/warsaw/opc-plc/StepUp"
|
|
#>
|
|
|
|
param(
|
|
[string]$OpcUaUrl = "opc.tcp://localhost:4840",
|
|
[string]$UpstreamUrl = "opc.tcp://localhost:50000",
|
|
[Parameter(Mandatory)] [string]$BridgedNodeId,
|
|
[string]$UpstreamNodeId = "ns=3;s=StepUp",
|
|
[int]$ChangeWaitSec = 10
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
. "$PSScriptRoot/_common.ps1"
|
|
|
|
$opcUaCli = Get-CliInvocation `
|
|
-ProjectFolder "src/ZB.MOM.WW.OtOpcUa.Client.CLI" `
|
|
-ExeName "otopcua-cli"
|
|
|
|
$results = @()
|
|
|
|
# Stage 1: probe
|
|
$results += Test-Probe `
|
|
-Name "OpcUaClient probe" `
|
|
-Cmd $opcUaCli `
|
|
-Args @("connect", "-u", $OpcUaUrl)
|
|
|
|
# Stage 2: bridged read
|
|
$results += Test-Probe `
|
|
-Name "OpcUaClient bridged read" `
|
|
-Cmd $opcUaCli `
|
|
-Args @("read", "-u", $OpcUaUrl, "-n", $BridgedNodeId)
|
|
|
|
# Stage 3: subscribe-sees-change
|
|
Write-Host "[INFO] Subscribing to $BridgedNodeId for ${ChangeWaitSec}s..."
|
|
$subResults = & $opcUaCli.Cmd @($opcUaCli.Args + @(
|
|
"subscribe", "-u", $OpcUaUrl, "-n", $BridgedNodeId,
|
|
"-i", "500", "--duration", "$ChangeWaitSec"))
|
|
if ($LASTEXITCODE -eq 0 -and $subResults -match "DataChange|StepUp|value=") {
|
|
$results += [pscustomobject]@{ Stage = "Subscribe-sees-change"; Status = "PASS" }
|
|
} else {
|
|
$results += [pscustomobject]@{ Stage = "Subscribe-sees-change"; Status = "FAIL" }
|
|
}
|
|
|
|
# Stage 4: topology change (auto-reimport on ModelChangeEvent)
|
|
#
|
|
# The OPC UA Client driver subscribes to BaseModelChangeEventType on the
|
|
# upstream Server node (i=2253) at the end of InitializeAsync, then debounces
|
|
# events over OpcUaClientDriverOptions.ModelChangeDebounce (default 5s) and
|
|
# triggers ReinitializeAsync.
|
|
#
|
|
# Driving a real upstream ModelChangeEvent from outside the simulator is
|
|
# upstream-specific:
|
|
# - opc-plc: invoke OpcPlc.AddSlowNode via OPC UA Call (requires a session
|
|
# directly to opc-plc, not via the gateway, since the gateway exposes
|
|
# mirrored read/write paths only for variables — methods are mirrored
|
|
# under PR-9 but call permissions on the simulator's namespace may
|
|
# not allow downstream invocation).
|
|
# - production server: deploy a topology-change to the upstream server +
|
|
# observe the local re-import.
|
|
#
|
|
# This stage is therefore documentation-only by default. Set
|
|
# $env:OPCUACLIENT_TOPOLOGY_TRIGGER_CMD to a command that drives a real
|
|
# topology change on the upstream and we'll execute it + wait for the
|
|
# debounced re-import.
|
|
$triggerCmd = $env:OPCUACLIENT_TOPOLOGY_TRIGGER_CMD
|
|
if ($triggerCmd) {
|
|
Write-Host "[INFO] Driving topology change via: $triggerCmd"
|
|
& cmd.exe /c $triggerCmd
|
|
Start-Sleep -Seconds 8 # debounce window + re-import duration
|
|
# After re-import the bridged node should still be readable (or, if
|
|
# the upstream removed the node, the read should return BadNodeIdUnknown).
|
|
# Either way the gateway must remain healthy.
|
|
$results += Test-Probe `
|
|
-Name "Topology-change re-read" `
|
|
-Cmd $opcUaCli `
|
|
-Args @("read", "-u", $OpcUaUrl, "-n", $BridgedNodeId)
|
|
} else {
|
|
Write-Host "[INFO] Topology-change stage skipped (set OPCUACLIENT_TOPOLOGY_TRIGGER_CMD to drive a real upstream model change)."
|
|
$results += [pscustomobject]@{ Stage = "Topology-change"; Status = "SKIP" }
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "=== test-opcuaclient.ps1 results ==="
|
|
$results | Format-Table -AutoSize
|
|
$failed = $results | Where-Object { $_.Status -eq "FAIL" }
|
|
if ($failed) {
|
|
exit 1
|
|
}
|
|
exit 0
|