mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 05:23:41 +08:00
82daa5bbe9
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
102 lines
3.1 KiB
Python
102 lines
3.1 KiB
Python
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import time
|
|
import unittest
|
|
|
|
from openpilot.starpilot.software.fast_update import run
|
|
|
|
|
|
class TestUpdateProcess(unittest.TestCase):
|
|
def setUp(self):
|
|
self.temporary = tempfile.TemporaryDirectory()
|
|
self.addCleanup(self.temporary.cleanup)
|
|
self.directory = Path(self.temporary.name)
|
|
|
|
def command(self, source):
|
|
script = self.directory / 'command.py'
|
|
script.write_text(source)
|
|
return [sys.executable, '-u', str(script)]
|
|
|
|
def test_output_and_failure(self):
|
|
command = self.command("import sys\nprint('first')\nprint('last', file=sys.stderr)\nsys.exit(7)\n")
|
|
with self.assertRaises(subprocess.CalledProcessError) as error:
|
|
run(command, self.directory)
|
|
self.assertEqual(error.exception.returncode, 7)
|
|
self.assertEqual(error.exception.output, b'first\nlast\n')
|
|
|
|
def test_progress_and_success(self):
|
|
command = self.command("print('Receiving objects: 50%\\rReceiving objects: 100%')\nprint('done')\n")
|
|
progress = []
|
|
result = run(command, self.directory, progress.append)
|
|
self.assertEqual(result, 'Receiving objects: 50%\rReceiving objects: 100%\ndone\n')
|
|
self.assertEqual(progress, ['Receiving objects: 50%', 'Receiving objects: 100%'])
|
|
|
|
def test_timeout_allows_lock_cleanup(self):
|
|
command = self.command("""import signal
|
|
import time
|
|
from pathlib import Path
|
|
|
|
def terminate(*_):
|
|
raise SystemExit(1)
|
|
|
|
signal.signal(signal.SIGTERM, terminate)
|
|
lock = Path('shallow.lock')
|
|
lock.touch()
|
|
print('locked')
|
|
try:
|
|
time.sleep(60)
|
|
finally:
|
|
lock.unlink()
|
|
""")
|
|
with self.assertRaises(subprocess.TimeoutExpired) as error:
|
|
run(command, self.directory, timeout=0.5)
|
|
self.assertEqual(error.exception.output, b'locked\n')
|
|
self.assertFalse((self.directory / 'shallow.lock').exists())
|
|
|
|
def test_stubborn_command_is_killed(self):
|
|
command = self.command("""import os
|
|
import signal
|
|
import time
|
|
signal.signal(signal.SIGTERM, signal.SIG_IGN)
|
|
print(os.getpid())
|
|
time.sleep(60)
|
|
""")
|
|
started = time.monotonic()
|
|
with self.assertRaises(subprocess.TimeoutExpired) as error:
|
|
run(command, self.directory, timeout=0.5)
|
|
self.assertLess(time.monotonic() - started, 8)
|
|
with self.assertRaises(ProcessLookupError):
|
|
os.kill(int(error.exception.output.strip()), 0)
|
|
|
|
def test_exited_parent_with_child_pipe_is_bounded(self):
|
|
command = self.command("""import subprocess
|
|
import sys
|
|
import time
|
|
from pathlib import Path
|
|
subprocess.Popen([sys.executable, '-u', '-c', '''import signal
|
|
import time
|
|
from pathlib import Path
|
|
def terminate(*_):
|
|
Path('child_stopped').touch()
|
|
raise SystemExit(0)
|
|
signal.signal(signal.SIGTERM, terminate)
|
|
Path('child_ready').touch()
|
|
time.sleep(60)
|
|
'''])
|
|
while not Path('child_ready').exists():
|
|
time.sleep(0.01)
|
|
print('parent exited')
|
|
""")
|
|
started = time.monotonic()
|
|
with self.assertRaises(subprocess.TimeoutExpired):
|
|
run(command, self.directory, timeout=0.5)
|
|
self.assertLess(time.monotonic() - started, 8)
|
|
self.assertTrue((self.directory / 'child_stopped').exists())
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|