|
14 | 14 | from roborock.devices.traits.v1.maps import MapsTrait |
15 | 15 | from roborock.devices.traits.v1.rooms import RoomsTrait |
16 | 16 | from roborock.devices.traits.v1.status import StatusTrait |
17 | | -from roborock.exceptions import RoborockDeviceBusy |
| 17 | +from roborock.exceptions import RoborockDeviceBusy, RoborockException |
18 | 18 | from roborock.map.map_parser import ParsedMapData |
19 | 19 | from roborock.roborock_typing import RoborockCommand |
20 | 20 | from tests import mock_data |
|
42 | 42 | ], |
43 | 43 | } |
44 | 44 | ] |
| 45 | +MULTI_MAP_LIST_SINGLE_MAP_DATA = [ |
| 46 | + { |
| 47 | + "max_multi_map": 1, |
| 48 | + "max_bak_map": 0, |
| 49 | + "multi_map_count": 1, |
| 50 | + "map_info": [ |
| 51 | + { |
| 52 | + "mapFlag": 0, |
| 53 | + "add_time": 1747132930, |
| 54 | + "length": 0, |
| 55 | + "name": "Only Floor", |
| 56 | + "bak_maps": [], |
| 57 | + }, |
| 58 | + ], |
| 59 | + } |
| 60 | +] |
45 | 61 |
|
46 | 62 | ROOM_MAPPING_DATA_MAP_0 = [[16, "2362048"], [17, "2362044"]] |
47 | 63 | ROOM_MAPPING_DATA_MAP_123 = [[18, "2362041"], [19, "2362042"]] |
@@ -241,6 +257,57 @@ async def test_discover_home_with_existing_cache( |
241 | 257 | assert map_0_content.map_data is not None |
242 | 258 |
|
243 | 259 |
|
| 260 | +async def test_existing_home_cache_invalid_bytes( |
| 261 | + home_trait: HomeTrait, |
| 262 | + mock_rpc_channel: AsyncMock, |
| 263 | + mock_mqtt_rpc_channel: AsyncMock, |
| 264 | + mock_map_rpc_channel: AsyncMock, |
| 265 | +) -> None: |
| 266 | + """Test that discovery is skipped when cache already exists.""" |
| 267 | + # Pre-populate the cache. |
| 268 | + cache_data = await home_trait._cache.get() |
| 269 | + cache_data.home_map_info = {0: CombinedMapInfo(map_flag=0, name="Dummy", rooms=[])} |
| 270 | + # We override the map bytes parser to raise an exception above. |
| 271 | + cache_data.home_map_content = {0: MAP_BYTES_RESPONSE_1} |
| 272 | + await home_trait._cache.set(cache_data) |
| 273 | + |
| 274 | + # Setup mocks for the discovery process |
| 275 | + mock_rpc_channel.send_command.side_effect = [ |
| 276 | + ROOM_MAPPING_DATA_MAP_0, # Rooms for the single map |
| 277 | + ] |
| 278 | + mock_mqtt_rpc_channel.send_command.side_effect = [ |
| 279 | + MULTI_MAP_LIST_SINGLE_MAP_DATA, # Single map list |
| 280 | + ] |
| 281 | + mock_map_rpc_channel.send_command.side_effect = [ |
| 282 | + MAP_BYTES_RESPONSE_1, # Map bytes for the single map |
| 283 | + ] |
| 284 | + |
| 285 | + # Call discover_home. First attempt raises an exception then loading from the server |
| 286 | + # produes a valid result. |
| 287 | + with patch( |
| 288 | + "roborock.devices.traits.v1.map_content.MapParser.parse", |
| 289 | + side_effect=[ |
| 290 | + RoborockException("Invalid map bytes"), |
| 291 | + ParsedMapData( |
| 292 | + image_content=TEST_IMAGE_CONTENT_2, |
| 293 | + map_data=MagicMock(), |
| 294 | + ), |
| 295 | + ], |
| 296 | + ): |
| 297 | + await home_trait.discover_home() |
| 298 | + |
| 299 | + # Verify cache was loaded from storage. The map was re-fetched from storage. |
| 300 | + assert home_trait.home_map_info |
| 301 | + assert home_trait.home_map_info.keys() == {0} |
| 302 | + assert home_trait.home_map_info[0].name == "Only Floor" |
| 303 | + assert home_trait.home_map_content |
| 304 | + assert home_trait.home_map_content.keys() == {0} |
| 305 | + map_0_content = home_trait.home_map_content[0] |
| 306 | + assert map_0_content is not None |
| 307 | + assert map_0_content.image_content == TEST_IMAGE_CONTENT_2 |
| 308 | + assert map_0_content.map_data is not None |
| 309 | + |
| 310 | + |
244 | 311 | async def test_discover_home_no_maps( |
245 | 312 | home_trait: HomeTrait, |
246 | 313 | mock_rpc_channel: AsyncMock, |
@@ -311,10 +378,6 @@ async def test_refresh_no_cache_no_update( |
311 | 378 | mock_mqtt_rpc_channel: AsyncMock, |
312 | 379 | ) -> None: |
313 | 380 | """Test that refresh doesn't update when no cache exists.""" |
314 | | - # Setup mocks for refresh |
315 | | - # mock_mqtt_rpc_channel.send_command.side_effect = [ |
316 | | - # MULTI_MAP_LIST_DATA, # Maps refresh |
317 | | - # ] |
318 | 381 | # Perform refresh without existing cache |
319 | 382 | with pytest.raises(Exception, match="Cannot refresh home data without home cache, did you call discover_home()?"): |
320 | 383 | await home_trait.refresh() |
@@ -383,34 +446,16 @@ async def test_single_map_no_switching( |
383 | 446 | mock_map_rpc_channel: AsyncMock, |
384 | 447 | ) -> None: |
385 | 448 | """Test that single map discovery doesn't trigger map switching.""" |
386 | | - single_map_data = [ |
387 | | - { |
388 | | - "max_multi_map": 1, |
389 | | - "max_bak_map": 0, |
390 | | - "multi_map_count": 1, |
391 | | - "map_info": [ |
392 | | - { |
393 | | - "mapFlag": 0, |
394 | | - "add_time": 1747132930, |
395 | | - "length": 0, |
396 | | - "name": "Only Floor", |
397 | | - "bak_maps": [], |
398 | | - }, |
399 | | - ], |
400 | | - } |
401 | | - ] |
402 | | - |
403 | 449 | mock_rpc_channel.send_command.side_effect = [ |
404 | 450 | ROOM_MAPPING_DATA_MAP_0, # Rooms for the single map |
405 | 451 | ] |
406 | 452 | mock_mqtt_rpc_channel.send_command.side_effect = [ |
407 | | - single_map_data, # Single map list |
| 453 | + MULTI_MAP_LIST_SINGLE_MAP_DATA, # Single map list |
408 | 454 | ] |
409 | 455 | mock_map_rpc_channel.send_command.side_effect = [ |
410 | 456 | MAP_BYTES_RESPONSE_1, # Map bytes for the single map |
411 | 457 | ] |
412 | 458 |
|
413 | | - |
414 | 459 | await home_trait.discover_home() |
415 | 460 |
|
416 | 461 | # Verify cache is populated |
|
0 commit comments