11"""Test `load_network_info` and `write_network_info` methods."""
22
33import importlib .metadata
4+ from unittest .mock import ANY , call
45
56import pytest
6- from zigpy .exceptions import ControllerException , NetworkNotFormed
7+ from zigpy .exceptions import CannotWriteNetworkSettings , NetworkNotFormed
78import zigpy .state as app_state
89import zigpy .types as t
910import zigpy .zdo .types as zdo_t
@@ -70,37 +71,74 @@ def network_info(node_info):
7071@patch .object (application , "CHANGE_NETWORK_POLL_TIME" , 0.001 )
7172@patch .object (application , "CHANGE_NETWORK_STATE_DELAY" , 0.001 )
7273@pytest .mark .parametrize (
73- "channel_mask, channel, security_level, fw_supports_fc, logical_type" ,
74+ (
75+ "channel_mask" ,
76+ "channel" ,
77+ "security_level" ,
78+ "fw_supports_fc" ,
79+ "logical_type" ,
80+ "tx_counter" ,
81+ "should_error" ,
82+ ),
7483 [
84+ # FW supports frame counter
7585 (
7686 t .Channels .from_channel_list ([15 ]),
7787 15 ,
7888 0 ,
7989 True ,
8090 zdo_t .LogicalType .Coordinator ,
91+ 39009277 ,
92+ False ,
93+ ),
94+ # FW doesn't support but we're writing blank settings (tx_counter == 0)
95+ (
96+ t .Channels .from_channel_list ([15 ]),
97+ 15 ,
98+ 5 ,
99+ False ,
100+ zdo_t .LogicalType .Coordinator ,
101+ 0 ,
102+ False ,
81103 ),
104+ # FW doesn't support and we're writing real settings (should error)
82105 (
83106 t .Channels .from_channel_list ([15 ]),
84107 15 ,
85108 0 ,
86109 False ,
87110 zdo_t .LogicalType .Coordinator ,
111+ 39009277 ,
112+ True ,
88113 ),
114+ # Additional test cases with FW support
89115 (
90116 t .Channels .from_channel_list ([15 , 20 ]),
91117 15 ,
92118 5 ,
93119 True ,
94120 zdo_t .LogicalType .Coordinator ,
121+ 39009277 ,
122+ False ,
95123 ),
96124 (
97125 t .Channels .from_channel_list ([15 , 20 , 25 ]),
98126 None ,
99127 5 ,
100128 True ,
101129 zdo_t .LogicalType .Router ,
130+ 39009277 ,
131+ False ,
132+ ),
133+ (
134+ None ,
135+ 15 ,
136+ 5 ,
137+ True ,
138+ zdo_t .LogicalType .Coordinator ,
139+ 39009277 ,
140+ False ,
102141 ),
103- (None , 15 , 5 , True , zdo_t .LogicalType .Coordinator ),
104142 ],
105143)
106144async def test_write_network_info (
@@ -112,6 +150,8 @@ async def test_write_network_info(
112150 security_level ,
113151 fw_supports_fc ,
114152 logical_type ,
153+ tx_counter ,
154+ should_error ,
115155):
116156 """Test that network info is correctly written."""
117157
@@ -137,13 +177,14 @@ async def write_parameter(param, *args):
137177 channel = channel ,
138178 channel_mask = channel_mask ,
139179 security_level = security_level ,
180+ network_key = network_info .network_key .replace (tx_counter = tx_counter ),
140181 )
141182
142183 node_info = node_info .replace (logical_type = logical_type )
143184
144- if not fw_supports_fc :
185+ if should_error :
145186 with pytest .raises (
146- ControllerException ,
187+ CannotWriteNetworkSettings ,
147188 match = (
148189 "Please upgrade your adapter firmware. Firmware version 0x26580700 does"
149190 " not support writing the network key frame counter, which is required"
@@ -166,7 +207,9 @@ async def write_parameter(param, *args):
166207 for call in app ._api .write_parameter .await_args_list
167208 }
168209
169- assert params ["nwk_frame_counter" ] == (network_info .network_key .tx_counter ,)
210+ # Only check frame counter if firmware supports it
211+ if fw_supports_fc :
212+ assert params ["nwk_frame_counter" ] == (network_info .network_key .tx_counter ,)
170213
171214 if node_info .logical_type == zdo_t .LogicalType .Coordinator :
172215 assert params ["aps_designed_coordinator" ] == (1 ,)
@@ -328,3 +371,57 @@ async def read_param(param, *args):
328371 assert app .state .network_info == network_info
329372
330373 assert app .state .node_info == node_info .replace (** node_state_changes )
374+
375+
376+ @patch .object (application , "CHANGE_NETWORK_POLL_TIME" , 0.001 )
377+ @patch .object (application , "CHANGE_NETWORK_STATE_DELAY" , 0.001 )
378+ async def test_form_network_fast_without_frame_counter_support (app ): # noqa: F811
379+ """Test that form_network(fast=True) works when FW doesn't support frame counter."""
380+
381+ async def write_parameter (param , * args ):
382+ if param == zigpy_deconz .api .NetworkParameter .nwk_frame_counter :
383+ raise zigpy_deconz .exception .CommandError (
384+ "Command is unsupported" ,
385+ status = zigpy_deconz .api .Status .UNSUPPORTED ,
386+ command = None ,
387+ )
388+
389+ app ._change_network_state = AsyncMock ()
390+ app ._api .write_parameter = AsyncMock (side_effect = write_parameter )
391+ app .backups = AsyncMock ()
392+ app .backups .restore_backup = AsyncMock ()
393+
394+ # This should not raise an error because fast=True sets form_quickly
395+ await app .form_network (fast = True )
396+
397+ # Verify that restore_backup was called with create_new=False (due to fast=True)
398+ assert app .backups .restore_backup .mock_calls == [
399+ call (backup = ANY , counter_increment = 0 , allow_incomplete = True , create_new = False )
400+ ]
401+
402+
403+ @patch .object (application , "CHANGE_NETWORK_POLL_TIME" , 0.001 )
404+ @patch .object (application , "CHANGE_NETWORK_STATE_DELAY" , 0.001 )
405+ async def test_reset_network_info_without_frame_counter_support (app ): # noqa: F811
406+ """Test that reset_network_info works even when FW doesn't support frame counter."""
407+
408+ async def write_parameter (param , * args ):
409+ if param == zigpy_deconz .api .NetworkParameter .nwk_frame_counter :
410+ raise zigpy_deconz .exception .CommandError (
411+ "Command is unsupported" ,
412+ status = zigpy_deconz .api .Status .UNSUPPORTED ,
413+ command = None ,
414+ )
415+
416+ app ._change_network_state = AsyncMock ()
417+ app ._api .write_parameter = AsyncMock (side_effect = write_parameter )
418+ app .backups = AsyncMock ()
419+ app .backups .restore_backup = AsyncMock ()
420+
421+ # Should not raise an error because reset_network_info calls form_network(fast=True)
422+ await app .reset_network_info ()
423+
424+ # Verify that restore_backup was called once (via form_network)
425+ assert app .backups .restore_backup .mock_calls == [
426+ call (backup = ANY , counter_increment = 0 , allow_incomplete = True , create_new = False )
427+ ]
0 commit comments