@@ -0,0 +1,35 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests;
|
||||
|
||||
/// <summary>
|
||||
/// PR abcip-5.1 — integration scaffold for HSBY paired-IP role probing. Skipped by default
|
||||
/// because <c>ab_server</c> cannot emulate a ControlLogix HSBY pair (it has no second-chassis
|
||||
/// concept + no <c>WallClockTime.SyncStatus</c> tag). Promoted from skipped to active when
|
||||
/// the Docker fixture grows the <c>hsby-mux</c> sidecar (planned in PR abcip-5.2 follow-up
|
||||
/// work) or when a real lab rig is available; the unit-level coverage in
|
||||
/// <c>AbCipHsbyTests</c> exercises the value-mapping + active-resolution rules in the
|
||||
/// meantime.
|
||||
/// <para>
|
||||
/// The skip lives in the test body so the file still compiles + the trait is discoverable
|
||||
/// by <c>dotnet test --filter "Category=Hsby"</c>; the body never gets to assert anything
|
||||
/// against <c>ab_server</c>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
[Trait("Category", "Hsby")]
|
||||
[Trait("Requires", "AbServer")]
|
||||
public sealed class AbCipHsbyRoleProberTests
|
||||
{
|
||||
[AbServerFact]
|
||||
public Task Role_prober_resolves_active_chassis_against_paired_fixture()
|
||||
{
|
||||
// ab_server cannot emulate an HSBY pair; the paired-fixture compose service +
|
||||
// hsby-mux sidecar that PR abcip-5.2 ships will let this body do real wire work.
|
||||
// For PR abcip-5.1 we keep the file as a scaffold so the integration trait is
|
||||
// discoverable and a future PR can flip the skip into a real assertion.
|
||||
Assert.Skip("HSBY paired-fixture (controllogix-secondary + hsby-mux sidecar) not yet wired — PR abcip-5.2 follow-up.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -95,3 +95,81 @@ services:
|
||||
"--tag=TestDINT:DINT[1]",
|
||||
"--tag=SafetyDINT_S:DINT[1]"
|
||||
]
|
||||
|
||||
# ---- PR abcip-5.1 — paired-fixture for HSBY role probing ------------------
|
||||
# The "paired" profile spins up two ab_server instances (controllogix-primary
|
||||
# on :44818, controllogix-secondary on :44819) plus a stub hsby-mux sidecar
|
||||
# that flips a role bit on demand. The mux is a placeholder — it does NOT
|
||||
# currently inject role bits because ab_server has no WallClockTime.SyncStatus
|
||||
# tag concept. PR abcip-5.2 follow-up will land:
|
||||
# 1. A patched ab_server image (or a separate Python TCP shim) that exposes
|
||||
# a writable WallClockTime.SyncStatus DINT per chassis.
|
||||
# 2. A real hsby-mux REST endpoint (POST /flip {"active": "primary"}) that
|
||||
# writes 1 to the chosen chassis + 0 to the other.
|
||||
# For now the services exist so the compose file documents the topology + the
|
||||
# AbCipHsbyRoleProberTests integration test has a place to land its
|
||||
# [AbServerFact] without breaking the pre-5.1 ab_server profiles.
|
||||
controllogix-primary:
|
||||
profiles: ["paired"]
|
||||
image: otopcua-ab-server:libplctag-release
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: otopcua-ab-server-controllogix-primary
|
||||
restart: "no"
|
||||
ports:
|
||||
- "44818:44818"
|
||||
command: [
|
||||
"ab_server",
|
||||
"--plc=ControlLogix",
|
||||
"--path=1,0",
|
||||
"--port=44818",
|
||||
"--tag=TestDINT:DINT[1]",
|
||||
# Stand-in for WallClockTime.SyncStatus until the patched image lands.
|
||||
"--tag=SyncStatus:DINT[1]"
|
||||
]
|
||||
|
||||
controllogix-secondary:
|
||||
profiles: ["paired"]
|
||||
image: otopcua-ab-server:libplctag-release
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: otopcua-ab-server-controllogix-secondary
|
||||
restart: "no"
|
||||
ports:
|
||||
- "44819:44818"
|
||||
command: [
|
||||
"ab_server",
|
||||
"--plc=ControlLogix",
|
||||
"--path=1,0",
|
||||
"--port=44818",
|
||||
"--tag=TestDINT:DINT[1]",
|
||||
"--tag=SyncStatus:DINT[1]"
|
||||
]
|
||||
|
||||
# Stub hsby-mux — placeholder. Today's image is a tiny Python script that
|
||||
# exposes a /health endpoint + nothing else. PR abcip-5.2 will replace this
|
||||
# with a real role-flip endpoint that writes SyncStatus on either chassis.
|
||||
hsby-mux:
|
||||
profiles: ["paired"]
|
||||
image: python:3.12-alpine
|
||||
container_name: otopcua-ab-hsby-mux
|
||||
restart: "no"
|
||||
ports:
|
||||
- "8080:8080"
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
python -c "
|
||||
import http.server, socketserver
|
||||
class H(http.server.BaseHTTPRequestHandler):
|
||||
def do_GET(s):
|
||||
s.send_response(200); s.send_header('Content-Type','text/plain'); s.end_headers()
|
||||
s.wfile.write(b'hsby-mux stub - PR abcip-5.2 follow-up will wire role flips')
|
||||
socketserver.TCPServer(('', 8080), H).serve_forever()
|
||||
"
|
||||
depends_on:
|
||||
- controllogix-primary
|
||||
- controllogix-secondary
|
||||
|
||||
Reference in New Issue
Block a user