Skip to content

Commit 5dd3447

Browse files
authored
Gracefully handle a few more XNCP parsing failures (#653)
1 parent 06eb3d9 commit 5dd3447

File tree

3 files changed

+44
-1
lines changed

3 files changed

+44
-1
lines changed

bellows/ezsp/__init__.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,14 @@ async def send_xncp_frame(
659659
if status != t.EmberStatus.SUCCESS:
660660
raise InvalidCommandError("XNCP is not supported")
661661

662-
rsp_frame = xncp.XncpCommand.from_bytes(data)
662+
try:
663+
rsp_frame = xncp.XncpCommand.from_bytes(data)
664+
except ValueError:
665+
raise InvalidCommandError(f"Invalid XNCP response: {data!r}")
666+
667+
if isinstance(rsp_frame.payload, xncp.Unknown):
668+
raise InvalidCommandError(f"XNCP firmware does not support {payload}")
669+
663670
LOGGER.debug("Received XNCP frame: %s", rsp_frame)
664671

665672
if rsp_frame.status != t.EmberStatus.SUCCESS:

bellows/ezsp/xncp.py

+5
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,8 @@ class GetFlowControlTypeReq(XncpCommandPayload):
159159
@register_command(XncpCommandId.GET_FLOW_CONTROL_TYPE_RSP)
160160
class GetFlowControlTypeRsp(XncpCommandPayload):
161161
flow_control_type: FlowControlType
162+
163+
164+
@register_command(XncpCommandId.UNKNOWN)
165+
class Unknown(XncpCommandPayload):
166+
pass

tests/test_xncp.py

+31
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,37 @@ async def test_xncp_failure(ezsp_f: EZSP) -> None:
3434
]
3535

3636

37+
async def test_xncp_failure_multiprotocol(ezsp_f: EZSP) -> None:
38+
"""Test XNCP failure with multiprotocol firmware."""
39+
ezsp_f._mock_commands["customFrame"] = customFrame = AsyncMock(
40+
return_value=[t.EmberStatus.SUCCESS, b""]
41+
)
42+
43+
with pytest.raises(InvalidCommandError):
44+
await ezsp_f.xncp_get_supported_firmware_features()
45+
46+
assert customFrame.mock_calls == [
47+
call(xncp.XncpCommand.from_payload(xncp.GetSupportedFeaturesReq()).serialize())
48+
]
49+
50+
51+
async def test_xncp_failure_unknown(ezsp_f: EZSP) -> None:
52+
"""Test XNCP failure, unknown command."""
53+
ezsp_f._mock_commands["customFrame"] = customFrame = AsyncMock(
54+
return_value=[
55+
t.EmberStatus.SUCCESS,
56+
xncp.XncpCommand.from_payload(xncp.Unknown()).serialize(),
57+
]
58+
)
59+
60+
with pytest.raises(InvalidCommandError):
61+
await ezsp_f.xncp_get_supported_firmware_features()
62+
63+
assert customFrame.mock_calls == [
64+
call(xncp.XncpCommand.from_payload(xncp.GetSupportedFeaturesReq()).serialize())
65+
]
66+
67+
3768
async def test_xncp_get_supported_firmware_features(ezsp_f: EZSP) -> None:
3869
"""Test XNCP get_supported_firmware_features."""
3970
ezsp_f._mock_commands["customFrame"] = customFrame = AsyncMock(

0 commit comments

Comments
 (0)