Skip to content

Commit

Permalink
fix rooms without enabled map
Browse files Browse the repository at this point in the history
  • Loading branch information
edenhaus committed Sep 24, 2023
1 parent ed13248 commit 5534bc4
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 36 deletions.
72 changes: 39 additions & 33 deletions deebot_client/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,42 @@ def __init__(
self._amount_rooms: int = 0
self._last_image: LastImage | None = None
self._unsubscribers: list[Callable[[], None]] = []
self._unsubscribers_internal: list[Callable[[], None]] = []
self._tasks: set[asyncio.Future[Any]] = set()

async def on_map_set(event: MapSetEvent) -> None:
if event.type == MapSetType.ROOMS:
self._amount_rooms = len(event.subsets)

Check warning on line 155 in deebot_client/map.py

View check run for this annotation

Codecov / codecov/patch

deebot_client/map.py#L155

Added line #L155 was not covered by tests
for room_id, _ in self._map_data.rooms.copy().items():
if room_id not in event.subsets:
self._map_data.rooms.pop(room_id, None)

Check warning on line 158 in deebot_client/map.py

View check run for this annotation

Codecov / codecov/patch

deebot_client/map.py#L158

Added line #L158 was not covered by tests
else:
for subset_id, subset in self._map_data.map_subsets.copy().items():
if subset.type == event.type and subset_id not in event.subsets:
self._map_data.map_subsets.pop(subset_id, None)

Check warning on line 162 in deebot_client/map.py

View check run for this annotation

Codecov / codecov/patch

deebot_client/map.py#L162

Added line #L162 was not covered by tests

self._unsubscribers_internal.append(
self._event_bus.subscribe(MapSetEvent, on_map_set)
)

async def on_map_subset(event: MapSubsetEvent) -> None:
if event.type == MapSetType.ROOMS and event.name:
room = Room(event.name, event.id, event.coordinates)

Check warning on line 170 in deebot_client/map.py

View check run for this annotation

Codecov / codecov/patch

deebot_client/map.py#L170

Added line #L170 was not covered by tests
if self._map_data.rooms.get(event.id, None) != room:
self._map_data.rooms[room.id] = room

Check warning on line 172 in deebot_client/map.py

View check run for this annotation

Codecov / codecov/patch

deebot_client/map.py#L172

Added line #L172 was not covered by tests

if len(self._map_data.rooms) == self._amount_rooms:
self._event_bus.notify(

Check warning on line 175 in deebot_client/map.py

View check run for this annotation

Codecov / codecov/patch

deebot_client/map.py#L175

Added line #L175 was not covered by tests
RoomsEvent(list(self._map_data.rooms.values()))
)

elif self._map_data.map_subsets.get(event.id, None) != event:
self._map_data.map_subsets[event.id] = event

Check warning on line 180 in deebot_client/map.py

View check run for this annotation

Codecov / codecov/patch

deebot_client/map.py#L180

Added line #L180 was not covered by tests

self._unsubscribers_internal.append(
self._event_bus.subscribe(MapSubsetEvent, on_map_subset)
)

# ---------------------------- METHODS ----------------------------

def _update_trace_points(self, data: str) -> None:
Expand Down Expand Up @@ -206,37 +240,6 @@ def enable(self) -> None:

create_task(self._tasks, self._execute_command(GetCachedMapInfo()))

async def on_map_set(event: MapSetEvent) -> None:
if event.type == MapSetType.ROOMS:
self._amount_rooms = len(event.subsets)
for room_id, _ in self._map_data.rooms.copy().items():
if room_id not in event.subsets:
self._map_data.rooms.pop(room_id, None)
else:
for subset_id, subset in self._map_data.map_subsets.copy().items():
if subset.type == event.type and subset_id not in event.subsets:
self._map_data.map_subsets.pop(subset_id, None)

self._unsubscribers.append(self._event_bus.subscribe(MapSetEvent, on_map_set))

async def on_map_subset(event: MapSubsetEvent) -> None:
if event.type == MapSetType.ROOMS and event.name:
room = Room(event.name, event.id, event.coordinates)
if self._map_data.rooms.get(event.id, None) != room:
self._map_data.rooms[room.id] = room

if len(self._map_data.rooms) == self._amount_rooms:
self._event_bus.notify(
RoomsEvent(list(self._map_data.rooms.values()))
)

elif self._map_data.map_subsets.get(event.id, None) != event:
self._map_data.map_subsets[event.id] = event

self._unsubscribers.append(
self._event_bus.subscribe(MapSubsetEvent, on_map_subset)
)

async def on_position(event: PositionsEvent) -> None:
self._map_data.positions = event.positions

Expand Down Expand Up @@ -280,10 +283,12 @@ async def on_minor_map(event: MinorMapEvent) -> None:

def disable(self) -> None:
"""Disable map."""
unsubscribers = self._unsubscribers
self._unsubscribers.clear()
self._unsubscribe_from(self._unsubscribers)

def _unsubscribe_from(self, unsubscribers: list[Callable[[], None]]) -> None:
for unsubscribe in unsubscribers:
unsubscribe()
unsubscribers.clear()

def refresh(self) -> None:
"""Manually refresh map."""
Expand Down Expand Up @@ -377,6 +382,7 @@ def get_base64_map(self, width: int | None = None) -> bytes:
async def teardown(self) -> None:
"""Teardown map."""
self.disable()
self._unsubscribe_from(self._unsubscribers_internal)
await cancel(self._tasks)


Expand Down
1 change: 1 addition & 0 deletions requirements-test.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ pytest-timeout==2.1.0
setuptools>=65.5.1 # not directly required, pinned by Snyk to avoid a vulnerability
testfixtures==7.1.0
types-cachetools==5.3.0.6
types-mock==5.1.0.2
5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,8 @@ def execute_mock() -> AsyncMock:
@pytest.fixture
def event_bus(execute_mock: AsyncMock) -> EventBus:
return EventBus(execute_mock)


@pytest.fixture
def event_bus_mock() -> Mock:
return Mock(spec_set=EventBus)
25 changes: 22 additions & 3 deletions tests/test_map.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import asyncio
from unittest.mock import AsyncMock
from unittest.mock import ANY, AsyncMock, Mock, call

import pytest

from deebot_client.events.event_bus import EventBus
from deebot_client.events.map import MapChangedEvent, Position, PositionType
from deebot_client.map import MapData, _calc_point
from deebot_client.events.map import (
MapChangedEvent,
MapSetEvent,
MapSubsetEvent,
Position,
PositionType,
)
from deebot_client.map import Map, MapData, _calc_point
from deebot_client.models import Room

_test_calc_point_data = [
Expand Down Expand Up @@ -50,3 +56,16 @@ async def test_cycle() -> None:
await asyncio.sleep(1.1)

await test_cycle()


async def test_Map_internal_subscriptions(
execute_mock: AsyncMock, event_bus_mock: Mock
) -> None:
map = Map(execute_mock, event_bus_mock)

calls = [call(MapSetEvent, ANY), call(MapSubsetEvent, ANY)]
event_bus_mock.subscribe.assert_has_calls(calls)
assert len(map._unsubscribers_internal) == len(calls)

await map.teardown()
assert not map._unsubscribers_internal

0 comments on commit 5534bc4

Please sign in to comment.