76 lines
3.7 KiB
Python
76 lines
3.7 KiB
Python
#!/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())
|