diff --git a/tests/adapter/matrix/test_dispatcher.py b/tests/adapter/matrix/test_dispatcher.py index d8bfa69..b08e5bb 100644 --- a/tests/adapter/matrix/test_dispatcher.py +++ b/tests/adapter/matrix/test_dispatcher.py @@ -5,7 +5,7 @@ from unittest.mock import AsyncMock from adapter.matrix.bot import MatrixBot, build_runtime from adapter.matrix.handlers.auth import handle_invite -from adapter.matrix.store import get_room_meta +from adapter.matrix.store import get_room_meta, get_user_meta, set_user_meta from core.protocol import IncomingCallback, IncomingCommand, OutgoingMessage from sdk.mock import MockPlatformClient @@ -36,7 +36,7 @@ async def test_matrix_dispatcher_registers_custom_handlers(): user_id="u1", platform="matrix", chat_id="C1", command="settings_skills" ) result = await runtime.dispatcher.dispatch(skills) - assert any(isinstance(r, OutgoingMessage) and "Реакции 1️⃣-9️⃣" in r.text for r in result) + assert any(isinstance(r, OutgoingMessage) and "!skill on/off" in r.text for r in result) toggle = IncomingCallback( user_id="u1", @@ -50,8 +50,13 @@ async def test_matrix_dispatcher_registers_custom_handlers(): async def test_new_chat_creates_real_matrix_room_when_client_available(): - client = SimpleNamespace(room_create=AsyncMock(return_value=SimpleNamespace(room_id="!r2:example"))) + client = SimpleNamespace( + room_create=AsyncMock(return_value=SimpleNamespace(room_id="!r2:example")), + room_put_state=AsyncMock(), + room_invite=AsyncMock(), + ) runtime = build_runtime(platform=MockPlatformClient(), client=client) + await set_user_meta(runtime.store, "u1", {"space_id": "!space:example", "next_chat_index": 1}) start = IncomingCommand(user_id="u1", platform="matrix", chat_id="C1", command="start") await runtime.dispatcher.dispatch(start) @@ -65,40 +70,72 @@ async def test_new_chat_creates_real_matrix_room_when_client_available(): ) result = await runtime.dispatcher.dispatch(new) - client.room_create.assert_awaited_once_with(name="Research", invite=["u1"], is_direct=False) + client.room_create.assert_awaited_once_with(name="Research", visibility="private", is_direct=False) + client.room_put_state.assert_awaited_once() + put_call = client.room_put_state.call_args + assert put_call.kwargs.get("room_id") == "!space:example" or put_call.args[0] == "!space:example" chats = await runtime.chat_mgr.list_active("u1") assert [c.surface_ref for c in chats] == ["!r2:example"] - assert any(isinstance(r, OutgoingMessage) and "!r2:example" in r.text for r in result) + assert any(isinstance(r, OutgoingMessage) and "Research" in r.text for r in result) -async def test_invite_event_creates_dm_room_and_sends_welcome(): +async def test_invite_event_creates_space_and_chat_room(): runtime = build_runtime(platform=MockPlatformClient()) - client = SimpleNamespace(join=AsyncMock(), room_send=AsyncMock()) - room = SimpleNamespace(room_id="!dm:example.org", display_name="Alice DM") + space_resp = SimpleNamespace(room_id="!space:example.org") + chat_resp = SimpleNamespace(room_id="!chat1:example.org") + client = SimpleNamespace( + join=AsyncMock(), + room_create=AsyncMock(side_effect=[space_resp, chat_resp]), + room_put_state=AsyncMock(), + room_invite=AsyncMock(), + room_send=AsyncMock(), + ) + room = SimpleNamespace(room_id="!dm:example.org", display_name="Alice") event = SimpleNamespace(sender="@alice:example.org", membership="invite") await handle_invite(client, room, event, runtime.platform, runtime.store, runtime.auth_mgr) - client.join.assert_awaited_once_with("!dm:example.org") - client.room_send.assert_awaited_once() - meta = await get_room_meta(runtime.store, "!dm:example.org") - assert meta is not None - assert meta["chat_id"] == "C1" - assert meta["matrix_user_id"] == "@alice:example.org" + assert client.room_create.await_count == 2 + first_call = client.room_create.call_args_list[0] + assert first_call.kwargs.get("space") is True or ( + len(first_call.args) > 0 and first_call.kwargs.get("space") is True + ) + + client.room_put_state.assert_awaited_once() + put_state_call = client.room_put_state.call_args + assert put_state_call.kwargs.get("event_type") == "m.space.child" or put_state_call.args[1] == "m.space.child" + + user_meta = await get_user_meta(runtime.store, "@alice:example.org") + assert user_meta is not None + assert user_meta.get("space_id") == "!space:example.org" + + room_meta = await get_room_meta(runtime.store, "!chat1:example.org") + assert room_meta is not None + assert room_meta["chat_id"] == "C1" + assert room_meta["space_id"] == "!space:example.org" + assert await runtime.auth_mgr.is_authenticated("@alice:example.org") is True + client.room_send.assert_awaited_once() -async def test_invite_event_is_idempotent_per_room(): +async def test_invite_event_is_idempotent_per_user(): runtime = build_runtime(platform=MockPlatformClient()) - client = SimpleNamespace(join=AsyncMock(), room_send=AsyncMock()) - room = SimpleNamespace(room_id="!dm:example.org", display_name="Alice DM") + space_resp = SimpleNamespace(room_id="!space:example.org") + chat_resp = SimpleNamespace(room_id="!chat1:example.org") + client = SimpleNamespace( + join=AsyncMock(), + room_create=AsyncMock(side_effect=[space_resp, chat_resp]), + room_put_state=AsyncMock(), + room_invite=AsyncMock(), + room_send=AsyncMock(), + ) + room = SimpleNamespace(room_id="!dm:example.org", display_name="Alice") event = SimpleNamespace(sender="@alice:example.org", membership="invite") await handle_invite(client, room, event, runtime.platform, runtime.store, runtime.auth_mgr) await handle_invite(client, room, event, runtime.platform, runtime.store, runtime.auth_mgr) - client.join.assert_awaited_once_with("!dm:example.org") - client.room_send.assert_awaited_once() + assert client.room_create.await_count == 2 async def test_bot_ignores_its_own_messages(): diff --git a/tests/adapter/matrix/test_reactions.py b/tests/adapter/matrix/test_reactions.py index 0c9fccc..23f02f3 100644 --- a/tests/adapter/matrix/test_reactions.py +++ b/tests/adapter/matrix/test_reactions.py @@ -19,13 +19,14 @@ def test_build_skills_text(): text = build_skills_text(settings) assert "web-search" in text assert "fetch-url" in text - assert "Реакции 1️⃣-9️⃣" in text + assert "!skill on/off" in text def test_build_confirmation_text(): text = build_confirmation_text("Отправить письмо?") assert "Отправить письмо?" in text - assert "подтвердить" in text + assert "!yes" in text + assert "!no" in text def test_reaction_to_skill_index():