v3.25.1: the run-ownership fix for the proactive auto-handling
A card that re-queues a command immediately after each accepted TR (live 2026-10-11: the EP BAP card re-issued the same PROVIDE LOCAL INFORMATION 1100 times) turned the background poll's FETCH/TR chain into an unbounded loop that held _CARD_LOCK forever - every card operation, a test run's start included, blocked behind it. The chain now yields: - _handle_proactive_chain aborts before the next FETCH while a test run owns the card (_TEST_RUNNING) - the pending command stays for the script - and takes max_rounds; the background poll passes _POLL_CHAIN_MAX = 10, so a chatty card cannot hold the lock. - _do_status_poll re-arms on its run skip (a heartbeat that never fetches); _timer_expired and the BIP Data-available event wait during a run; _bip_flush_channel_events stays quiet too. - _sim_resume_poll() resumes polling at every run end - the two worker bodies, their exception paths and the spawn failure. Also the TR command-details qualifier echo (TS 102 223 6.8.1: the object shall be identical to the command's): _build_tr, testscript.build_tr and the interactive _menu_send_response echoed a hardcoded 00 - harmless for the loop's qual-00 PLI, wrong for any other qualifier. The menu pendings now carry cmd_qual (parsed in the on_fetch handler). Tests: the chain bound/abort (a fake card re-queueing a command), the poll/timer guards, the resume wiring, the qualifier echo in both builders. 883 frontend + 865 Python; sw cache simple-v425.
This commit is contained in:
@@ -863,6 +863,20 @@ class TestProactiveDecode(unittest.TestCase):
|
||||
tr = _build_tr(None, 1, 0x26, 0x81, 0x82, 0x00)
|
||||
self.assertEqual(tr.hex(), '81030126008202828103010093055210011000')
|
||||
|
||||
def test_build_tr_echoes_the_command_qualifier(self):
|
||||
# TS 102 223 6.8.1: the TR's command details shall be identical to
|
||||
# the command's (including the qualifier); without one they stay 00
|
||||
self.assertTrue(_build_tr(None, 1, 0x26, 0x81, 0x82, 0x06)
|
||||
.hex().startswith('8103012606'))
|
||||
self.assertTrue(_build_tr(None, 1, 0x03, 0x81, 0x82, None)
|
||||
.hex().startswith('8103010300'))
|
||||
# the runner's builder echoes the same way
|
||||
from pysim_simple_server import testscript as T
|
||||
self.assertTrue(T.build_tr(1, 0x26, 0x82, 0x81, {}, cmd_qual=0x06)
|
||||
.hex().startswith('8103012606'))
|
||||
self.assertTrue(T.build_tr(1, 0x26, 0x82, 0x81, {})
|
||||
.hex().startswith('8103012600'))
|
||||
|
||||
def test_build_tr_poll_interval_duration_after_result(self):
|
||||
import pysim_simple_server.server as srv
|
||||
tr = _build_tr(None, 1, 0x03, 0x81, 0x82, None)
|
||||
@@ -884,11 +898,12 @@ class TestProactiveDecode(unittest.TestCase):
|
||||
tr_west = _build_tr(None, 1, 0x26, 0x81, 0x82, 0x03, west)
|
||||
finally:
|
||||
srv._PLI_DATA[0x03] = saved
|
||||
# the command details echo the qualifier (TS 102 223 6.8.1)
|
||||
self.assertEqual(tr_east.hex(),
|
||||
'810301260082028281030100260762900312550021')
|
||||
'810301260382028281030100260762900312550021')
|
||||
# negative zone: the sign bit of the time zone byte (0x08)
|
||||
self.assertEqual(tr_west.hex(),
|
||||
'810301260082028281030100260762105080709009')
|
||||
'810301260382028281030100260762105080709009')
|
||||
|
||||
def test_build_tr_pli_dict_entry_overrides_host_clock(self):
|
||||
import pysim_simple_server.server as srv
|
||||
@@ -900,7 +915,7 @@ class TestProactiveDecode(unittest.TestCase):
|
||||
datetime(2026, 9, 30, 21, 55, tzinfo=timezone.utc))
|
||||
finally:
|
||||
srv._PLI_DATA[0x03] = saved
|
||||
self.assertEqual(tr.hex(), '810301260082028281030100130752f01000ff0001')
|
||||
self.assertEqual(tr.hex(), '810301260382028281030100130752f01000ff0001')
|
||||
|
||||
def test_build_tr_pli_empty_other_qualifier_sends_no_data(self):
|
||||
# a qualifier with neither an override nor a built-in default (02
|
||||
@@ -913,7 +928,7 @@ class TestProactiveDecode(unittest.TestCase):
|
||||
data = srv._pli_data_hex(0x02)
|
||||
finally:
|
||||
srv._PLI_DATA[0x02] = saved
|
||||
self.assertEqual(tr.hex(), '810301260082028281030100')
|
||||
self.assertEqual(tr.hex(), '810301260282028281030100')
|
||||
self.assertEqual(data, '')
|
||||
|
||||
def test_pli_defaults_cover_the_common_qualifiers(self):
|
||||
|
||||
Reference in New Issue
Block a user