Package workstation tools, reuse emulator sessions, and derive build versions

This commit is contained in:
2026-09-23 03:45:48 +08:00
parent 6bfcce8070
commit f5d9f96409
79 changed files with 878 additions and 132 deletions
+29 -2
View File
@@ -104,13 +104,17 @@ def interactive_program_checks():
os.write(master, b'\x03')
until(b'RETURN:130\r\n')
until(b'FDS> ')
os.write(master, b"b01:demo.report:shell -c 'printf \"STOP:%s\\n\" ready; exec tail -f /dev/null'\n")
os.write(master, b"b01:demo.report:shell -c 'printf \"STOP:%s\\n\" ready; read -r resumed; printf \"RESUMED:%s\\n\" \"$resumed\"; exec tail -f /dev/null'\n")
until(b'STOP:ready\r\n')
os.write(master, b'\x1a')
until(b'Stopped')
until(b'FDS> ')
os.write(master, b'fg\n')
until(b"exec tail -f /dev/null'\r\n")
# The fg command echo precedes terminal handoff and SIGCONT. Require
# actual input/output from the resumed foreground program before Ctrl-C.
os.write(master, b'continue\n')
until(b'RESUMED:continue\r\n')
os.write(master, b'\x03')
until(b'FDS> ')
os.write(master, b"test \"$(stty -g)\" = \"$(cat /tmp/program-tty-before)\" && printf 'RESTORE:%s\\n' passed\n")
@@ -156,6 +160,9 @@ original_software = digest(software)
try:
report = json.loads(invoke('start', *start_options))
assert report['qemu']['running']
initial_state = (session / 'session.json').read_bytes()
invoke('start', *start_options, ok=False)
assert (session / 'session.json').read_bytes() == initial_state
assert guest('id', '-u').strip() == '1000'
master, slave = pty.openpty()
original_termios = termios.tcgetattr(slave)
@@ -280,6 +287,24 @@ try:
guest('fds', 'run', 12, '--', 'demo.report:report', 'hold')
invoke('stop')
assert 'FDS_SHUTDOWN_FINAL' in (session / 'console.log').read_text()
retained_log = (session / 'console.log').read_bytes()
retained_data = {p: digest(p) for p in session.glob('data-*.qcow2')}
assert retained_data
previous_state = json.loads((session / 'session.json').read_text())
restarted = json.loads(invoke('start', *start_options))
assert restarted['qemu']['running'] and restarted['state']['cartridges'] == {}
assert restarted['state']['name'] != previous_state['name']
assert any(json.loads(p.read_text()) == previous_state for p in session.glob('previous-*.json'))
assert (session / 'console.log').read_bytes().startswith(retained_log)
assert all(digest(p) == value for p, value in retained_data.items())
assert guest('id', '-u').strip() == '1000'
assert all(b['state'] == 'empty' for b in query('bays')['bays'])
invoke('insert', 1, software); wait_bay(1, 'mounted_read_only')
assert 'Hello from' in guest('hello', 'restarted')
invoke('stop', '--force')
assert json.loads(invoke('start', *start_options))['qemu']['running']
assert guest('id', '-u').strip() == '1000'
invoke('stop')
finally:
subprocess.run([cli, '--session', str(session), 'stop', '--force'], capture_output=True, timeout=40)
@@ -340,7 +365,9 @@ record = dict(status='passed', ordinary_guest_uid=1000, public_emulator_cli=True
safe_eject=True, forced_removal_stops_consumer=True,
corrupt_program_and_catalogue_rejected=True, data_overlay_preserves_source=True,
restart_cleans_mounts_commands_and_consumers=True, extra_mount_blocks_safe=True,
native_shutdown_with_active_software=True, physical_pi='not tested')
native_shutdown_with_active_software=True, same_directory_restart_after_stop=True,
same_directory_restart_after_force=True, restart_retains_logs_overlays_and_mapping=True,
live_session_restart_rejected=True, physical_pi='not tested')
(work / 'acceptance.json').write_text(json.dumps(record, indent=2) + '\n')
(project / 'out/workstation-emulator-current.txt').write_text(str(work) + '\n')
print('PASS: public emulator, guest software and lifecycle acceptance:', work)