chore: база

This commit is contained in:
protokey committed 2026-09-24 17:05:42 +04:00
1 parent 93790da617
commit 5f53cadf89
39 files changed
+1458 -19

No files matched your search

+147 -2
View File
@@ -1,3 +1,148 @@
from django.test import TestCase
from types import SimpleNamespace
# Create your tests here.
from django.test import TestCase
from telebot import types
from . import interfaces
from .dispatcher import handle_update
from .interfaces import Interface, command, register, state, text
from .models import Bot, Chat, Message, User
class FakeApi:
def __init__(self):
self.sent = []
def send_message(self, chat_id, text, reply_markup=None, parse_mode=None):
self.sent.append((chat_id, text, reply_markup))
return SimpleNamespace(message_id=len(self.sent))
@register
class EchoInterface(Interface):
title = 'Echo'
@command('start')
@text('меню')
def menu(self, ctx):
ctx.reset()
ctx.reply('menu', keyboard=[['ask']])
@text('ask')
def ask(self, ctx):
ctx.state = 'await_name'
ctx.reply('name?')
@state('await_name')
def name(self, ctx):
ctx.data['name'] = ctx.text
ctx.state = ''
ctx.reply(f'hi {ctx.text}')
def fallback(self, ctx):
ctx.reply(f'echo {ctx.text}')
@register
class ChildInterface(EchoInterface):
@command('start')
def child_start(self, ctx):
ctx.reply('child')
def message_update(update_id, text, chat_type='private'):
return types.Update.de_json({
'update_id': update_id,
'message': {
'message_id': update_id,
'date': 0,
'text': text,
'chat': {'id': 42, 'type': chat_type, 'title': 'group' if chat_type != 'private' else None},
'from': {'id': 7, 'is_bot': False, 'first_name': 'Ann', 'username': 'ann'},
},
})
def member_update(update_id, status):
return types.Update.de_json({
'update_id': update_id,
'my_chat_member': {
'chat': {'id': -100, 'type': 'group', 'title': 'group'},
'from': {'id': 7, 'is_bot': False, 'first_name': 'Ann'},
'date': 0,
'old_chat_member': {'user': {'id': 1, 'is_bot': True, 'first_name': 'bot'}, 'status': 'left'},
'new_chat_member': {'user': {'id': 1, 'is_bot': True, 'first_name': 'bot'}, 'status': status},
},
})
class DispatcherTests(TestCase):
def setUp(self):
self.api = FakeApi()
self.bot = Bot.objects.create(token='1:test', interface=interfaces.key(EchoInterface))
def send(self, text, update_id=1, **kwargs):
handle_update(self.api, self.bot, message_update(update_id, text, **kwargs))
return self.api.sent[-1][1] if self.api.sent else None
def test_command_text_state_fallback(self):
self.assertEqual(self.send('/start'), 'menu')
self.assertEqual(self.send('ask'), 'name?')
self.assertEqual(self.send('Bob'), 'hi Bob')
self.assertEqual(self.send('whatever'), 'echo whatever')
self.assertEqual(Chat.objects.get().data, {'name': 'Bob'})
def test_command_with_bot_name_and_args(self):
self.assertEqual(self.send('/START@my_bot payload'), 'menu')
def test_saves_user_chat_and_messages(self):
self.send('/start')
user = User.objects.get()
self.assertEqual((user.tg_id, user.username), (7, 'ann'))
chat = Chat.objects.get()
self.assertEqual((chat.chat_id, chat.user, chat.type), (42, user, 'private'))
self.assertEqual(
list(Message.objects.order_by('pk').values_list('direction', 'text')),
[('in', '/start'), ('out', 'menu')],
)
def test_ignores_group_messages(self):
self.assertIsNone(self.send('/start', chat_type='group'))
self.assertFalse(Message.objects.exists())
def test_interface_switch_applies_immediately(self):
self.bot.interface = interfaces.key(ChildInterface)
self.assertEqual(self.send('/start'), 'child')
self.assertEqual(self.send('меню'), 'menu')
def test_no_interface(self):
self.bot.interface = ''
self.assertIsNone(self.send('/start'))
self.assertEqual(Message.objects.count(), 1)
def test_membership_marks_chat_deleted(self):
handle_update(self.api, self.bot, member_update(1, 'member'))
self.assertIsNone(Chat.objects.get().deleted_at)
handle_update(self.api, self.bot, member_update(2, 'kicked'))
self.assertIsNotNone(Chat.objects.get().deleted_at)
self.assertEqual(Chat.objects.count(), 1)
class InterfaceRegistryTests(TestCase):
def test_registered_interfaces_are_choices(self):
self.assertIn((interfaces.key(EchoInterface), 'Echo'), interfaces.choices())
class Unregistered(Interface):
pass
self.assertIsNone(interfaces.get(interfaces.key(Unregistered)))
class AdminTests(TestCase):
def test_bot_admin_pages(self):
from django.contrib.auth import get_user_model
admin = get_user_model().objects.create_superuser('root', 'secret-pass-123')
self.client.force_login(admin)
bot = Bot.objects.create(token='1:test')
for url in ('/admin/Telegram/bot/', '/admin/Telegram/bot/add/', f'/admin/Telegram/bot/{bot.pk}/change/'):
self.assertEqual(self.client.get(url).status_code, 200, url)