test: lock down application and agent contracts

This commit is contained in:
kandrusyak
2026-07-27 17:37:45 +03:00
parent 4b7a50d0cc
commit 3cc60c69e1
2 changed files with 208 additions and 1 deletions

65
tests/test_application.py Normal file
View File

@@ -0,0 +1,65 @@
import tempfile
import unittest
from pathlib import Path
from unittest.mock import Mock, patch
from zoneinfo import ZoneInfo
from assistant_bot import application as application_module
from assistant_bot.auth import authentication_guard
from assistant_bot.handlers import (
ask_command,
help_command,
history_command,
inline_query,
model_command,
models_command,
new_conversation_command,
private_text,
private_voice,
start,
)
class ApplicationRegistrationTests(unittest.TestCase):
def test_registers_the_current_public_handlers_in_order(self) -> None:
with tempfile.TemporaryDirectory() as directory, patch.multiple(
application_module,
get_assistant_password=Mock(return_value="secret"),
get_bot_token=Mock(return_value="123456:TEST"),
get_db_path=Mock(
return_value=Path(directory) / "assistant.sqlite3"
),
get_assistant_mode=Mock(return_value="local"),
get_ollama_base_url=Mock(return_value="http://localhost:11434"),
get_whisper_model=Mock(return_value="small"),
get_whisper_device=Mock(return_value="cpu"),
get_whisper_compute_type=Mock(return_value="int8"),
get_whisper_language=Mock(return_value="ru"),
get_local_timezone=Mock(return_value=ZoneInfo("UTC")),
get_voice_max_duration_seconds=Mock(return_value=120),
):
application = application_module.create_application()
self.assertEqual(
[handler.callback for handler in application.handlers[-1]],
[authentication_guard],
)
self.assertEqual(
[handler.callback for handler in application.handlers[0]],
[
start,
help_command,
ask_command,
models_command,
model_command,
new_conversation_command,
history_command,
inline_query,
private_voice,
private_text,
],
)
if __name__ == "__main__":
unittest.main()

View File

@@ -6,7 +6,11 @@ from datetime import datetime, timezone
from pathlib import Path
from zoneinfo import ZoneInfo
from assistant_bot.agent import execute_agent_tool, parse_agent_decision
from assistant_bot.agent import (
build_agent_tool_prompt,
execute_agent_tool,
parse_agent_decision,
)
from assistant_bot.reminders import parse_reminder, unit_to_timedelta
from assistant_bot.storage import AssistantStorage
@@ -52,6 +56,144 @@ class AgentDecisionTests(unittest.TestCase):
self.assertTrue(decision.reset_context)
class AgentToolContractTests(unittest.TestCase):
TOOL_NAMES = (
"get_current_datetime",
"remember",
"list_memory",
"delete_memory",
"create_note",
"list_notes",
"delete_note",
"create_reminder",
"list_reminders",
"cancel_reminder",
"create_status",
"list_statuses",
"update_status",
"delete_status",
"search_conversation",
)
def test_prompt_exposes_all_supported_tool_names(self) -> None:
prompt = build_agent_tool_prompt(ZoneInfo("UTC"))
for tool_name in self.TOOL_NAMES:
with self.subTest(tool_name=tool_name):
self.assertIn(tool_name, prompt)
def test_crud_tool_result_shapes_remain_stable(self) -> None:
with tempfile.TemporaryDirectory() as directory:
storage = AssistantStorage(Path(directory) / "assistant.sqlite3")
common = {
"storage": storage,
"user_id": 42,
"chat_id": 100,
"tz": ZoneInfo("UTC"),
}
memory = execute_agent_tool(
"remember",
{"text": "короткие ответы"},
**common,
)
self.assertEqual(
memory,
{"ok": True, "id": memory["id"], "text": "короткие ответы"},
)
self.assertEqual(
execute_agent_tool("list_memory", {"limit": 10}, **common)[
"items"
][0]["id"],
memory["id"],
)
self.assertEqual(
execute_agent_tool(
"delete_memory",
{"id": memory["id"]},
**common,
),
{"ok": True, "id": memory["id"]},
)
note = execute_agent_tool(
"create_note",
{"text": "идея"},
**common,
)
self.assertEqual(
note,
{"ok": True, "id": note["id"], "text": "идея"},
)
self.assertEqual(
execute_agent_tool("list_notes", {}, **common)["items"][0][
"id"
],
note["id"],
)
self.assertEqual(
execute_agent_tool(
"delete_note",
{"id": note["id"]},
**common,
),
{"ok": True, "id": note["id"]},
)
status = execute_agent_tool(
"create_status",
{"title": "паспорт", "status": "ожидание"},
**common,
)
self.assertEqual(
status,
{
"ok": True,
"id": status["id"],
"title": "паспорт",
"status": "ожидание",
},
)
self.assertEqual(
execute_agent_tool(
"update_status",
{"id": status["id"], "status": "готово"},
**common,
),
{"ok": True, "id": status["id"], "status": "готово"},
)
self.assertEqual(
execute_agent_tool("list_statuses", {}, **common)["items"][0][
"status"
],
"готово",
)
self.assertEqual(
execute_agent_tool(
"delete_status",
{"id": status["id"]},
**common,
),
{"ok": True, "id": status["id"]},
)
def test_unknown_tool_error_remains_stable(self) -> None:
with tempfile.TemporaryDirectory() as directory:
result = execute_agent_tool(
"missing",
{},
AssistantStorage(Path(directory) / "assistant.sqlite3"),
user_id=42,
chat_id=100,
tz=ZoneInfo("UTC"),
)
self.assertEqual(
result,
{"ok": False, "error": "unknown tool: missing"},
)
class StorageTests(unittest.TestCase):
def test_user_authorization_is_persisted(self) -> None:
with tempfile.TemporaryDirectory() as directory: