Skip to content

Commit 0f88c36

Browse files
committed
Update artifacts
1 parent 56ebb39 commit 0f88c36

18 files changed

+634
-487
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ build
44
*.pyc
55

66
tools/
7+
**/.DS_Store

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Serial communication is unreliable. Bits flip. Packets drop. Cables disconnect.
66

77
Data Bridge ensures every byte arrives exactly as sent, or you know about it.
88

9-
![Serial Data Corruption Examples](reliability_plot.png)
9+
![Serial Data Corruption Examples](docs/reliability_plot.png)
1010

1111
## The Problem
1212

@@ -172,7 +172,7 @@ uv run python bridge.py publish # Publish both
172172
uv run python bridge.py publish python # Publish only Python bindings
173173
```
174174

175-
![Fault Tolerance Test Results](docs/test_timeline.png)
175+
![Fault Tolerance Test Results](docs/traceability/artifacts/latest/test_timeline.png)
176176

177177
---
178178

bridge.py

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import shutil
2222
import subprocess
2323
import sys
24+
from datetime import datetime
2425
from pathlib import Path
2526

2627
# --- Configuration ---
@@ -170,27 +171,95 @@ def task_build(args):
170171
def task_test(args):
171172
"""Run tests."""
172173
target = args.target
174+
artifacts_dir = PROJECT_ROOT / "docs" / "traceability" / "artifacts" / "latest"
175+
176+
def run_logged(cmd: list[str], log_path: Path, cwd: Path, title: str, check: bool):
177+
info(title)
178+
log_path.parent.mkdir(parents=True, exist_ok=True)
179+
with open(log_path, "w") as log_file:
180+
start = datetime.utcnow().isoformat() + "Z"
181+
log_file.write(f"=== START {start} ===\n")
182+
try:
183+
proc = subprocess.Popen(
184+
cmd,
185+
cwd=cwd,
186+
stdout=subprocess.PIPE,
187+
stderr=subprocess.STDOUT,
188+
text=True,
189+
)
190+
assert proc.stdout is not None
191+
for line in proc.stdout:
192+
ts = datetime.utcnow().isoformat() + "Z"
193+
log_file.write(f"[{ts}] {line}")
194+
proc.wait()
195+
end = datetime.utcnow().isoformat() + "Z"
196+
log_file.write(f"=== END {end} (exit {proc.returncode}) ===\n")
197+
if check and proc.returncode != 0:
198+
error(f"Command failed: {' '.join(cmd)}")
199+
return proc.returncode == 0
200+
except subprocess.CalledProcessError as e:
201+
if check:
202+
error(f"Command failed: {' '.join(cmd)}\n{e}")
203+
return False
204+
except FileNotFoundError:
205+
warn(f"Command not found: {cmd[0]}")
206+
return False
207+
except KeyboardInterrupt:
208+
print("\nInterrupted.")
209+
sys.exit(130)
173210

174211
# Unit Tests
175212
if target == "unit" or target == "all":
176213
log("=== Unit Tests ===")
214+
artifacts_dir.mkdir(parents=True, exist_ok=True)
177215

178216
# 1. C++
179217
ctest = shutil.which("ctest")
180218
if ctest:
181-
run([ctest, "--output-on-failure"], cwd=BUILD_DIR, title="C++ Core Tests")
219+
run_logged(
220+
[ctest, "--output-on-failure"],
221+
artifacts_dir / "ctest.log",
222+
BUILD_DIR,
223+
"C++ Core Tests",
224+
True,
225+
)
182226
else:
183227
warn("ctest not found")
184228

185229
# 2. Python
186230
log("Python Tests...")
187-
uv_run(["python", "-m", "pytest"], cwd=PYTHON_BINDING_DIR)
231+
pytest_log = artifacts_dir / "pytest.log"
232+
pytest_junit = artifacts_dir / "pytest-junit.xml"
233+
uv_run(
234+
[
235+
"python",
236+
"-m",
237+
"pytest",
238+
"--log-file",
239+
str(pytest_log),
240+
"--log-file-level",
241+
"INFO",
242+
"--log-format",
243+
"%(asctime)s %(levelname)s %(name)s %(message)s",
244+
"--log-date-format",
245+
"%Y-%m-%dT%H:%M:%S",
246+
"--junitxml",
247+
str(pytest_junit),
248+
],
249+
cwd=PYTHON_BINDING_DIR,
250+
)
188251

189252
# 3. Node.js
190253
if NODE_DIR.exists():
191254
log("Node.js Tests...")
192255
npm = "npm.cmd" if sys.platform == "win32" else "npm"
193-
run([npm, "test"], cwd=NODE_DIR, check=False, title="Node.js Tests")
256+
run_logged(
257+
[npm, "test"],
258+
artifacts_dir / "node-test.log",
259+
NODE_DIR,
260+
"Node.js Tests",
261+
False,
262+
)
194263

195264
# Reliability/System Tests
196265
if target == "verify" or target == "all":
@@ -202,6 +271,23 @@ def task_test(args):
202271
uv_cmd = ["--with", "matplotlib", "python", str(script)]
203272
uv_run(uv_cmd, cwd=PROJECT_ROOT)
204273

274+
viz_report = (
275+
PROJECT_ROOT
276+
/ "docs"
277+
/ "traceability"
278+
/ "artifacts"
279+
/ "latest"
280+
/ "verify_reliability_report.md"
281+
)
282+
viz = SCRIPTS_DIR / "visualize_results.py"
283+
uv_run(
284+
["--with", "matplotlib", "python", str(viz), str(viz_report)],
285+
cwd=PROJECT_ROOT,
286+
)
287+
288+
diagram = SCRIPTS_DIR / "generate_diagram.py"
289+
uv_run(["--with", "matplotlib", "python", str(diagram)], cwd=PROJECT_ROOT)
290+
205291
linker = SCRIPTS_DIR / "link_test_ids.py"
206292
run(
207293
[sys.executable, str(linker)],
@@ -244,10 +330,19 @@ def task_viz(args):
244330
"""Generate reports/charts."""
245331
log("Running Visualization...")
246332
script = SCRIPTS_DIR / "visualize_results.py"
247-
report_file = PROJECT_ROOT / "docs" / "test_report.md"
333+
report_file = (
334+
PROJECT_ROOT
335+
/ "docs"
336+
/ "traceability"
337+
/ "artifacts"
338+
/ "latest"
339+
/ "verify_reliability_report.md"
340+
)
248341

249342
if not report_file.exists():
250-
warn("No test_report.md found. Run 'bridge.py test verify' first.")
343+
warn(
344+
"No verify_reliability_report.md found. Run 'bridge.py test verify' first."
345+
)
251346

252347
# We pass the log file path if needed, but the script defaults to test_report.md logic
253348
# Actually the script takes the report file as arg 1

docs/latency_histogram.png

-41.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)