Skip to content

Commit

Permalink
Ensure version-specific unit tests cover command sending format (#639)
Browse files Browse the repository at this point in the history
* Use the correct kwarg when sending `setPolicy`

* Ensure mocked EZSP functions enforce their signature

* Migrate v4

* Migrate v5

* Migrate v6

* Migrate v7

* Migrate v9

* Migrate v10

* Migarte 11

* Migrate v12

* Migrate v13

* Migrate v14

* Fix v7 import

* Ensure application unit tests mock as little of EZSP as possible

* Avoid mocking EZSP when testing multicast

* Explicitly stop EZSP in unit test testing for stopped EZSP

* Test no-op `add_transient_link_key`

* Oops

* Fix all slow unit tests

* Use `call_count` instead of `await_count`

* Revert "Use `call_count` instead of `await_count`"

This reverts commit 8752c61.

* Try `sleep` :)

* Revert "Try `sleep` :)"

This reverts commit 2a5afc1.

* Fix flaky test (hopefully)
  • Loading branch information
puddly authored Jul 24, 2024
1 parent 61f7ec0 commit 595a285
Show file tree
Hide file tree
Showing 21 changed files with 436 additions and 360 deletions.
12 changes: 7 additions & 5 deletions bellows/ezsp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,11 +193,11 @@ def close(self):
def _get_command_priority(self, name: str) -> int:
return {
# Deprioritize any commands that send packets
"setSourceRoute": -1,
"set_source_route": -1,
"setExtendedTimeout": -1,
"sendUnicast": -1,
"sendMulticast": -1,
"sendBroadcast": -1,
"send_unicast": -1,
"send_multicast": -1,
"send_broadcast": -1,
# Prioritize watchdog commands
"nop": 999,
"readCounters": 999,
Expand All @@ -206,6 +206,8 @@ def _get_command_priority(self, name: str) -> int:
}.get(name, 0)

async def _command(self, name: str, *args: Any, **kwargs: Any) -> Any:
command = getattr(self._protocol, name)

if not self.is_ezsp_running:
LOGGER.debug(
"Couldn't send command %s(%s, %s). EZSP is not running",
Expand All @@ -216,7 +218,7 @@ async def _command(self, name: str, *args: Any, **kwargs: Any) -> Any:
raise EzspError("EZSP is not running")

async with self._send_sem(priority=self._get_command_priority(name)):
return await self._protocol.command(name, *args, **kwargs)
return await command(*args, **kwargs)

async def _list_command(
self, name, item_frames, completion_frame, spos, *args, **kwargs
Expand Down
3 changes: 2 additions & 1 deletion bellows/ezsp/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,11 @@ def __getattr__(self, name: str) -> Callable:
async def pre_permit(self, time_s: int) -> None:
"""Schedule task before allowing new joins."""

@abc.abstractmethod
async def add_transient_link_key(
self, ieee: t.EUI64, key: t.KeyData
) -> t.sl_Status:
"""Add a transient link key."""
raise NotImplementedError

@abc.abstractmethod
async def read_child_data(
Expand Down
5 changes: 5 additions & 0 deletions bellows/ezsp/v4/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ def _ezsp_frame_rx(self, data: bytes) -> tuple[int, int, bytes]:
async def pre_permit(self, time_s: int) -> None:
pass

async def add_transient_link_key(
self, ieee: t.EUI64, key: t.KeyData
) -> t.sl_Status:
return t.sl_Status.OK

async def read_child_data(
self,
) -> AsyncGenerator[tuple[t.NWK, t.EUI64, t.EmberNodeType], None]:
Expand Down
8 changes: 4 additions & 4 deletions bellows/ezsp/v8/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ async def pre_permit(self, time_s: int) -> None:
"""Temporarily change TC policy while allowing new joins."""
await super().pre_permit(time_s)
await self.setPolicy(
valueId=t.EzspPolicyId.TRUST_CENTER_POLICY,
value=(
policyId=t.EzspPolicyId.TRUST_CENTER_POLICY,
decisionId=(
t.EzspDecisionBitmask.ALLOW_JOINS
| t.EzspDecisionBitmask.ALLOW_UNSECURED_REJOINS
),
)
await asyncio.sleep(time_s + 2)
await self.setPolicy(
valueId=t.EzspPolicyId.TRUST_CENTER_POLICY,
value=self.tc_policy,
policyId=t.EzspPolicyId.TRUST_CENTER_POLICY,
decisionId=self.tc_policy,
)
15 changes: 15 additions & 0 deletions tests/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from __future__ import annotations

from unittest.mock import AsyncMock

from bellows.ezsp.protocol import ProtocolHandler


def mock_ezsp_commands(ezsp: ProtocolHandler) -> ProtocolHandler:
for command_name, (_command_id, tx_schema, _rx_schema) in ezsp.COMMANDS.items():
# TODO: make this end-to-end instead of relying on this serialization hack
async def fake_sender(*args, _command_name=command_name, _ezsp=ezsp, **kwargs):
# Trigger an exception early
_ezsp._ezsp_frame(_command_name, *args, **kwargs)

setattr(ezsp, command_name, AsyncMock(wraps=fake_sender))
Loading

0 comments on commit 595a285

Please sign in to comment.