test: record actual ScadaBridge consumer and baseline authorization gates
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run the real ScadaBridge consumer in separate processes against both application versions."""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import secrets
|
||||
import subprocess
|
||||
import time
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--baseline-host", type=Path, required=True)
|
||||
parser.add_argument("--candidate-host", type=Path, required=True)
|
||||
parser.add_argument("--probe", type=Path, required=True)
|
||||
parser.add_argument("--results", type=Path, required=True)
|
||||
args = parser.parse_args()
|
||||
root = args.results.resolve()
|
||||
root.mkdir(parents=True, exist_ok=False)
|
||||
artifacts = {name: path.resolve() for name, path in vars(args).items() if name != "results"}
|
||||
for path in artifacts.values():
|
||||
if not path.is_file():
|
||||
raise FileNotFoundError(path)
|
||||
receipt = {
|
||||
"artifacts": {name: {"path": str(path), "sha256": hashlib.sha256(path.read_bytes()).hexdigest()}
|
||||
for name, path in artifacts.items()},
|
||||
"legs": [],
|
||||
}
|
||||
for version in ("baseline", "candidate"):
|
||||
for mode in ("None", "SignAndEncrypt"):
|
||||
leg = root / f"{version}-{mode}"
|
||||
leg.mkdir()
|
||||
server_root = leg / "server"
|
||||
env = os.environ.copy()
|
||||
env["OPCUA_MATRIX_PASSWORD"] = "otua_matrix_" + secrets.token_urlsafe(32)
|
||||
if mode == "None":
|
||||
env["OPCUA_MATRIX_SERVER_SECURITY"] = "none"
|
||||
else:
|
||||
env.pop("OPCUA_MATRIX_SERVER_SECURITY", None)
|
||||
server_command = ["dotnet", str(artifacts[f"{version}_host"]), "server", str(server_root)]
|
||||
result = {"server": version, "mode": mode, "serverCommand": server_command}
|
||||
with (leg / "server.log").open("w") as server_log:
|
||||
server = subprocess.Popen(server_command, env=env, stdout=server_log, stderr=subprocess.STDOUT)
|
||||
try:
|
||||
until = time.monotonic() + 40
|
||||
while not (server_root / "endpoint.txt").is_file():
|
||||
if server.poll() is not None or time.monotonic() >= until:
|
||||
raise RuntimeError(f"Server failed to become ready; inspect {leg / 'server.log'}")
|
||||
time.sleep(0.1)
|
||||
endpoint = (server_root / "endpoint.txt").read_text().strip()
|
||||
env["SCADABRIDGE_PROBE_SERVER_CERTS"] = str(server_root / "server-pki" / "own" / "certs")
|
||||
command = ["dotnet", str(artifacts["probe"]), endpoint, mode, str(leg / "consumer")]
|
||||
with (leg / "consumer.log").open("w") as log:
|
||||
probe = subprocess.run(command, env=env, stdout=log, stderr=subprocess.STDOUT, timeout=150)
|
||||
result.update(command=command, exit=probe.returncode,
|
||||
result=str(leg / "consumer" / "result.json"))
|
||||
finally:
|
||||
server_root.mkdir(exist_ok=True)
|
||||
(server_root / "stop").touch()
|
||||
try:
|
||||
server.wait(timeout=15)
|
||||
except subprocess.TimeoutExpired:
|
||||
server.terminate()
|
||||
server.wait(timeout=10)
|
||||
result["serverExit"] = server.returncode
|
||||
receipt["legs"].append(result)
|
||||
(root / "receipt.json").write_text(json.dumps(receipt, indent=2))
|
||||
# A pre-existing consumer limitation is evidence to investigate, never converted into a passing leg.
|
||||
return int(any(leg["exit"] != 0 or leg["serverExit"] != 0 for leg in receipt["legs"]))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user