Files
social-post-writer-bot/tests/test_raw_updates.py
T

105 lines
4.3 KiB
Python

import sqlite3
import tempfile
import unittest
from pathlib import Path
from unittest.mock import AsyncMock, patch
from aiogram import Dispatcher
from aiogram.types import Update
import bot
import raw_updates
class RawUpdateStorageTests(unittest.TestCase):
def setUp(self):
self.temp_dir = tempfile.TemporaryDirectory()
self.db_path = str(Path(self.temp_dir.name) / "updates.sqlite3")
raw_updates.init_raw_updates_db(self.db_path)
def tearDown(self):
self.temp_dir.cleanup()
def test_save_and_read_update_by_id(self):
payload = {"update_id": 456, "message": {"message_id": 8, "text": "Привет"}}
raw_updates.save_raw_update(456, payload, self.db_path)
record = raw_updates.get_raw_update(456, self.db_path)
self.assertIsNotNone(record)
self.assertEqual(record["event_type"], "message")
self.assertEqual(record["payload"], payload)
self.assertIsNone(raw_updates.get_raw_update(999, self.db_path))
def test_sensitive_fields_are_redacted(self):
raw_updates.save_raw_update(
457,
{"update_id": 457, "message": {"text": "Bearer abc123", "token": "private"}},
self.db_path,
)
record = raw_updates.get_raw_update(457, self.db_path)
assert record is not None
self.assertEqual(record["payload"]["message"]["text"], "Bearer [REDACTED]")
self.assertEqual(record["payload"]["message"]["token"], "[REDACTED]")
def test_records_older_than_retention_are_removed(self):
raw_updates.save_raw_update(458, {"update_id": 458, "message": {}}, self.db_path)
with sqlite3.connect(self.db_path) as connection:
connection.execute(
"UPDATE raw_updates SET received_at = datetime('now', '-31 days') WHERE update_id = 458"
)
raw_updates.init_raw_updates_db(self.db_path)
self.assertIsNone(raw_updates.get_raw_update(458, self.db_path))
class RawUpdateMiddlewareTests(unittest.IsolatedAsyncioTestCase):
async def test_update_is_persisted_before_handler(self):
update = Update.model_validate({
"update_id": 456,
"message": {
"message_id": 8,
"date": 1,
"chat": {"id": 42, "type": "private"},
"from": {"id": 42, "is_bot": False, "first_name": "Test"},
"text": "Привет",
},
})
temp_dir = tempfile.TemporaryDirectory()
self.addCleanup(temp_dir.cleanup)
db_path = str(Path(temp_dir.name) / "updates.sqlite3")
raw_updates.init_raw_updates_db(db_path)
middleware = raw_updates.RawUpdateMiddleware()
async def handler(event, data):
record = raw_updates.get_raw_update(456, db_path)
assert record is not None
self.assertEqual(record["payload"]["message"]["text"], "Привет")
return "handled"
with (
patch.object(raw_updates, "RAW_UPDATES_DB_PATH", db_path),
patch.object(raw_updates, "save_raw_update", wraps=raw_updates.save_raw_update) as save,
):
result = await middleware(handler, update, {})
self.assertEqual(result, "handled")
save.assert_called_once()
async def test_persistence_failure_does_not_block_update(self):
middleware = raw_updates.RawUpdateMiddleware()
update = Update(update_id=459)
handler = AsyncMock(return_value="handled")
with patch.object(raw_updates, "save_raw_update", side_effect=OSError("disk full")):
self.assertEqual(await middleware(handler, update, {}), "handled")
handler.assert_awaited_once()
class RawUpdateModeTests(unittest.TestCase):
def test_middleware_is_registered_in_every_environment(self):
"""Прод-бот тоже пишет сырые апдейты: групповые события видны только так."""
for deploy_env in ("production", "development"):
with self.subTest(deploy_env=deploy_env):
dispatcher = Dispatcher()
with patch.object(bot, "DEPLOY_ENV", deploy_env), patch.object(
dispatcher.update, "outer_middleware"
) as register:
self.assertTrue(bot.configure_raw_update_logging(dispatcher))
register.assert_called_once()