mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-04 13:24:13 +08:00
Reserve Mac replay ownership before showcase preparation
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
"""Exclusive Mac showcase ownership while the compiled camera port is global."""
|
||||
from contextlib import contextmanager
|
||||
import errno
|
||||
import fcntl
|
||||
import os
|
||||
from pathlib import Path
|
||||
import socket
|
||||
|
||||
|
||||
class ReplayBusy(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def check_camera_port():
|
||||
"""Check the existing IPv4 ZMQ publisher bind without connecting or sending."""
|
||||
try:
|
||||
with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as probe:
|
||||
# Match a normal listening socket's restart behavior after TIME_WAIT.
|
||||
probe.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
|
||||
probe.bind(('0.0.0.0',9000))
|
||||
except OSError as error:
|
||||
if error.errno==errno.EADDRINUSE:
|
||||
raise ReplayBusy('Mac replay camera port 9000 is already in use. Close the existing Mac replay before starting another.') from None
|
||||
raise ReplayBusy('Cannot verify Mac replay camera port 9000: '+str(error)) from error
|
||||
|
||||
|
||||
@contextmanager
|
||||
def mac_replay_lease(root, *, port_check=None):
|
||||
"""Hold this descriptor until parent cleanup ends; children never inherit it."""
|
||||
path=Path(root)/'generated/mac_showcase.lock'
|
||||
path.parent.mkdir(parents=True,exist_ok=True)
|
||||
with path.open('a+') as lease:
|
||||
os.set_inheritable(lease.fileno(),False)
|
||||
try:fcntl.flock(lease,fcntl.LOCK_EX|fcntl.LOCK_NB)
|
||||
except BlockingIOError:
|
||||
raise ReplayBusy('A Mac RoadScore replay is already running. Close its existing demo before starting another.') from None
|
||||
try:
|
||||
(check_camera_port if port_check is None else port_check)()
|
||||
yield lease
|
||||
finally:fcntl.flock(lease,fcntl.LOCK_UN)
|
||||
|
||||
|
||||
def preflight(root):
|
||||
"""Advisory check before paired launch; the Mac parent later holds its lease."""
|
||||
with mac_replay_lease(root):pass
|
||||
@@ -411,6 +411,14 @@ def main():
|
||||
return audio_worker(a)
|
||||
if a.no_control_server:raise SystemExit('--no-control-server is an internal prepared audio-worker option')
|
||||
if sys.platform!='darwin' or Path('/TICI').exists():raise SystemExit('Prepared Mac showcase runs only on the Mac')
|
||||
if a.check:return parent_main(a)
|
||||
from mac_replay_ownership import ReplayBusy, mac_replay_lease
|
||||
try:
|
||||
with mac_replay_lease(a.project_root.resolve()/'roadscore'):return parent_main(a)
|
||||
except ReplayBusy as error:raise SystemExit(str(error)) from None
|
||||
|
||||
|
||||
def parent_main(a):
|
||||
launch_started=time.monotonic()
|
||||
project=a.project_root.resolve();rt=a.runtime or project/'.host_runtime/darwin/worktree'
|
||||
py=rt.parent/'venv/bin/python'
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import errno
|
||||
import os
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import mac_showcase
|
||||
from mac_replay_ownership import ReplayBusy, check_camera_port, mac_replay_lease, preflight
|
||||
|
||||
|
||||
class MacReplayOwnershipTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
temporary=tempfile.TemporaryDirectory();self.addCleanup(temporary.cleanup)
|
||||
self.root=Path(temporary.name)
|
||||
|
||||
def test_two_real_descriptors_are_exclusive_and_release_on_exception(self):
|
||||
check=MagicMock()
|
||||
with self.assertRaisesRegex(ValueError,'fixture failure'):
|
||||
with mac_replay_lease(self.root,port_check=check) as held:
|
||||
self.assertFalse(os.get_inheritable(held.fileno()))
|
||||
with self.assertRaises(ReplayBusy):
|
||||
with mac_replay_lease(self.root,port_check=check):self.fail('Second lease acquired')
|
||||
self.assertEqual(check.call_count,1)
|
||||
raise ValueError('fixture failure')
|
||||
with mac_replay_lease(self.root,port_check=check):pass
|
||||
self.assertEqual(check.call_count,2)
|
||||
|
||||
def test_port_failure_releases_lease_and_preflight_does_not_hold_it(self):
|
||||
with patch('mac_replay_ownership.check_camera_port',side_effect=ReplayBusy('busy')):
|
||||
with self.assertRaises(ReplayBusy):preflight(self.root)
|
||||
with patch('mac_replay_ownership.check_camera_port') as check:
|
||||
preflight(self.root)
|
||||
with mac_replay_lease(self.root):pass
|
||||
self.assertEqual(check.call_count,2)
|
||||
|
||||
def test_port_probe_reports_busy_without_connecting_or_sending(self):
|
||||
probe=MagicMock();probe.__enter__.return_value=probe
|
||||
with patch('mac_replay_ownership.socket.socket',return_value=probe):
|
||||
check_camera_port()
|
||||
probe.bind.assert_called_once_with(('0.0.0.0',9000))
|
||||
probe.connect.assert_not_called();probe.send.assert_not_called()
|
||||
probe.bind.side_effect=OSError(errno.EADDRINUSE,'in use')
|
||||
with self.assertRaisesRegex(ReplayBusy,'port 9000'):check_camera_port()
|
||||
|
||||
def test_parent_holds_lease_before_any_preparation(self):
|
||||
args=mac_showcase.parser().parse_args(['--project-root',str(self.root)])
|
||||
def prepared(value):
|
||||
with self.assertRaises(ReplayBusy):
|
||||
with mac_replay_lease(self.root/'roadscore',port_check=lambda:None):pass
|
||||
return 17
|
||||
with (patch('mac_showcase.parser') as parser,patch('mac_showcase.parent_main',side_effect=prepared) as parent,
|
||||
patch('mac_showcase.sys.platform','darwin'),patch('mac_replay_ownership.check_camera_port')):
|
||||
parser.return_value.parse_args.return_value=args
|
||||
self.assertEqual(mac_showcase.main(),17)
|
||||
parent.assert_called_once_with(args)
|
||||
with mac_replay_lease(self.root/'roadscore',port_check=lambda:None):pass
|
||||
|
||||
def test_worker_and_check_never_acquire_parent_lease(self):
|
||||
for flags,target in ((['--audio-worker'],'audio_worker'),(['--check'],'parent_main')):
|
||||
args=mac_showcase.parser().parse_args(flags)
|
||||
with (patch('mac_showcase.parser') as parser,patch('mac_showcase.'+target,return_value=23),
|
||||
patch('mac_showcase.sys.platform','darwin'),patch('mac_replay_ownership.mac_replay_lease') as lease):
|
||||
parser.return_value.parse_args.return_value=args
|
||||
self.assertEqual(mac_showcase.main(),23)
|
||||
lease.assert_not_called()
|
||||
|
||||
|
||||
if __name__=='__main__':unittest.main()
|
||||
Reference in New Issue
Block a user