Skip to content

Commit dc44c44

Browse files
committed
Test high-level network formation to ensure that it actually runs
1 parent cf3690a commit dc44c44

File tree

2 files changed

+89
-11
lines changed

2 files changed

+89
-11
lines changed

tests/test_application.py

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def __init__(self, *args, **kwargs):
5959
def reply_once_to(self, request, responses):
6060
called_future = asyncio.get_running_loop().create_future()
6161

62-
async def callback():
62+
async def callback(request):
6363
if callback.called:
6464
return
6565

@@ -68,27 +68,35 @@ async def callback():
6868
for response in responses:
6969
await asyncio.sleep(0.1)
7070
LOGGER.debug("Replying to %s with %s", request, response)
71-
self.send(response)
71+
72+
try:
73+
self.send(response(request))
74+
except TypeError:
75+
self.send(response)
7276

7377
called_future.set_result(True)
7478

7579
callback.called = False
76-
self.callback_for_response(request, lambda _: asyncio.create_task(callback()))
80+
self.callback_for_response(request, lambda r: asyncio.create_task(callback(r)))
7781

7882
return called_future
7983

8084
def reply_to(self, request, responses):
81-
async def callback():
85+
async def callback(request):
8286
callback.call_count += 1
8387

8488
for response in responses:
8589
await asyncio.sleep(0.1)
8690
LOGGER.debug("Replying to %s with %s", request, response)
87-
self.send(response)
91+
92+
try:
93+
self.send(response(request))
94+
except TypeError:
95+
self.send(response)
8896

8997
callback.call_count = 0
9098

91-
self.callback_for_response(request, lambda _: asyncio.create_task(callback()))
99+
self.callback_for_response(request, lambda r: asyncio.create_task(callback(r)))
92100

93101
return callback
94102

@@ -844,3 +852,75 @@ async def test_force_remove(application, mocker):
844852
# Make sure the device is gone once we remove it
845853
with pytest.raises(KeyError):
846854
app.get_device(nwk=device.nwk)
855+
856+
857+
@pytest_mark_asyncio_timeout(seconds=3)
858+
async def test_auto_form_unnecessary(application, mocker):
859+
app, znp_server = application
860+
861+
# b"\x55" means that Z-Stack is already configured?
862+
read_zstack_configured = znp_server.reply_once_to(
863+
request=c.Sys.OSALNVRead.Req(Id=NwkNvIds.HAS_CONFIGURED_ZSTACK3, Offset=0),
864+
responses=[c.Sys.OSALNVRead.Rsp(Status=t.Status.Success, Value=b"\x55")],
865+
)
866+
867+
mocker.patch.object(app, "form_network")
868+
869+
await app.startup(auto_form=True)
870+
871+
await read_zstack_configured
872+
assert app.form_network.call_count == 0
873+
874+
875+
@pytest_mark_asyncio_timeout(seconds=3)
876+
async def test_auto_form_necessary(application, mocker):
877+
app, znp_server = application
878+
nvram = {}
879+
880+
mocker.patch.object(app, "update_network", new=CoroutineMock())
881+
mocker.patch.object(app, "_reset", new=CoroutineMock())
882+
883+
def nvram_writer(req):
884+
if req.Id in nvram:
885+
raise ValueError("Unexpected overwrite")
886+
887+
nvram[req.Id] = req.Value
888+
889+
return c.Sys.OSALNVWrite.Rsp(Status=t.Status.Success)
890+
891+
read_zstack_configured = znp_server.reply_once_to(
892+
request=c.Sys.OSALNVRead.Req(Id=NwkNvIds.HAS_CONFIGURED_ZSTACK3, Offset=0),
893+
responses=[c.Sys.OSALNVRead.Rsp(Status=t.Status.Success, Value=b"\x00")],
894+
)
895+
896+
znp_server.reply_to(
897+
request=c.Sys.OSALNVWrite.Req(Offset=0, partial=True), responses=[nvram_writer]
898+
)
899+
900+
znp_server.reply_to(
901+
request=c.AppConfig.BDBStartCommissioning.Req(
902+
Mode=c.app_config.BDBCommissioningMode.NwkFormation
903+
),
904+
responses=[
905+
c.AppConfig.BDBStartCommissioning.Rsp(Status=t.Status.Success),
906+
c.ZDO.StateChangeInd.Callback(State=t.DeviceState.StartedAsCoordinator),
907+
],
908+
)
909+
910+
znp_server.reply_to(
911+
request=c.AppConfig.BDBStartCommissioning.Req(
912+
Mode=c.app_config.BDBCommissioningMode.NwkSteering
913+
),
914+
responses=[c.AppConfig.BDBStartCommissioning.Rsp(Status=t.Status.Success)],
915+
)
916+
917+
await app.startup(auto_form=True)
918+
919+
await read_zstack_configured
920+
921+
assert app.update_network.call_count == 1
922+
assert app._reset.call_count == 2
923+
924+
assert nvram[NwkNvIds.STARTUP_OPTION] == t.StartupOptions.ClearState.serialize()
925+
assert nvram[NwkNvIds.LOGICAL_TYPE] == t.DeviceLogicalType.Coordinator.serialize()
926+
assert nvram[NwkNvIds.ZDO_DIRECT_CB] == t.Bool(True).serialize()

zigpy_znp/zigbee/application.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -403,13 +403,11 @@ async def form_network(self):
403403
)
404404
await self._reset()
405405

406-
pan_id = self.config[conf.SCHEMA_NETWORK][conf.CONF_NWK_PAN_ID]
407-
extended_pan_id = self.config[conf.SCHEMA_NETWORK][
408-
conf.CONF_NWK_EXTENDED_PAN_ID
409-
]
406+
pan_id = self.config[conf.CONF_NWK][conf.CONF_NWK_PAN_ID]
407+
extended_pan_id = self.config[conf.CONF_NWK][conf.CONF_NWK_EXTENDED_PAN_ID]
410408

411409
await self.update_network(
412-
channels=self.config[conf.SCHEMA_NETWORK][conf.CONF_NWK_CHANNELS],
410+
channels=self.config[conf.CONF_NWK][conf.CONF_NWK_CHANNELS],
413411
pan_id=0xFFFF if pan_id is None else pan_id,
414412
extended_pan_id=ExtendedPanId(os.urandom(8))
415413
if extended_pan_id is None

0 commit comments

Comments
 (0)