Serialize Matrix chat sends
This commit is contained in:
parent
4533118b68
commit
17d580096b
4 changed files with 281 additions and 79 deletions
|
|
@ -44,7 +44,7 @@ async def test_matrix_dispatcher_registers_custom_handlers():
|
|||
user_id="u1", platform="matrix", chat_id=current_chat_id, command="settings_skills"
|
||||
)
|
||||
result = await runtime.dispatcher.dispatch(skills)
|
||||
assert any(isinstance(r, OutgoingMessage) and "!skill on/off" in r.text for r in result)
|
||||
assert any(isinstance(r, OutgoingMessage) and "mvp" in r.text.lower() for r in result)
|
||||
|
||||
toggle = IncomingCallback(
|
||||
user_id="u1",
|
||||
|
|
@ -54,7 +54,7 @@ async def test_matrix_dispatcher_registers_custom_handlers():
|
|||
payload={"skill_index": 2},
|
||||
)
|
||||
result = await runtime.dispatcher.dispatch(toggle)
|
||||
assert any(isinstance(r, OutgoingMessage) and "fetch-url" in r.text for r in result)
|
||||
assert any(isinstance(r, OutgoingMessage) and "mvp" in r.text.lower() for r in result)
|
||||
|
||||
|
||||
async def test_new_chat_creates_real_matrix_room_when_client_available():
|
||||
|
|
@ -226,7 +226,75 @@ async def test_bot_degrades_platform_errors_to_user_reply():
|
|||
)
|
||||
|
||||
|
||||
async def test_mat11_settings_returns_dashboard():
|
||||
async def test_unregistered_room_bootstraps_space_and_chat_on_first_message():
|
||||
runtime = build_runtime(platform=MockPlatformClient())
|
||||
await set_user_meta(runtime.store, "@alice:example.org", {"next_chat_index": 1})
|
||||
space_resp = SimpleNamespace(room_id="!space:example.org")
|
||||
chat_resp = SimpleNamespace(room_id="!chat1:example.org")
|
||||
client = SimpleNamespace(
|
||||
user_id="@bot:example.org",
|
||||
room_create=AsyncMock(side_effect=[space_resp, chat_resp]),
|
||||
room_put_state=AsyncMock(),
|
||||
room_send=AsyncMock(),
|
||||
)
|
||||
bot = MatrixBot(client, runtime)
|
||||
room = SimpleNamespace(room_id="!entry:example.org", display_name="Entry")
|
||||
event = SimpleNamespace(sender="@alice:example.org", body="hello")
|
||||
|
||||
await bot.on_room_message(room, event)
|
||||
|
||||
assert client.room_create.await_count == 2
|
||||
first_call = client.room_create.call_args_list[0]
|
||||
second_call = client.room_create.call_args_list[1]
|
||||
assert first_call.kwargs.get("space") is True
|
||||
assert first_call.kwargs.get("invite") == ["@alice:example.org"]
|
||||
assert second_call.kwargs.get("name") == "Чат 1"
|
||||
assert second_call.kwargs.get("invite") == ["@alice:example.org"]
|
||||
client.room_put_state.assert_awaited_once()
|
||||
room_meta = await get_room_meta(runtime.store, "!chat1:example.org")
|
||||
assert room_meta is not None
|
||||
assert room_meta["chat_id"] == "C1"
|
||||
user_meta = await get_user_meta(runtime.store, "@alice:example.org")
|
||||
assert user_meta is not None
|
||||
assert user_meta["space_id"] == "!space:example.org"
|
||||
room_send_calls = client.room_send.await_args_list
|
||||
assert any(call.args[0] == "!chat1:example.org" for call in room_send_calls)
|
||||
assert any(call.args[0] == "!entry:example.org" for call in room_send_calls)
|
||||
|
||||
|
||||
async def test_unregistered_room_creates_new_chat_in_existing_space():
|
||||
runtime = build_runtime(platform=MockPlatformClient())
|
||||
await set_user_meta(
|
||||
runtime.store,
|
||||
"@alice:example.org",
|
||||
{"space_id": "!space:example.org", "next_chat_index": 4},
|
||||
)
|
||||
chat_resp = SimpleNamespace(room_id="!chat4:example.org")
|
||||
client = SimpleNamespace(
|
||||
user_id="@bot:example.org",
|
||||
room_create=AsyncMock(return_value=chat_resp),
|
||||
room_put_state=AsyncMock(),
|
||||
room_send=AsyncMock(),
|
||||
)
|
||||
bot = MatrixBot(client, runtime)
|
||||
room = SimpleNamespace(room_id="!entry:example.org", display_name="Entry")
|
||||
event = SimpleNamespace(sender="@alice:example.org", body="hello")
|
||||
|
||||
await bot.on_room_message(room, event)
|
||||
|
||||
client.room_create.assert_awaited_once_with(
|
||||
name="Чат 4",
|
||||
visibility=RoomVisibility.private,
|
||||
is_direct=False,
|
||||
invite=["@alice:example.org"],
|
||||
)
|
||||
client.room_put_state.assert_awaited_once()
|
||||
room_meta = await get_room_meta(runtime.store, "!chat4:example.org")
|
||||
assert room_meta is not None
|
||||
assert room_meta["chat_id"] == "C4"
|
||||
|
||||
|
||||
async def test_mat11_settings_returns_mvp_unavailable_message():
|
||||
runtime = build_runtime(platform=MockPlatformClient())
|
||||
current_chat_id = "C9"
|
||||
|
||||
|
|
@ -238,15 +306,10 @@ async def test_mat11_settings_returns_dashboard():
|
|||
)
|
||||
result = await runtime.dispatcher.dispatch(settings_cmd)
|
||||
|
||||
assert len(result) >= 1
|
||||
assert len(result) == 1
|
||||
text = result[0].text
|
||||
assert "Скиллы" in text or "скиллы" in text.lower()
|
||||
assert "Личность" in text
|
||||
assert "Безопасность" in text
|
||||
assert "Активные чаты" in text
|
||||
assert "Изменить" not in text
|
||||
assert "!connectors" not in text
|
||||
assert "!whoami" not in text
|
||||
assert "недоступна" in text.lower()
|
||||
assert "mvp" in text.lower()
|
||||
|
||||
|
||||
async def test_mat12_help_returns_command_reference():
|
||||
|
|
@ -259,10 +322,26 @@ async def test_mat12_help_returns_command_reference():
|
|||
assert len(result) == 1
|
||||
text = result[0].text
|
||||
assert "!new" in text
|
||||
assert "!chats" in text
|
||||
assert "!rename" in text
|
||||
assert "!archive" in text
|
||||
assert "!settings" in text
|
||||
assert "!yes" in text
|
||||
assert "!context" in text
|
||||
assert "!save" in text
|
||||
assert "!load" in text
|
||||
assert "!reset" not in text
|
||||
assert "!settings" not in text
|
||||
assert "!skills" not in text
|
||||
|
||||
|
||||
async def test_unknown_command_returns_helpful_message():
|
||||
runtime = build_runtime(platform=MockPlatformClient())
|
||||
|
||||
result = await runtime.dispatcher.dispatch(
|
||||
IncomingCommand(user_id="u1", platform="matrix", chat_id="C1", command="clear")
|
||||
)
|
||||
|
||||
assert len(result) == 1
|
||||
assert "неизвестная команда" in result[0].text.lower()
|
||||
|
||||
|
||||
async def test_prepare_live_sync_returns_next_batch_from_bootstrap_sync():
|
||||
|
|
@ -302,3 +381,41 @@ async def test_build_runtime_uses_real_platform_when_matrix_backend_is_real(monk
|
|||
|
||||
assert isinstance(runtime.platform, RealPlatformClient)
|
||||
assert runtime.platform.agent_api.url == "ws://agent.example/agent_ws/"
|
||||
|
||||
|
||||
async def test_matrix_main_closes_platform_without_connecting_root_agent(monkeypatch):
|
||||
bot_module = importlib.import_module("adapter.matrix.bot")
|
||||
|
||||
platform_close = AsyncMock()
|
||||
agent_connect = AsyncMock()
|
||||
runtime = SimpleNamespace(
|
||||
platform=SimpleNamespace(
|
||||
close=platform_close,
|
||||
agent_api=SimpleNamespace(connect=agent_connect),
|
||||
)
|
||||
)
|
||||
|
||||
class FakeAsyncClient:
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.access_token = None
|
||||
self.callbacks = []
|
||||
self.sync_forever = AsyncMock()
|
||||
self.close = AsyncMock()
|
||||
|
||||
async def login(self, *args, **kwargs):
|
||||
raise AssertionError("login should not be called when access token is provided")
|
||||
|
||||
def add_event_callback(self, callback, event_type):
|
||||
self.callbacks.append((callback, event_type))
|
||||
|
||||
monkeypatch.setenv("MATRIX_HOMESERVER", "https://matrix.example.org")
|
||||
monkeypatch.setenv("MATRIX_USER_ID", "@bot:example.org")
|
||||
monkeypatch.setenv("MATRIX_ACCESS_TOKEN", "token")
|
||||
monkeypatch.setattr(bot_module, "AsyncClient", FakeAsyncClient)
|
||||
monkeypatch.setattr(bot_module, "build_runtime", lambda **kwargs: runtime)
|
||||
monkeypatch.setattr(bot_module, "prepare_live_sync", AsyncMock(return_value="s123"))
|
||||
|
||||
await bot_module.main()
|
||||
|
||||
agent_connect.assert_not_awaited()
|
||||
platform_close.assert_awaited_once()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue