v3.25.6: the PLI dictionary save feedback + the timer wording

The v3.25.5 report's follow-ups: a field the server could not use was
silently dropped, and the PWA also filtered non-hex fields client-side
(never sending them).  The POST now collects them and names them in the
response - `invalid` (a malformed key/value: not hex, an odd number of
digits, a non-string value) and `unknown` (a well-formed code outside the
qualifier list), both omitted when everything was applied - and the PWA's
Save sends every field, composes "Not saved: 0A (invalid value), 18
(unknown qualifier)" (`pysimPliRejectMsg`) into a new #pli-save-msg line
under the button and shows "Not saved" briefly.

The guide's timer exception now says "card-initiated automatic action"
(the timer retries every 5 s; polling/menu are suspended, not retrying).

Docs: api.md's POST contract, help EN/RU - which also said "22 PLI
qualifiers" while the list has 25.  Tests: the rejection lists per case
(odd length, non-hex value/key, non-string, unknown code) and the
valid-save absence, the PWA message helper and the wiring pins.
887 frontend + 875 Python; sw cache simple-v430.
This commit is contained in:
2026-10-11 16:51:30 +03:00
parent f2046d7f0a
commit 9fd8238051
10 changed files with 152 additions and 36 deletions
+33
View File
@@ -199,11 +199,44 @@ class PliDictHttpTests(unittest.TestCase):
status, resp = self._req('POST', '/api/pli-dict', {'18': 'AABB'})
self.assertEqual(status, 200, resp)
self.assertNotIn(0x18, srv._PLI_DATA)
self.assertEqual(resp['unknown'], ['18'])
self.assertEqual(resp['0A'], '630103')
finally:
srv._PLI_DATA.clear()
srv._PLI_DATA.update(saved)
def test_rejected_values_are_reported(self):
# a field the server cannot use is named in the response, never
# silently dropped (v3.25.6): the PWA shows it under the Save button
import pysim_simple_server.server as srv
saved = dict(srv._PLI_DATA)
try:
# an odd-length hex value
status, resp = self._req('POST', '/api/pli-dict', {'0A': '63010'})
self.assertEqual(status, 200, resp)
self.assertEqual(resp['invalid'], ['0A'])
self.assertNotIn(0x0A, srv._PLI_DATA)
self.assertEqual(resp['0A'], srv.PLI_DEFAULTS[0x0A])
# a non-hex value and a non-hex key
status, resp = self._req('POST', '/api/pli-dict', {'0A': 'ZZ', '0G': 'AA'})
self.assertEqual(sorted(resp['invalid']), ['0A', '0G'])
self.assertNotIn('unknown', resp)
# a non-string value
status, resp = self._req('POST', '/api/pli-dict', {'0A': 123})
self.assertEqual(resp['invalid'], ['0A'])
# an unknown (well-formed) qualifier
status, resp = self._req('POST', '/api/pli-dict', {'18': 'AABB'})
self.assertEqual(resp['unknown'], ['18'])
self.assertNotIn('invalid', resp)
# a valid save carries neither rejection list
status, resp = self._req('POST', '/api/pli-dict', {'0A': '630102'})
self.assertEqual(resp['0A'], '630102')
self.assertNotIn('invalid', resp)
self.assertNotIn('unknown', resp)
finally:
srv._PLI_DATA.clear()
srv._PLI_DATA.update(saved)
class CardFreeGetTests(unittest.TestCase):
"""Cached GETs must answer while the card lock is held.