94 lines
3.6 KiB
Python
94 lines
3.6 KiB
Python
import os
|
|
import sys
|
|
import tempfile
|
|
|
|
_fd, _TMP = tempfile.mkstemp(suffix=".db")
|
|
os.close(_fd)
|
|
os.unlink(_TMP)
|
|
os.environ["AGENT_OFFICE_DB_PATH"] = _TMP
|
|
|
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
|
|
import pytest
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def _init_db(monkeypatch):
|
|
import gc
|
|
gc.collect()
|
|
# config.DB_PATH는 첫 import 시 1회 고정되므로, 다른 테스트 파일과 조합 실행 시
|
|
# db가 이 파일의 _TMP가 아닌 다른 경로를 쓸 수 있다. db.DB_PATH를 이 파일 전용으로
|
|
# 강제해 영속 테이블의 테스트 간 누수를 결정적으로 차단.
|
|
import app.db as _db
|
|
monkeypatch.setattr(_db, "DB_PATH", _TMP)
|
|
for suffix in ("", "-wal", "-shm"):
|
|
p = _TMP + suffix
|
|
if os.path.exists(p):
|
|
os.remove(p)
|
|
_db.init_db()
|
|
yield
|
|
gc.collect()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_watch_command_calls_add():
|
|
from app.telegram import webhook
|
|
msg = {"chat": {"id": 1}, "text": "/watch 005930"}
|
|
with patch("app.telegram.webhook.service_proxy.watchlist_add",
|
|
new=AsyncMock(return_value={"ok": True})) as m, \
|
|
patch("app.telegram.webhook.api_call", new=AsyncMock(return_value={"ok": True})):
|
|
handled = await webhook.handle_watch_command(msg)
|
|
assert handled is True
|
|
m.assert_awaited_once_with("005930")
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_non_watch_text_ignored():
|
|
from app.telegram import webhook
|
|
msg = {"chat": {"id": 1}, "text": "안녕"}
|
|
assert await webhook.handle_watch_command(msg) is False
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_unwatch_command_calls_remove():
|
|
from app.telegram import webhook
|
|
msg = {"chat": {"id": 1}, "text": "/unwatch 005930"}
|
|
with patch("app.telegram.webhook.service_proxy.watchlist_remove",
|
|
new=AsyncMock(return_value={"ok": True})) as m, \
|
|
patch("app.telegram.webhook.api_call", new=AsyncMock(return_value={"ok": True})) as sent:
|
|
handled = await webhook.handle_watch_command(msg)
|
|
assert handled is True
|
|
m.assert_awaited_once_with("005930")
|
|
sent.assert_awaited_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_watchlist_command_calls_list_and_formats_items():
|
|
from app.telegram import webhook
|
|
msg = {"chat": {"id": 1}, "text": "/watchlist"}
|
|
items = {"watchlist": [{"ticker": "005930", "name": "삼성전자"}]}
|
|
with patch("app.telegram.webhook.service_proxy.watchlist_list",
|
|
new=AsyncMock(return_value=items)) as m, \
|
|
patch("app.telegram.webhook.api_call", new=AsyncMock(return_value={"ok": True})) as sent:
|
|
handled = await webhook.handle_watch_command(msg)
|
|
assert handled is True
|
|
m.assert_awaited_once_with()
|
|
text = sent.await_args.args[1]["text"]
|
|
assert "005930" in text and "삼성전자" in text
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_watch_command_reaches_handle_webhook_before_slash_dispatch():
|
|
"""handle_webhook이 /watch 를 agent_dispatcher 호출 전에 가로채야 한다."""
|
|
from app.telegram import webhook
|
|
data = {"message": {"chat": {"id": 1}, "text": "/watch 005930"}}
|
|
dispatcher = AsyncMock(side_effect=AssertionError("agent_dispatcher가 호출되면 안 됨"))
|
|
with patch("app.telegram.webhook.service_proxy.watchlist_add",
|
|
new=AsyncMock(return_value={"ok": True})) as m, \
|
|
patch("app.telegram.webhook.api_call", new=AsyncMock(return_value={"ok": True})):
|
|
result = await webhook.handle_webhook(data, agent_dispatcher=dispatcher)
|
|
assert result is None
|
|
m.assert_awaited_once_with("005930")
|
|
dispatcher.assert_not_awaited()
|