qemu: rs485 silence|restore takes a simulated device off the bus mid-run
ui-drive.sh --rs485-devices fixed the roster for the whole boot, so no script could show the guest noticing a device go quiet. mbsim.py now serves a control socket (flare-edge --control); ui-drive.sh opens it next to the pty and hands its path to qmp.py drive (--rs485-control), whose new verb `rs485 silence|restore ADDR` sends one command and judges the reply. A run without a simulated bus records the step as fatal rather than a silent pass. Rig: unit 5 silenced reads online=false after 65 s in the status json, restored reads online=true after 64 s (flare-edge #184). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3G6m9Aw5RyVY4ZowtKzEj
This commit is contained in:
@@ -62,7 +62,7 @@ def fake_rpc(sock, sock_file, obj):
|
||||
return {}
|
||||
|
||||
|
||||
def run_script(text, refs=None):
|
||||
def run_script(text, refs=None, rs485_control=None):
|
||||
"""-> (exit code or None, {cmd: row}, rows) for one drive() over TEXT."""
|
||||
outdir = tempfile.mkdtemp(prefix="qmpdrive.")
|
||||
script = os.path.join(outdir, "s.txt")
|
||||
@@ -78,7 +78,7 @@ def run_script(text, refs=None):
|
||||
try:
|
||||
try:
|
||||
qmp.drive(None, None, script, outdir, SIZE, ctl_path="fake",
|
||||
console_path=None, refs_path=refs_path)
|
||||
console_path=None, refs_path=refs_path, rs485_control=rs485_control)
|
||||
except SystemExit as e:
|
||||
rc = e.code
|
||||
finally:
|
||||
@@ -190,6 +190,26 @@ class DriveVerbs(unittest.TestCase):
|
||||
self.assertIn("cannot capture", by["capture_region huge 0 0 999 999 exact"]["detail"])
|
||||
self.assertIn("unknown tolerance", by["capture_region r2 0 0 8 8 fuzzy"]["detail"])
|
||||
|
||||
def test_rs485_verb_talks_to_the_simulator_or_is_fatal(self):
|
||||
sent = []
|
||||
|
||||
def fake_send(path, line):
|
||||
sent.append((path, line))
|
||||
return "ok 5 silent" if line.startswith("silence") else "error no simulated device at 9"
|
||||
|
||||
saved = qmp.rs485_send
|
||||
qmp.rs485_send = fake_send
|
||||
try:
|
||||
rc, by, rows = run_script("rs485 silence 5\nrs485 restore 9\nrs485 bounce 5\n",
|
||||
rs485_control="fake.ctl")
|
||||
finally:
|
||||
qmp.rs485_send = saved
|
||||
self.assertEqual([r["status"] for r in rows], ["ok", "fail", "fatal"])
|
||||
self.assertEqual(sent, [("fake.ctl", "silence 5"), ("fake.ctl", "restore 9")])
|
||||
rc, by, rows = run_script("rs485 silence 5\n")
|
||||
self.assertEqual(rows[0]["status"], "fatal", "no bus in the run must not look like a pass")
|
||||
self.assertIn("no simulated RS485 bus", rows[0]["detail"])
|
||||
|
||||
def test_unknown_verb_is_fatal_for_the_run(self):
|
||||
# A silently-ignored line is a test that proves nothing, so this one
|
||||
# is the documented exception to "the run continues": drive() exits
|
||||
|
||||
Reference in New Issue
Block a user