1010import zigpy_znp .types as t
1111import zigpy_znp .config as conf
1212import zigpy_znp .commands as c
13- from zigpy_znp .exceptions import InvalidCommandResponse
1413
1514from ..conftest import (
1615 FORMED_DEVICES ,
@@ -145,10 +144,10 @@ async def test_zigpy_request_failure(device, make_application, mocker):
145144 mocker .spy (app , "send_packet" )
146145
147146 # Fail to turn on the light
148- with pytest .raises (InvalidCommandResponse ):
147+ with pytest .raises (DeliveryError ):
149148 await device .endpoints [1 ].on_off .on ()
150149
151- assert app .send_packet .call_count = = 1
150+ assert app .send_packet .call_count > = 1
152151 await app .shutdown ()
153152
154153
@@ -425,7 +424,7 @@ async def inner():
425424
426425 asyncio .create_task (inner ())
427426
428- data_req = znp_server .reply_once_to (
427+ znp_server .reply_to (
429428 c .AF .DataRequestExt .Req (partial = True ),
430429 responses = [
431430 c .AF .DataRequestExt .Rsp (Status = t .Status .SUCCESS ),
@@ -444,7 +443,6 @@ async def inner():
444443 data = b"\x00 " ,
445444 )
446445
447- await data_req
448446 await delayed_reply_sent
449447
450448 assert app ._znp ._unhandled_command .call_count == 0
@@ -532,9 +530,6 @@ def set_route_discovered(req):
532530 await was_route_discovered
533531 await zdo_req
534532
535- # 6 accounts for the loopback requests
536- assert sum (c .value for c in app .state .counters ["Retry_NONE" ].values ()) == 6 + 1
537-
538533 await app .shutdown ()
539534
540535
@@ -583,15 +578,6 @@ def set_route_discovered(req):
583578 ],
584579 )
585580
586- # Ignore the source routing request as well
587- znp_server .reply_to (
588- c .AF .DataRequestSrcRtg .Req (partial = True ),
589- responses = [
590- c .AF .DataRequestSrcRtg .Rsp (Status = t .Status .SUCCESS ),
591- data_confirm_replier ,
592- ],
593- )
594-
595581 await app .request (
596582 device = device ,
597583 profile = 260 ,
@@ -603,75 +589,6 @@ def set_route_discovered(req):
603589 )
604590
605591 await was_route_discovered
606- assert (
607- sum (c .value for c in app .state .counters ["Retry_RouteDiscovery" ].values ()) == 1
608- )
609-
610- await app .shutdown ()
611-
612-
613- @pytest .mark .parametrize ("device" , [FormedLaunchpadCC26X2R1 ])
614- async def test_request_recovery_use_ieee_addr (device , make_application , mocker ):
615- app , znp_server = make_application (server_cls = device )
616-
617- await app .startup (auto_form = False )
618-
619- # The data confirm timeout must be shorter than the ARSP timeout
620- mocker .patch ("zigpy_znp.zigbee.application.DATA_CONFIRM_TIMEOUT" , new = 0.1 )
621- app ._znp ._config [conf .CONF_ZNP_CONFIG ][conf .CONF_ARSP_TIMEOUT ] = 1
622-
623- device = app .add_initialized_device (ieee = t .EUI64 (range (8 )), nwk = 0xABCD )
624-
625- was_ieee_addr_used = False
626-
627- def data_confirm_replier (req ):
628- nonlocal was_ieee_addr_used
629-
630- if req .DstAddrModeAddress .mode == t .AddrMode .IEEE :
631- status = t .Status .SUCCESS
632- was_ieee_addr_used = True
633- else :
634- status = t .Status .MAC_NO_ACK
635-
636- return c .AF .DataConfirm .Callback (Status = status , Endpoint = 1 , TSN = 1 )
637-
638- znp_server .reply_once_to (
639- c .ZDO .ExtRouteDisc .Req (
640- Dst = device .nwk , Options = c .zdo .RouteDiscoveryOptions .UNICAST , partial = True
641- ),
642- responses = [c .ZDO .ExtRouteDisc .Rsp (Status = t .Status .SUCCESS )],
643- )
644-
645- znp_server .reply_to (
646- c .AF .DataRequestExt .Req (partial = True ),
647- responses = [
648- c .AF .DataRequestExt .Rsp (Status = t .Status .SUCCESS ),
649- data_confirm_replier ,
650- ],
651- )
652-
653- # Ignore the source routing request as well
654- znp_server .reply_to (
655- c .AF .DataRequestSrcRtg .Req (partial = True ),
656- responses = [
657- c .AF .DataRequestSrcRtg .Rsp (Status = t .Status .SUCCESS ),
658- c .AF .DataConfirm .Callback (Status = t .Status .MAC_NO_ACK , Endpoint = 1 , TSN = 1 ),
659- ],
660- )
661-
662- await app .request (
663- device = device ,
664- profile = 260 ,
665- cluster = 1 ,
666- src_ep = 1 ,
667- dst_ep = 1 ,
668- sequence = 1 ,
669- data = b"\x00 " ,
670- )
671-
672- assert was_ieee_addr_used
673- assert sum (c .value for c in app .state .counters ["Retry_IEEEAddress" ].values ()) == 1
674-
675592 await app .shutdown ()
676593
677594
@@ -686,7 +603,6 @@ async def test_request_recovery_assoc_remove(
686603 await app .startup (auto_form = False )
687604
688605 mocker .patch ("zigpy_znp.zigbee.application.DATA_CONFIRM_TIMEOUT" , new = 0.1 )
689- mocker .patch ("zigpy_znp.zigbee.application.REQUEST_ERROR_RETRY_DELAY" , new = 0 )
690606
691607 app ._znp ._config [conf .CONF_ZNP_CONFIG ][conf .CONF_ARSP_TIMEOUT ] = 1
692608
@@ -713,14 +629,6 @@ def data_confirm_replier(req):
713629 ],
714630 )
715631
716- znp_server .reply_to (
717- c .AF .DataRequestSrcRtg .Req (partial = True ),
718- responses = [
719- c .AF .DataRequestSrcRtg .Rsp (Status = t .Status .SUCCESS ),
720- data_confirm_replier ,
721- ],
722- )
723-
724632 def assoc_get_with_addr (req ):
725633 nonlocal assoc_device
726634
@@ -730,7 +638,7 @@ def assoc_get_with_addr(req):
730638
731639 return c .UTIL .AssocGetWithAddress .Rsp (Device = assoc_device )
732640
733- did_assoc_get = znp_server .reply_once_to (
641+ did_assoc_get = znp_server .reply_to (
734642 c .UTIL .AssocGetWithAddress .Req (IEEE = device .ieee , partial = True ),
735643 responses = [assoc_get_with_addr ],
736644 )
@@ -750,12 +658,12 @@ def assoc_remove(req):
750658 assoc_device = None
751659 return c .UTIL .AssocRemove .Rsp (Status = t .Status .SUCCESS )
752660
753- did_assoc_remove = znp_server .reply_once_to (
661+ did_assoc_remove = znp_server .reply_to (
754662 c .UTIL .AssocRemove .Req (IEEE = device .ieee ),
755663 responses = [assoc_remove ],
756664 )
757665
758- did_assoc_add = znp_server .reply_once_to (
666+ did_assoc_add = znp_server .reply_to (
759667 c .UTIL .AssocAdd .Req (
760668 NWK = device .nwk ,
761669 IEEE = device .ieee ,
@@ -791,102 +699,23 @@ def assoc_remove(req):
791699 await req
792700
793701 if fw_assoc_remove :
794- await did_assoc_remove
702+ assert len ( did_assoc_remove . mock_calls ) >= 1
795703
796704 if final_status != t .Status .SUCCESS :
797705 # The association is re-added on failure
798- await did_assoc_add
706+ assert len ( did_assoc_add . mock_calls ) >= 1
799707 else :
800- assert not did_assoc_add .done ()
708+ assert len ( did_assoc_add .mock_calls ) == 0
801709 elif issubclass (device_cls , FormedLaunchpadCC26X2R1 ):
802- await did_assoc_get
803- assert was_route_discovered .call_count >= 1
710+ assert len (did_assoc_get .mock_calls ) >= 1
804711 else :
805712 # Don't even attempt this with older firmwares
806- assert not did_assoc_get .done ()
713+ assert len ( did_assoc_get .mock_calls ) == 0
807714 assert was_route_discovered .call_count == 0
808715
809716 await app .shutdown ()
810717
811718
812- @pytest .mark .parametrize ("device" , [FormedLaunchpadCC26X2R1 ])
813- @pytest .mark .parametrize ("succeed" , [True , False ])
814- @pytest .mark .parametrize ("relays" , [[0x1111 , 0x2222 , 0x3333 ], []])
815- async def test_request_recovery_manual_source_route (
816- device , succeed , relays , make_application , mocker
817- ):
818- app , znp_server = make_application (server_cls = device )
819-
820- await app .startup (auto_form = False )
821-
822- mocker .patch ("zigpy_znp.zigbee.application.DATA_CONFIRM_TIMEOUT" , new = 0.1 )
823- mocker .patch ("zigpy_znp.zigbee.application.REQUEST_ERROR_RETRY_DELAY" , new = 0 )
824-
825- app ._znp ._config [conf .CONF_ZNP_CONFIG ][conf .CONF_ARSP_TIMEOUT ] = 1
826-
827- device = app .add_initialized_device (ieee = t .EUI64 (range (8 )), nwk = 0xABCD )
828- device .relays = relays
829-
830- def data_confirm_replier (req ):
831- if isinstance (req , c .AF .DataRequestExt .Req ) or not succeed :
832- return c .AF .DataConfirm .Callback (
833- Status = t .Status .MAC_NO_ACK ,
834- Endpoint = 1 ,
835- TSN = 1 ,
836- )
837- else :
838- return c .AF .DataConfirm .Callback (
839- Status = t .Status .SUCCESS ,
840- Endpoint = 1 ,
841- TSN = 1 ,
842- )
843-
844- normal_data_request = znp_server .reply_to (
845- c .AF .DataRequestExt .Req (partial = True ),
846- responses = [
847- c .AF .DataRequestExt .Rsp (Status = t .Status .SUCCESS ),
848- data_confirm_replier ,
849- ],
850- )
851-
852- source_routing_data_request = znp_server .reply_to (
853- c .AF .DataRequestSrcRtg .Req (partial = True ),
854- responses = [
855- c .AF .DataRequestSrcRtg .Rsp (Status = t .Status .SUCCESS ),
856- data_confirm_replier ,
857- ],
858- )
859-
860- znp_server .reply_to (
861- c .ZDO .ExtRouteDisc .Req (
862- Dst = device .nwk , Options = c .zdo .RouteDiscoveryOptions .UNICAST , partial = True
863- ),
864- responses = [c .ZDO .ExtRouteDisc .Rsp (Status = t .Status .SUCCESS )],
865- )
866-
867- req = app .request (
868- device = device ,
869- profile = 260 ,
870- cluster = 1 ,
871- src_ep = 1 ,
872- dst_ep = 1 ,
873- sequence = 1 ,
874- data = b"\x00 " ,
875- )
876-
877- if succeed :
878- await req
879- else :
880- with pytest .raises (DeliveryError ):
881- await req
882-
883- # In either case only one source routing attempt is performed
884- assert source_routing_data_request .call_count == 1
885- assert normal_data_request .call_count >= 1
886-
887- await app .shutdown ()
888-
889-
890719@pytest .mark .parametrize ("device" , [FormedLaunchpadCC26X2R1 ])
891720async def test_route_discovery_concurrency (device , make_application ):
892721 app , znp_server = make_application (server_cls = device )
0 commit comments