Update workstation UI, ROS task control and device integration

This commit is contained in:
cheng
2026-10-20 15:46:13 +08:00
parent 2b74c50ba8
commit e5b06df6da
141 changed files with 91520 additions and 748 deletions
+40
View File
@@ -19,3 +19,43 @@ class ProcessesTest(TestCase):
processes.run('long',[sys.executable,'-c','import time;time.sleep(30)'],event)
self.assertFalse(processes.snapshot()['long']['running'])
finally: processes.close()
def test_each_run_has_its_own_log_slice_and_explicit_owner(self):
with tempfile.TemporaryDirectory() as directory:
processes=ProcessSupervisor(directory)
try:
processes.run('tool:89',[sys.executable,'-c','print("OLD_FAILURE")'],threading.Event())
result=processes.run('tool:89',[sys.executable,'-c','print("NEW_RESULT")'],threading.Event())
self.assertIn('NEW_RESULT',result['detail']);self.assertNotIn('OLD_FAILURE',result['detail'])
row=processes.snapshot()['tool:89']
self.assertEqual(row['owner'],'station');self.assertEqual(row['state'],'exited')
finally: processes.close()
def test_success_waits_for_orphaned_child_cleanup(self):
from pathlib import Path
from arm_application.process_lifecycle import _stat
with tempfile.TemporaryDirectory() as directory:
processes=ProcessSupervisor(directory)
pidfile=Path(directory)/'pid'
source="import subprocess,sys,time;from pathlib import Path;p=subprocess.Popen([sys.executable,'-c','import time;time.sleep(120)'],start_new_session=True);Path(sys.argv[1]).write_text(str(p.pid))"
try:
result=processes.run('motion:89',[sys.executable,'-c',source,str(pidfile)],threading.Event(),timeout=12)
self.assertTrue(result['ok'],result)
child=int(pidfile.read_text());state=_stat(child)
self.assertTrue(state is None or state[2]=='Z','task reported success with a live orphan')
finally: processes.close()
def test_process_cleanup_phase_is_reported_before_resource_release(self):
from pathlib import Path
with tempfile.TemporaryDirectory() as directory:
processes=ProcessSupervisor(directory)
ready=Path(directory)/'ready'
child="import signal,time,sys;from pathlib import Path;signal.signal(signal.SIGINT,lambda *a:(time.sleep(.4),sys.exit(0)));Path(sys.argv[1]).write_text('ready');time.sleep(20)"
source="import subprocess,sys,time;from pathlib import Path;subprocess.Popen([sys.executable,'-c',sys.argv[1],sys.argv[2]],start_new_session=True)\nwhile not Path(sys.argv[2]).exists():time.sleep(.01)"
phases=[]
try:
result=processes.run('motion:89',[sys.executable,'-c',source,child,str(ready)],threading.Event(),timeout=8,on_phase=phases.append)
self.assertTrue(result['ok'],result)
self.assertIn('收尾',phases)
self.assertFalse(processes.snapshot()['motion:89']['running'])
finally: processes.close()