|
4 | 4 | import pytest |
5 | 5 |
|
6 | 6 | from zigpy_deconz import api as deconz_api, types as t, uart |
| 7 | +import zigpy_deconz.exception |
7 | 8 |
|
8 | 9 |
|
9 | 10 | COMMANDS = [*deconz_api.TX_COMMANDS.items(), *deconz_api.RX_COMMANDS.items()] |
@@ -109,6 +110,47 @@ def test_data_received(api, monkeypatch): |
109 | 110 | my_handler.reset_mock() |
110 | 111 |
|
111 | 112 |
|
| 113 | +def test_data_received_unk_status(api, monkeypatch): |
| 114 | + monkeypatch.setattr(t, 'deserialize', mock.MagicMock( |
| 115 | + return_value=(mock.sentinel.deserialize_data, b''))) |
| 116 | + my_handler = mock.MagicMock() |
| 117 | + |
| 118 | + for cmd, cmd_opts in deconz_api.RX_COMMANDS.items(): |
| 119 | + cmd_id, unsolicited = cmd_opts[0], cmd_opts[2] |
| 120 | + payload = b'\x01\x02\x03\x04' |
| 121 | + status = t.uint8_t(0xfe).serialize() |
| 122 | + data = cmd_id.to_bytes(1, 'big') + b'\x00' + \ |
| 123 | + status + b'\x00\x00' + payload |
| 124 | + setattr(api, '_handle_{}'.format(cmd), my_handler) |
| 125 | + api._awaiting[0] = (mock.MagicMock(), ) |
| 126 | + api.data_received(data) |
| 127 | + assert t.deserialize.call_count == 1 |
| 128 | + assert t.deserialize.call_args[0][0] == payload |
| 129 | + if unsolicited: |
| 130 | + assert my_handler.call_count == 0 |
| 131 | + else: |
| 132 | + assert my_handler.call_count == 1 |
| 133 | + t.deserialize.reset_mock() |
| 134 | + my_handler.reset_mock() |
| 135 | + |
| 136 | + |
| 137 | +def test_data_received_unk_cmd(api, monkeypatch): |
| 138 | + monkeypatch.setattr(t, 'deserialize', mock.MagicMock( |
| 139 | + return_value=(mock.sentinel.deserialize_data, b''))) |
| 140 | + |
| 141 | + for cmd_id in range(0, 255): |
| 142 | + if cmd_id in api._commands_by_id: |
| 143 | + continue |
| 144 | + payload = b'\x01\x02\x03\x04' |
| 145 | + status = t.uint8_t(0x00).serialize() |
| 146 | + data = cmd_id.to_bytes(1, 'big') + b'\x00' + \ |
| 147 | + status + b'\x00\x00' + payload |
| 148 | + api._awaiting[0] = (mock.MagicMock(), ) |
| 149 | + api.data_received(data) |
| 150 | + assert t.deserialize.call_count == 0 |
| 151 | + t.deserialize.reset_mock() |
| 152 | + |
| 153 | + |
112 | 154 | def test_simplified_beacon(api): |
113 | 155 | api._handle_simplified_beacon( |
114 | 156 | (0x0007, 0x1234, 0x5678, 0x19, 0x00, 0x01) |
@@ -166,3 +208,71 @@ def mock_cmd(*args, **kwargs): |
166 | 208 | res = await api._aps_data_indication() |
167 | 209 | assert res is None |
168 | 210 | assert api._data_indication is False |
| 211 | + |
| 212 | + |
| 213 | +@pytest.mark.asyncio |
| 214 | +async def test_aps_data_request(api): |
| 215 | + params = [ |
| 216 | + 0x00, # req id |
| 217 | + t.DeconzAddressEndpoint.deserialize( |
| 218 | + b'\x02\xaa\x55\x01')[0], # dst + ep |
| 219 | + 0x0104, # profile id |
| 220 | + 0x0007, # cluster id |
| 221 | + 0x01, # src ep |
| 222 | + b'aps payload' |
| 223 | + ] |
| 224 | + |
| 225 | + mock_cmd = mock.MagicMock( |
| 226 | + side_effect=asyncio.coroutine(mock.MagicMock())) |
| 227 | + api._command = mock_cmd |
| 228 | + |
| 229 | + await api.aps_data_request(*params) |
| 230 | + assert mock_cmd.call_count == 1 |
| 231 | + |
| 232 | + |
| 233 | +@pytest.mark.asyncio |
| 234 | +async def test_aps_data_request_timeout(api, monkeypatch): |
| 235 | + params = [ |
| 236 | + 0x00, # req id |
| 237 | + t.DeconzAddressEndpoint.deserialize( |
| 238 | + b'\x02\xaa\x55\x01')[0], # dst + ep |
| 239 | + 0x0104, # profile id |
| 240 | + 0x0007, # cluster id |
| 241 | + 0x01, # src ep |
| 242 | + b'aps payload' |
| 243 | + ] |
| 244 | + |
| 245 | + mock_cmd = mock.MagicMock(return_value=asyncio.Future()) |
| 246 | + api._command = mock_cmd |
| 247 | + monkeypatch.setattr(deconz_api, 'COMMAND_TIMEOUT', .1) |
| 248 | + |
| 249 | + with pytest.raises(asyncio.TimeoutError): |
| 250 | + await api.aps_data_request(*params) |
| 251 | + assert mock_cmd.call_count == 1 |
| 252 | + |
| 253 | + |
| 254 | +@pytest.mark.asyncio |
| 255 | +async def test_aps_data_request_busy(api, monkeypatch): |
| 256 | + params = [ |
| 257 | + 0x00, # req id |
| 258 | + t.DeconzAddressEndpoint.deserialize( |
| 259 | + b'\x02\xaa\x55\x01')[0], # dst + ep |
| 260 | + 0x0104, # profile id |
| 261 | + 0x0007, # cluster id |
| 262 | + 0x01, # src ep |
| 263 | + b'aps payload' |
| 264 | + ] |
| 265 | + |
| 266 | + res = asyncio.Future() |
| 267 | + exc = zigpy_deconz.exception.CommandError(deconz_api.STATUS.BUSY, 'busy') |
| 268 | + res.set_exception(exc) |
| 269 | + mock_cmd = mock.MagicMock(return_value=res) |
| 270 | + |
| 271 | + api._command = mock_cmd |
| 272 | + monkeypatch.setattr(deconz_api, 'COMMAND_TIMEOUT', .1) |
| 273 | + sleep = mock.MagicMock(side_effect=asyncio.coroutine(mock.MagicMock())) |
| 274 | + monkeypatch.setattr(asyncio, 'sleep', sleep) |
| 275 | + |
| 276 | + with pytest.raises(zigpy_deconz.exception.CommandError): |
| 277 | + await api.aps_data_request(*params) |
| 278 | + assert mock_cmd.call_count == 4 |
0 commit comments