chore: интерфесы бота
This commit is contained in:
1 parent
5f53cadf89
commit
6d322f36a9
42 files changed
+1731
-111
No files matched your search
+209
-12
@@ -1,18 +1,215 @@
|
||||
from unittest import mock
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from Telegram import interfaces
|
||||
from Telegram.dispatcher import handle_update
|
||||
from Telegram.models import Bot
|
||||
from Telegram.tests import FakeApi, message_update
|
||||
from Telegram.models import Bot, Chat, User as TelegramUser
|
||||
from Telegram.testing import Conversation, FakeApi
|
||||
|
||||
from .bot import MAIN_KEYBOARD, MyPointInterface
|
||||
from . import tasks
|
||||
from .bot import texts
|
||||
from .bot.interface import MyPointInterface, is_proxy_url, parse_credentials
|
||||
from .models import Point
|
||||
from .tests_services import FakeRunner, create_point, patch_runner
|
||||
|
||||
|
||||
class MyPointInterfaceTests(TestCase):
|
||||
class ParsersTests(TestCase):
|
||||
def test_credentials(self):
|
||||
self.assertEqual(parse_credentials('1.2.3.4:pa:ss').password, 'pa:ss')
|
||||
self.assertIsNone(parse_credentials('1.2.3.4:'))
|
||||
self.assertIsNone(parse_credentials('host:pw'))
|
||||
self.assertIsNone(parse_credentials('1.2.3.400:pw'))
|
||||
|
||||
def test_proxy_url(self):
|
||||
self.assertTrue(is_proxy_url('http://127.0.0.1:9050'))
|
||||
self.assertTrue(is_proxy_url('socks5://user:pw@proxy.example.com:1080'))
|
||||
self.assertFalse(is_proxy_url('http://127.0.0.1'))
|
||||
self.assertFalse(is_proxy_url('ftp://127.0.0.1:21'))
|
||||
|
||||
|
||||
class BotTestCase(TestCase):
|
||||
def setUp(self):
|
||||
self.bot = Bot.objects.create(token='1:test', interface=interfaces.key(MyPointInterface))
|
||||
self.chat = Conversation(self.bot)
|
||||
self.api = self.chat.api
|
||||
|
||||
def say(self, text):
|
||||
return self.chat.say(text)
|
||||
|
||||
@property
|
||||
def keyboard(self):
|
||||
return self.api.last_keyboard
|
||||
|
||||
|
||||
class MainMenuTests(BotTestCase):
|
||||
def test_start_and_main_menu_button_are_same(self):
|
||||
api = FakeApi()
|
||||
bot = Bot.objects.create(token='1:test', interface=interfaces.key(MyPointInterface))
|
||||
handle_update(api, bot, message_update(1, '/start'))
|
||||
handle_update(api, bot, message_update(2, 'главное меню'))
|
||||
self.assertEqual(api.sent[0][1], api.sent[1][1])
|
||||
self.assertEqual([button['text'] for button in api.sent[0][2].keyboard[0]], MAIN_KEYBOARD[0])
|
||||
self.assertEqual(self.say('/start'), texts.GREETING)
|
||||
self.assertEqual(self.keyboard, texts.MAIN_KEYBOARD)
|
||||
self.assertEqual(self.say(texts.MAIN_MENU), texts.GREETING)
|
||||
|
||||
def test_lists_points(self):
|
||||
self.say('/start')
|
||||
point = create_point(TelegramUser.objects.get())
|
||||
self.assertIn(point.name, self.say('/start'))
|
||||
self.assertEqual(self.keyboard, texts.MAIN_KEYBOARD_WITH_POINTS)
|
||||
|
||||
def test_faq_and_help(self):
|
||||
self.assertEqual(self.say(texts.FAQ), texts.FAQ_TEXT)
|
||||
self.assertEqual(self.say(texts.HELP), texts.HELP_TEXT)
|
||||
|
||||
|
||||
@mock.patch.object(tasks.install_point, 'send')
|
||||
class AddServerTests(BotTestCase):
|
||||
def fill(self, role_button, credentials):
|
||||
self.say(role_button)
|
||||
return self.say(credentials)
|
||||
|
||||
def test_full_flow(self, send):
|
||||
self.say(texts.ADD_SERVER)
|
||||
self.assertEqual(self.keyboard, texts.DRAFT_KEYBOARD)
|
||||
card = self.fill(texts.SERVER, '10.0.0.1:panel-pw')
|
||||
self.assertIn('Сервер: 10.0.0.1', card)
|
||||
self.assertNotIn('panel-pw', card)
|
||||
self.fill(texts.MASK, '10.0.0.2:mask-pw')
|
||||
self.say(texts.DOMAIN)
|
||||
self.say('Example.COM.')
|
||||
self.say(texts.CLOUDFLARE)
|
||||
self.say(texts.ENABLE)
|
||||
self.say(texts.PROXY)
|
||||
card = self.say(texts.CF_WARP)
|
||||
self.assertIn('Домен: example.com', card)
|
||||
self.assertIn('Cloudflare: Да', card)
|
||||
self.assertIn('Прокси: cf_warp', card)
|
||||
|
||||
self.assertEqual(self.say(texts.INSTALL), texts.INSTALL_STARTED)
|
||||
point = Point.objects.get()
|
||||
self.assertEqual((point.panel.address, point.panel.root_password), ('10.0.0.1', 'panel-pw'))
|
||||
self.assertEqual((point.mask.address, point.mask.root_password), ('10.0.0.2', 'mask-pw'))
|
||||
self.assertEqual((point.domain, point.cloudflare, point.outbound_proxy), ('example.com', True, 'cf_warp'))
|
||||
self.assertEqual(point.owner, TelegramUser.objects.get())
|
||||
send.assert_called_once_with(point.pk, Chat.objects.get().pk)
|
||||
# сообщения с паролями удалены из чата
|
||||
self.assertEqual(len(self.api.deleted), 2)
|
||||
self.assertEqual(Chat.objects.get().state, '')
|
||||
|
||||
def test_validation(self, send):
|
||||
self.say(texts.ADD_SERVER)
|
||||
self.assertEqual(self.say(texts.INSTALL), texts.DRAFT_INCOMPLETE)
|
||||
self.assertEqual(self.fill(texts.SERVER, 'nonsense'), texts.CREDENTIALS_INVALID)
|
||||
self.say('10.0.0.1:pw')
|
||||
self.assertEqual(self.fill(texts.MASK, '10.0.0.1:pw'), texts.ADDRESS_DUPLICATE)
|
||||
create_point(TelegramUser.objects.get())
|
||||
self.assertEqual(self.say('10.0.0.2:pw'), texts.ADDRESS_TAKEN.format(address='10.0.0.2'))
|
||||
self.say(texts.CANCEL)
|
||||
self.assertEqual(self.fill(texts.DOMAIN, 'not a domain'), texts.DOMAIN_INVALID)
|
||||
self.say(texts.CANCEL)
|
||||
self.assertEqual(self.fill(texts.PROXY, 'http://nope'), texts.PROXY_INVALID)
|
||||
send.assert_not_called()
|
||||
|
||||
def test_cloudflare_requires_domain(self, send):
|
||||
self.say(texts.ADD_SERVER)
|
||||
self.fill(texts.SERVER, '10.0.0.1:pw')
|
||||
self.fill(texts.MASK, '10.0.0.2:pw')
|
||||
self.fill(texts.CLOUDFLARE, texts.ENABLE)
|
||||
self.assertEqual(self.say(texts.INSTALL), texts.CLOUDFLARE_WITHOUT_DOMAIN)
|
||||
send.assert_not_called()
|
||||
|
||||
def test_cancel_in_prompt_returns_to_draft(self, send):
|
||||
self.say(texts.ADD_SERVER)
|
||||
self.fill(texts.SERVER, '10.0.0.1:pw')
|
||||
self.say(texts.MASK)
|
||||
self.assertIn('Сервер: 10.0.0.1', self.say(texts.CANCEL))
|
||||
self.assertEqual(self.say(texts.CANCEL), texts.GREETING)
|
||||
|
||||
|
||||
class PointMenuTests(BotTestCase):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.say('/start')
|
||||
self.point = create_point(TelegramUser.objects.get())
|
||||
self.point.status = Point.Status.READY
|
||||
self.point.save()
|
||||
|
||||
def open_point(self):
|
||||
self.say(texts.MANAGE)
|
||||
return self.say(self.point.name)
|
||||
|
||||
def test_select_point(self):
|
||||
self.assertIn(self.point.name, self.say(texts.MANAGE))
|
||||
self.assertEqual(self.say('unknown'), texts.POINT_NOT_FOUND)
|
||||
card = self.say(self.point.name)
|
||||
self.assertIn('Состояние: активен', card)
|
||||
self.assertEqual(self.keyboard, texts.POINT_KEYBOARD)
|
||||
|
||||
def test_foreign_point_is_not_found(self):
|
||||
other = Conversation(self.bot, user_id=8)
|
||||
other.say(texts.MANAGE)
|
||||
self.assertEqual(other.say(self.point.name), texts.POINT_NOT_FOUND)
|
||||
|
||||
@mock.patch.object(tasks.release_point, 'send')
|
||||
def test_release(self, send):
|
||||
self.open_point()
|
||||
self.say(texts.RELEASE)
|
||||
self.assertIn(self.point.name, self.say(texts.NO))
|
||||
self.assertIn('Продолжить?', self.say(texts.RELEASE))
|
||||
self.assertEqual(self.say(texts.YES), texts.RELEASE_STARTED)
|
||||
send.assert_called_once_with(self.point.pk, Chat.objects.get(user__tg_id=7).pk)
|
||||
self.point.refresh_from_db()
|
||||
self.assertEqual(self.point.status, Point.Status.RELEASING)
|
||||
|
||||
@mock.patch.object(tasks.release_point, 'send')
|
||||
def test_busy_point(self, send):
|
||||
self.point.status = Point.Status.INSTALLING
|
||||
self.point.save()
|
||||
self.open_point()
|
||||
self.assertEqual(self.say(texts.RELEASE), texts.POINT_BUSY.format(status='устанавливается'))
|
||||
send.assert_not_called()
|
||||
|
||||
@mock.patch.object(tasks.reinstall_point, 'send')
|
||||
def test_reinstall_one_server(self, send):
|
||||
self.open_point()
|
||||
self.say(texts.REINSTALL)
|
||||
self.assertEqual(self.say('10.9.9.9:pw'), texts.REINSTALL_UNKNOWN_ADDRESS.format(address='10.9.9.9'))
|
||||
self.assertEqual(self.say('10.0.0.2:new-pw'), texts.REINSTALL_STARTED)
|
||||
send.assert_called_once_with(self.point.pk, mock.ANY, '10.0.0.2', 'new-pw')
|
||||
self.assertEqual(len(self.api.deleted), 2)
|
||||
|
||||
@mock.patch.object(tasks.reinstall_point, 'send')
|
||||
def test_reinstall_with_old_passwords(self, send):
|
||||
self.open_point()
|
||||
self.say(texts.REINSTALL)
|
||||
self.say(texts.USE_OLD)
|
||||
send.assert_called_once_with(self.point.pk, mock.ANY, None, None)
|
||||
|
||||
def test_server_menu_button_opens_latest_point(self):
|
||||
self.assertIn(self.point.name, self.say(texts.SERVER_MENU))
|
||||
|
||||
|
||||
class TasksTests(TestCase):
|
||||
def setUp(self):
|
||||
bot = Bot.objects.create(token='1:test')
|
||||
owner = TelegramUser.objects.create(tg_id=1)
|
||||
self.chat = Chat.objects.create(bot=bot, chat_id=1, type='private', user=owner)
|
||||
self.point = create_point(owner)
|
||||
self.api = FakeApi()
|
||||
|
||||
def run_task(self, actor, *args, runner=None):
|
||||
with patch_runner(runner or FakeRunner()), mock.patch.object(Bot, 'api', return_value=self.api):
|
||||
actor.fn(*args)
|
||||
return self.api.last_text
|
||||
|
||||
def test_install_notifies_success(self):
|
||||
text = self.run_task(tasks.install_point, self.point.pk, self.chat.pk)
|
||||
self.assertIn(self.point.name, text)
|
||||
self.assertIn('готов к работе', text)
|
||||
self.assertEqual(self.api.last_keyboard, [[texts.SERVER_MENU]])
|
||||
|
||||
def test_install_notifies_failure(self):
|
||||
with self.assertLogs('App.tasks', 'ERROR'):
|
||||
text = self.run_task(tasks.install_point, self.point.pk, self.chat.pk, runner=FakeRunner(fail='xui'))
|
||||
self.assertIn('Не удалось', text)
|
||||
self.assertIn('boom', text)
|
||||
|
||||
def test_release_notifies_passwords(self):
|
||||
text = self.run_task(tasks.release_point, self.point.pk, self.chat.pk)
|
||||
self.assertIn('10.0.0.1 - пароль root', text)
|
||||
self.assertFalse(Point.objects.exists())
|
||||
Reference in new issue
Block a user