Files
FreeCADWasmDev/tools/test_web_build_lock.py
wangdequan 9a7c4f0335 Save FreeCAD Web workspace sources and user validation evidence
IFC native binding remains incomplete; preserve accurate test results.
2026-09-15 22:01:58 +08:00

60 lines
2.8 KiB
Python

import fcntl
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
from unittest.mock import patch
from web_build_lock import cmake_build_tree, run_build
class BuildLockTests(unittest.TestCase):
def test_build_tree_detection_resolves_relative_paths(self):
self.assertEqual(cmake_build_tree(["/usr/bin/cmake", "--build", "cache", "--target", "Probe"], Path("/tmp")), Path("/tmp/cache"))
self.assertIsNone(cmake_build_tree(["node", "test.mjs"], Path("/tmp")))
def test_second_writer_cannot_enter_and_child_inherits_descriptor(self):
with tempfile.TemporaryDirectory() as temporary:
tree = Path(temporary)
command = ["cmake", "--build", str(tree)]
def child(_command, **kwargs):
self.assertIn("pass_fds", kwargs)
with (tree / ".freecad-web-build.lock").open("a") as second:
with self.assertRaises(BlockingIOError):
fcntl.flock(second.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
code = "import os,sys; os.fstat(int(sys.argv[1]))"
process = subprocess.Popen([sys.executable, "-c", code, str(kwargs["pass_fds"][-1])], pass_fds=kwargs["pass_fds"])
self.assertEqual(process.wait(timeout=5), 0)
return subprocess.CompletedProcess(command, 0)
with patch("web_build_lock.subprocess.run", side_effect=child):
self.assertEqual(run_build(command, cwd=tree).returncode, 0)
with (tree / ".freecad-web-build.lock").open("a") as lock:
fcntl.flock(lock.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
def test_busy_tree_times_out_without_starting_a_build(self):
with tempfile.TemporaryDirectory() as temporary:
tree = Path(temporary)
with (tree / ".freecad-web-build.lock").open("a") as lock:
fcntl.flock(lock.fileno(), fcntl.LOCK_EX)
with patch("web_build_lock.subprocess.run") as run:
with self.assertRaises(subprocess.TimeoutExpired):
run_build(["cmake", "--build", str(tree)], cwd=tree, timeout=0.03)
run.assert_not_called()
def test_nonbuild_command_is_unchanged(self):
with patch("web_build_lock.subprocess.run") as run:
run_build(["node", "case.mjs"], cwd=Path("/tmp"), timeout=2)
self.assertNotIn("pass_fds", run.call_args.kwargs)
def test_missing_tree_is_not_created(self):
with tempfile.TemporaryDirectory() as temporary:
missing = Path(temporary) / "missing"
with self.assertRaises(FileNotFoundError):
run_build(["cmake", "--build", str(missing)], cwd=Path(temporary))
self.assertFalse(missing.exists())
if __name__ == "__main__":
unittest.main()