v3.22.7: a raised card error honours the step's on_fail
The runner's step loop caught an exception and hard-coded status "error" + stop, ignoring on_fail - so a file-read of an absent optional file (re-verified live on 3.22.6: MF/A153/49AC, note "6a82: Wrong parameters - File not found", on_fail "warning" still stopped the run) could not express the "read an optional file" pattern (49AC is documented optional: its absence means no menu password). The handler now treats a raised error as a failed "Error" check at the step's level (the message as actual/detail and the note): on_fail "warning" warns and the run continues, the default still stops; the drain-if-pending behaviour is unchanged. Every raised exception is treated the same - the two "file absent" raise paths (pySim's SwMatchError for model files and probe_file's RuntimeError with the decoded SW for custom FIDs) cannot be told apart by type, and load-time validation (normalise_script) stays strict. Docs: the guide's on_fail paragraph and run-errors list (the 6A82 bullet), api.md and help EN/RU. Tests: a raising file-read with on_fail "warning" warns and the next step runs; without on_fail the run still stops. 843 frontend + 821 Python; sw cache simple-v411.
This commit is contained in:
@@ -1690,6 +1690,50 @@ class TestRunnerActions(RunnerTestCase):
|
||||
self.assertEqual(lchan.written, 'AA55')
|
||||
self.assertEqual(run['steps'][1]['data'], 'AA55')
|
||||
|
||||
def test_a_raised_card_error_honours_on_fail(self):
|
||||
# v3.22.7: a card error raised during a step (an absent optional
|
||||
# file's 6A82, a refused SELECT) is a step failure like any other -
|
||||
# on_fail "warning" warns and the run continues.
|
||||
lchan = object() # _select_path (patched) raises before its use
|
||||
server = FakeServer(FakeScc())
|
||||
server.app = type('App', (), {'rs': type('Rs', (), {'lchan': [lchan]})()})()
|
||||
server.scc.push('80F2', '', '9000')
|
||||
with mock.patch.object(S, '_select_path', side_effect=RuntimeError(
|
||||
'6a82: Wrong parameters - File not found')):
|
||||
run = self.run_script(server, [
|
||||
{'type': 'action', 'kind': 'file-read',
|
||||
'params': {'path': 'MF/A153/49AC'}, 'on_fail': 'warning'},
|
||||
{'type': 'action', 'kind': 'status', 'params': {}},
|
||||
])
|
||||
self.assertEqual(run['status'], 'warning', run['steps'])
|
||||
self.assertEqual(len(run['steps']), 2)
|
||||
entry = run['steps'][0]
|
||||
self.assertEqual(entry['status'], 'warning')
|
||||
self.assertIn('6a82', entry['note'])
|
||||
check = entry['checks'][0]
|
||||
self.assertEqual(check['label'], 'Error')
|
||||
self.assertFalse(check['ok'])
|
||||
self.assertEqual(check['level'], 'warning')
|
||||
self.assertIn('6a82', check['actual'])
|
||||
# the following step ran
|
||||
self.assertEqual(run['steps'][1]['status'], 'ok')
|
||||
|
||||
def test_a_raised_card_error_still_stops_by_default(self):
|
||||
lchan = object() # _select_path (patched) raises before its use
|
||||
server = FakeServer(FakeScc())
|
||||
server.app = type('App', (), {'rs': type('Rs', (), {'lchan': [lchan]})()})()
|
||||
with mock.patch.object(S, '_select_path', side_effect=RuntimeError(
|
||||
'6a82: Wrong parameters - File not found')):
|
||||
run = self.run_script(server, [
|
||||
{'type': 'action', 'kind': 'file-read',
|
||||
'params': {'path': 'MF/A153/49AC'}},
|
||||
{'type': 'action', 'kind': 'status', 'params': {}},
|
||||
])
|
||||
self.assertEqual(run['status'], 'error', run['steps'])
|
||||
self.assertEqual(len(run['steps']), 1)
|
||||
self.assertEqual(run['steps'][0]['status'], 'error')
|
||||
self.assertIn('6a82', run['steps'][0]['note'])
|
||||
|
||||
def test_run_guard_blocks_card_endpoints_only(self):
|
||||
S._TEST_RUNNING = True
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user