|
|
@@ -1001,7 +1001,7 @@ class TestPresence:
|
|
|
|
|
|
def _adapter(self):
|
|
|
adapter = _make_adapter()
|
|
|
- adapter._chatto_client.update_presence = AsyncMock()
|
|
|
+ adapter._chatto_client.set_presence = AsyncMock()
|
|
|
return adapter
|
|
|
|
|
|
async def test_refresh_loop_keeps_reannouncing_online(self):
|
|
|
@@ -1011,7 +1011,7 @@ class TestPresence:
|
|
|
with patch.object(ChattoConstants, "PRESENCE_REFRESH_INTERVAL", 0.01):
|
|
|
task = asyncio.create_task(adapter._presence_refresh_loop())
|
|
|
for _ in range(200):
|
|
|
- if adapter._chatto_client.update_presence.await_count >= 3:
|
|
|
+ if adapter._chatto_client.set_presence.await_count >= 3:
|
|
|
break
|
|
|
await asyncio.sleep(0.01)
|
|
|
adapter._closing = True
|
|
|
@@ -1021,21 +1021,21 @@ class TestPresence:
|
|
|
except asyncio.CancelledError:
|
|
|
pass
|
|
|
|
|
|
- assert adapter._chatto_client.update_presence.await_count >= 3
|
|
|
- for call in adapter._chatto_client.update_presence.await_args_list:
|
|
|
+ assert adapter._chatto_client.set_presence.await_count >= 3
|
|
|
+ for call in adapter._chatto_client.set_presence.await_args_list:
|
|
|
assert call.kwargs["status"] == PresenceStatus.ONLINE
|
|
|
|
|
|
async def test_refresh_survives_a_failing_call(self):
|
|
|
"""One bad tick must not kill the loop and strand the bot offline."""
|
|
|
adapter = self._adapter()
|
|
|
adapter._closing = False
|
|
|
- adapter._chatto_client.update_presence = AsyncMock(
|
|
|
+ adapter._chatto_client.set_presence = AsyncMock(
|
|
|
side_effect=[RuntimeError("boom"), None, None]
|
|
|
)
|
|
|
with patch.object(ChattoConstants, "PRESENCE_REFRESH_INTERVAL", 0.01):
|
|
|
task = asyncio.create_task(adapter._presence_refresh_loop())
|
|
|
for _ in range(200):
|
|
|
- if adapter._chatto_client.update_presence.await_count >= 3:
|
|
|
+ if adapter._chatto_client.set_presence.await_count >= 3:
|
|
|
break
|
|
|
await asyncio.sleep(0.01)
|
|
|
adapter._closing = True
|
|
|
@@ -1045,11 +1045,11 @@ class TestPresence:
|
|
|
except asyncio.CancelledError:
|
|
|
pass
|
|
|
|
|
|
- assert adapter._chatto_client.update_presence.await_count >= 3
|
|
|
+ assert adapter._chatto_client.set_presence.await_count >= 3
|
|
|
|
|
|
async def test_announce_online_reports_failure(self):
|
|
|
adapter = self._adapter()
|
|
|
- adapter._chatto_client.update_presence = AsyncMock(
|
|
|
+ adapter._chatto_client.set_presence = AsyncMock(
|
|
|
side_effect=RuntimeError("nope")
|
|
|
)
|
|
|
assert await adapter._announce_online() is False
|
|
|
@@ -1060,7 +1060,7 @@ class TestPresence:
|
|
|
adapter._chatto_client.close = AsyncMock()
|
|
|
client = adapter._chatto_client # disconnect() drops the reference
|
|
|
await adapter.disconnect()
|
|
|
- client.update_presence.assert_not_called()
|
|
|
+ client.set_presence.assert_not_called()
|
|
|
|
|
|
|
|
|
# -- Mentions of other people --
|
|
|
@@ -1079,7 +1079,13 @@ class TestForeignMention:
|
|
|
for key, value in overrides.items():
|
|
|
getattr(adapter.chatto_config, key).value = value
|
|
|
adapter.me = _make_user("bot-user-id", "hermes_bot")
|
|
|
- adapter._user_cache["user-1"] = _make_user("user-1", "alice")
|
|
|
+ room_members = [
|
|
|
+ DirectoryMember(user=adapter.me),
|
|
|
+ DirectoryMember(user=_make_user("user-1", "alice")),
|
|
|
+ DirectoryMember(user=_make_user("user-2", "bob")),
|
|
|
+ ]
|
|
|
+ for member in room_members:
|
|
|
+ adapter._user_cache[member.user.id] = member.user
|
|
|
adapter.handle_message = AsyncMock()
|
|
|
adapter.add_reaction = AsyncMock(return_value=True)
|
|
|
adapter._room_kinds["room-1"] = RoomKind.CHANNEL
|
|
|
@@ -1087,13 +1093,24 @@ class TestForeignMention:
|
|
|
# The directory knows bob and nobody else. Resolution is
|
|
|
# case-insensitive, as Chatto's single mention namespace guarantees
|
|
|
# (FDR-006) — the fake models that at its own boundary.
|
|
|
- adapter._chatto_client.get_user = AsyncMock(
|
|
|
+ adapter._chatto_client.admin_get_member = AsyncMock(
|
|
|
side_effect=lambda **kw: (
|
|
|
DirectoryMember(user=_make_user("user-2", "bob"))
|
|
|
if str(kw.get("login", "")).lower() == "bob"
|
|
|
else None
|
|
|
)
|
|
|
)
|
|
|
+ room_members = [
|
|
|
+ DirectoryMember(user=_make_user("user-1", "alice")),
|
|
|
+ DirectoryMember(user=_make_user("user-2", "bob")),
|
|
|
+ ]
|
|
|
+ room_ids = [m.user.id for m in room_members]
|
|
|
+ adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
+ return_value=(room_ids, Page())
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=room_members
|
|
|
+ )
|
|
|
return adapter
|
|
|
|
|
|
async def _dispatch(self, adapter, body, room_id="room-1"):
|
|
|
@@ -1116,7 +1133,7 @@ class TestForeignMention:
|
|
|
|
|
|
async def test_several_people_addressed_and_none_of_them_us(self):
|
|
|
adapter = self._adapter()
|
|
|
- adapter._chatto_client.get_user = AsyncMock(
|
|
|
+ adapter._chatto_client.admin_get_member = AsyncMock(
|
|
|
side_effect=lambda **kw: (
|
|
|
DirectoryMember(user=_make_user("u", kw["login"]))
|
|
|
if kw.get("login") in {"bob", "carol"}
|
|
|
@@ -1209,7 +1226,7 @@ class TestForeignMention:
|
|
|
adapter = self._adapter()
|
|
|
await self._dispatch(adapter, "@BOB ping")
|
|
|
await self._dispatch(adapter, "@bob again")
|
|
|
- assert adapter._chatto_client.get_user.await_count == 1
|
|
|
+ assert adapter._chatto_client.admin_get_member.await_count == 1
|
|
|
|
|
|
async def test_talking_about_mentions_is_not_a_mention(self):
|
|
|
"""Verbatim from the field: the instruction to send a mention later must
|
|
|
@@ -1227,7 +1244,7 @@ class TestForeignMention:
|
|
|
"""A plausible-looking @token that resolves to no user is not someone
|
|
|
else — answering a false positive beats falling silent on one."""
|
|
|
adapter = self._adapter()
|
|
|
- adapter._chatto_client.get_user = AsyncMock(return_value=None)
|
|
|
+ adapter._chatto_client.admin_get_member = AsyncMock(return_value=None)
|
|
|
await self._dispatch(adapter, "gilt das auch für @nonexistent_person?")
|
|
|
adapter.handle_message.assert_called_once()
|
|
|
adapter.add_reaction.assert_not_awaited()
|
|
|
@@ -1236,14 +1253,14 @@ class TestForeignMention:
|
|
|
adapter = self._adapter()
|
|
|
await self._dispatch(adapter, "@bob ping")
|
|
|
await self._dispatch(adapter, "@bob again")
|
|
|
- assert adapter._chatto_client.get_user.await_count == 1
|
|
|
+ assert adapter._chatto_client.admin_get_member.await_count == 1
|
|
|
assert adapter.handle_message.await_count == 0
|
|
|
|
|
|
async def test_an_email_address_is_not_a_mention(self):
|
|
|
adapter = self._adapter()
|
|
|
await self._dispatch(adapter, "schreib an bob@example.com")
|
|
|
adapter.handle_message.assert_called_once()
|
|
|
- adapter._chatto_client.get_user.assert_not_awaited()
|
|
|
+ adapter._chatto_client.admin_get_member.assert_not_awaited()
|
|
|
|
|
|
async def test_plain_message_is_unaffected(self):
|
|
|
adapter = self._adapter()
|
|
|
@@ -1381,7 +1398,7 @@ class TestRoomPolicies:
|
|
|
|
|
|
|
|
|
def _roster_user(user_id, login, presence=PresenceStatus.UNSPECIFIED, deleted=False):
|
|
|
- """A directory user as list_room_members() would return it."""
|
|
|
+ """A directory user — used as input to _members() and _directory_members()."""
|
|
|
return User(
|
|
|
id=user_id,
|
|
|
login=login,
|
|
|
@@ -1412,9 +1429,15 @@ class TestRoomRoster:
|
|
|
|
|
|
@staticmethod
|
|
|
def _members(*users, total_count=None):
|
|
|
- members = [DirectoryMember(user=user) for user in users]
|
|
|
- page = Page(total_count=total_count or len(members))
|
|
|
- return members, page
|
|
|
+ member_ids = [user.id for user in users]
|
|
|
+ page = Page(total_count=total_count or len(member_ids))
|
|
|
+ return member_ids, page
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def _directory_members(*users):
|
|
|
+ """DirectoryMember objects that batch_get_room_members() returns."""
|
|
|
+ directory_members = [DirectoryMember(user=user) for user in users]
|
|
|
+ return directory_members
|
|
|
|
|
|
async def _dispatch(
|
|
|
self,
|
|
|
@@ -1457,6 +1480,14 @@ class TestRoomRoster:
|
|
|
_roster_user("user-3", "carol", deleted=True),
|
|
|
)
|
|
|
)
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(
|
|
|
+ _roster_user("user-1", "alice", PresenceStatus.ONLINE),
|
|
|
+ _roster_user("user-2", "bob", PresenceStatus.OFFLINE),
|
|
|
+ _roster_user("bot-user-id", "hermes_bot"),
|
|
|
+ _roster_user("user-3", "carol", deleted=True),
|
|
|
+ )
|
|
|
+ )
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
|
|
|
@@ -1472,8 +1503,12 @@ class TestRoomRoster:
|
|
|
copy of the roster — repetition is the point, deduplication a bug."""
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
@@ -1495,8 +1530,12 @@ class TestRoomRoster:
|
|
|
adapter = self._adapter()
|
|
|
adapter.chatto_config.require_mention_rooms.value = ["room-1"]
|
|
|
adapter._room_kinds["room-1"] = RoomKind.UNSPECIFIED
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
@@ -1507,6 +1546,7 @@ class TestRoomRoster:
|
|
|
adapter = self._adapter()
|
|
|
adapter._room_kinds["dm-1"] = RoomKind.DM
|
|
|
adapter._chatto_client.list_room_members = AsyncMock()
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock()
|
|
|
|
|
|
await self._dispatch(adapter, "hi there", room_id="dm-1")
|
|
|
|
|
|
@@ -1520,6 +1560,7 @@ class TestRoomRoster:
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
side_effect=RuntimeError("directory down")
|
|
|
)
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock()
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
|
|
|
@@ -1529,12 +1570,13 @@ class TestRoomRoster:
|
|
|
async def test_large_room_notes_the_unfetched_rest(self):
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
+ bob = _roster_user("user-2", "bob")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(
|
|
|
- _roster_user("user-1", "alice"),
|
|
|
- _roster_user("user-2", "bob"),
|
|
|
- total_count=150,
|
|
|
- )
|
|
|
+ return_value=self._members(alice, bob, total_count=150)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice, bob)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
@@ -1546,8 +1588,12 @@ class TestRoomRoster:
|
|
|
roster; the already-answered lock then keeps further edits out."""
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
|
|
|
await self._edit(adapter, "no mention yet")
|
|
|
@@ -1562,13 +1608,18 @@ class TestRoomRoster:
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(return_value=([], Page()))
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock()
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
assert self._dispatched_event(adapter).channel_context is None
|
|
|
|
|
|
adapter.handle_message.reset_mock()
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
payload = _make_posted_payload(room_id="room-1", message_event_id="msg-9")
|
|
|
_with_get_message(
|
|
|
@@ -1589,8 +1640,12 @@ class TestRoomRoster:
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
# alice starts UNSPECIFIED (no presence label in the rendered entry).
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
@@ -1615,8 +1670,12 @@ class TestRoomRoster:
|
|
|
still rides on every turn, but the directory is never re-asked."""
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
@@ -1640,8 +1699,12 @@ class TestRoomRoster:
|
|
|
rendered line untouched — but the turn still carries it."""
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
@@ -1665,8 +1728,12 @@ class TestRoomRoster:
|
|
|
the bot in its own audience."""
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
@@ -1685,6 +1752,7 @@ class TestRoomRoster:
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
adapter._chatto_client.list_room_members = AsyncMock()
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock()
|
|
|
|
|
|
await adapter._handle_realtime_event(_make_presence_event(user_id="user-42"))
|
|
|
|
|
|
@@ -1696,11 +1764,13 @@ class TestRoomRoster:
|
|
|
next turn refetches once, delivering the updated line."""
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
+ bob = _roster_user("user-2", "bob")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(
|
|
|
- _roster_user("user-1", "alice"),
|
|
|
- _roster_user("user-2", "bob"),
|
|
|
- )
|
|
|
+ return_value=self._members(alice, bob)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice, bob)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
@@ -1713,8 +1783,9 @@ class TestRoomRoster:
|
|
|
assert "room-1" not in adapter._rosters
|
|
|
|
|
|
# The server directory now reflects who actually remained.
|
|
|
- adapter._chatto_client.list_room_members.return_value = self._members(
|
|
|
- _roster_user("user-2", "bob")
|
|
|
+ adapter._chatto_client.list_room_members.return_value = self._members(bob)
|
|
|
+ adapter._chatto_client.batch_get_room_members.return_value = (
|
|
|
+ self._directory_members(bob)
|
|
|
)
|
|
|
await self._dispatch(
|
|
|
adapter,
|
|
|
@@ -1743,8 +1814,12 @@ class TestRoomRoster:
|
|
|
next turn instead of paying a burst right away."""
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter)
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi")
|
|
|
@@ -1770,8 +1845,12 @@ class TestRoomRoster:
|
|
|
adapter = self._adapter()
|
|
|
self._seed_channel(adapter, room_id="gone-1")
|
|
|
adapter._joined_room_ids = ["gone-1"]
|
|
|
+ alice = _roster_user("user-1", "alice")
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(
|
|
|
- return_value=self._members(_roster_user("user-1", "alice"))
|
|
|
+ return_value=self._members(alice)
|
|
|
+ )
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ return_value=self._directory_members(alice)
|
|
|
)
|
|
|
|
|
|
await self._dispatch(adapter, "@hermes_bot hi", room_id="gone-1")
|
|
|
@@ -2196,7 +2275,7 @@ class TestInboundAttachments:
|
|
|
# NOTE: there are deliberately no tests for get_user(), set_presence() or
|
|
|
# set_custom_status() on the adapter. Those are not adapter responsibilities —
|
|
|
# callers use the chattolib client directly, which exposes them (client.get_user,
|
|
|
-# client.update_presence, client.update_custom_status). The adapter only touches
|
|
|
+# client.set_presence, client.update_custom_status). The adapter only touches
|
|
|
# presence in connect()/disconnect().
|
|
|
|
|
|
|
|
|
@@ -2566,17 +2645,22 @@ class TestSilentRoomRefresh:
|
|
|
async def test_join_log_shows_dm_partner_username(self, caplog):
|
|
|
adapter = self._adapter([])
|
|
|
adapter.me = User(id="bot-1", login="hermes", display_name="Hermes")
|
|
|
- directory: dict[str, list[DirectoryMember]] = {
|
|
|
- "dm-1": [
|
|
|
- DirectoryMember(user=adapter.me),
|
|
|
- DirectoryMember(user=_make_user("user-9", "paula")),
|
|
|
- ]
|
|
|
- }
|
|
|
+ dm_users = [
|
|
|
+ DirectoryMember(user=adapter.me),
|
|
|
+ DirectoryMember(user=_make_user("user-9", "paula")),
|
|
|
+ ]
|
|
|
|
|
|
async def list_members(room_id, **_kwargs):
|
|
|
- return directory.get(room_id, []), Page()
|
|
|
+ members = dm_users if room_id == "dm-1" else []
|
|
|
+ return [m.user.id for m in members], Page()
|
|
|
+
|
|
|
+ async def batch_members(room_id, user_ids):
|
|
|
+ return [dm for dm in dm_users if dm.user.id in user_ids]
|
|
|
|
|
|
adapter._chatto_client.list_room_members = AsyncMock(side_effect=list_members)
|
|
|
+ adapter._chatto_client.batch_get_room_members = AsyncMock(
|
|
|
+ side_effect=batch_members
|
|
|
+ )
|
|
|
dm = _make_room_state(_make_room("dm-1", "", RoomKind.DM), True)
|
|
|
adapter._chatto_client.list_rooms = AsyncMock(return_value=[dm])
|
|
|
|