60 lines
2.8 KiB
Python
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()
|