Files
FreeCADWasmDev/tools/test_business_timeout.py

71 lines
4.1 KiB
Python

import json
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import time
import unittest
from unittest.mock import patch
import run_module_batch_pipeline as pipeline
from prepare_module_implementation_packet import acceptance_build_for_ids, frontend_acceptance_build
class BusinessTimeoutTests(unittest.TestCase):
def test_mixed_product_and_desktop_web_batch_retains_its_declared_frontend_owner(self):
contract = {"build": {"kind": "frontend", "tree": "web", "target": "FreeCADWebReactProduct"}}
declared, explicit = acceptance_build_for_ids(contract, {"product:file-workflows", "Web:desktop:Std_Open"})
self.assertTrue(explicit)
self.assertEqual(frontend_acceptance_build(declared)["runtime"], "web/dist/index.html")
with self.assertRaises(ValueError):
frontend_acceptance_build({**declared, "tree": "../outside"})
def test_outer_timeout_includes_declared_case_and_selected_verifiers(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
contracts = root / "docs/business-acceptance"
contracts.mkdir(parents=True)
(contracts / "Web.json").write_text(json.dumps({"timeoutSeconds": 840}))
rows = [{"id": "web"}, {"id": "ifc", "independentVerification": ["node", "verify.mjs"]}]
with patch.object(pipeline, "ROOT", root), patch("business_acceptance.requirements", return_value=rows):
self.assertEqual(pipeline.business_timeout({"selected": {"module": "Web"}, "records": [["web"]]}), 870)
self.assertEqual(pipeline.business_timeout({"selected": {"module": "BIM"}, "records": [["ifc"]]}), 390)
(contracts / "Web.json").write_text(json.dumps({"timeoutSeconds": True}))
self.assertEqual(pipeline.business_timeout({"selected": {"module": "Web"}, "records": [["web"]]}), 210)
def test_outer_timeout_cleans_real_runner_case_and_grandchild(self):
tools = Path(__file__).resolve().parent
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
current = root / "docs/current"
current.mkdir(parents=True)
contracts = root / "docs/business-acceptance"
contracts.mkdir()
(current / "feature-capability-registry.json").write_text(json.dumps({"records": [
{"id": "Web:timeout", "module": "Web", "command": "timeout"}]}))
(contracts / "Web.json").write_text(json.dumps({"command": ["python3", "case.py"], "timeoutSeconds": 30}))
child = "import time; from pathlib import Path; time.sleep(3); Path('orphan').write_text('bad')"
(root / "case.py").write_text("import subprocess,sys,time\nsubprocess.Popen([sys.executable,'-c',"
+ repr(child) + "])\nfrom pathlib import Path\nPath('started').touch()\nprint('case started',flush=True)\ntime.sleep(30)\n")
wrapper = (f"import sys,runpy; from pathlib import Path; sys.path.insert(0,{str(tools)!r}); "
f"import business_acceptance as b; b.ROOT=Path({str(root)!r}); b.LEDGER=b.ROOT/'docs/current/business-acceptance.json'; "
f"sys.argv=['runner','--module','Web','--ids','Web:timeout']; runpy.run_path({str(tools / 'run_business_acceptance.py')!r},run_name='__main__')")
with self.assertRaises(subprocess.TimeoutExpired):
pipeline.run_business_process([sys.executable, "-c", wrapper], root, dict(os.environ), 1)
self.assertTrue((root / "started").exists())
time.sleep(2.5)
self.assertFalse((root / "orphan").exists())
def test_timeout_retains_wrapper_diagnostics(self):
with self.assertRaises(subprocess.TimeoutExpired) as caught:
pipeline.run_business_process([sys.executable, "-c",
"import sys,time; print('outer-start',flush=True); print('error-detail',file=sys.stderr,flush=True); time.sleep(30)"],
Path.cwd(), dict(os.environ), 0.2)
self.assertIn("outer-start", caught.exception.output)
self.assertIn("error-detail", caught.exception.stderr)
if __name__ == "__main__":
unittest.main()