forked from LengKundee/MQL5-Google-Onedrive
120 lines
4.5 KiB
Python
120 lines
4.5 KiB
Python
import sys
|
|
import unittest
|
|
import asyncio
|
|
from unittest.mock import MagicMock, patch, AsyncMock
|
|
|
|
# Mock telegram modules BEFORE importing the bot script
|
|
# This prevents the script from exiting due to missing dependencies
|
|
sys.modules['telegram'] = MagicMock()
|
|
sys.modules['telegram.ext'] = MagicMock()
|
|
|
|
# Import the module to test
|
|
# We rely on the script being in the same directory or python path
|
|
import scripts.telegram_deploy_bot as bot
|
|
|
|
class TestTelegramBotAsync(unittest.TestCase):
|
|
def test_check_fly_status_success(self):
|
|
"""Test check_fly_status returns success message on 0 return code"""
|
|
async def run_test():
|
|
# Mock the subprocess process object
|
|
mock_proc = MagicMock()
|
|
mock_proc.returncode = 0
|
|
# communicate() is a coroutine, so the mock needs to return an awaitable
|
|
# that resolves to (stdout, stderr)
|
|
f = asyncio.Future()
|
|
f.set_result((b'App is running', b''))
|
|
mock_proc.communicate.return_value = f
|
|
|
|
# create_subprocess_exec is an async function, so mock it with AsyncMock
|
|
with patch('asyncio.create_subprocess_exec', new_callable=AsyncMock) as mock_exec:
|
|
mock_exec.return_value = mock_proc
|
|
|
|
result = await bot.check_fly_status()
|
|
|
|
# Check that create_subprocess_exec was called with correct args
|
|
mock_exec.assert_called_with(
|
|
'flyctl', 'status',
|
|
cwd=bot.REPO_ROOT,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE
|
|
)
|
|
|
|
# Check output format
|
|
self.assertIn("Fly.io Status", result)
|
|
self.assertIn("App is running", result)
|
|
self.assertNotIn("failed", result.lower())
|
|
|
|
asyncio.run(run_test())
|
|
|
|
def test_check_fly_status_failure(self):
|
|
"""Test check_fly_status returns failure message on non-0 return code"""
|
|
async def run_test():
|
|
mock_proc = MagicMock()
|
|
mock_proc.returncode = 1
|
|
|
|
f = asyncio.Future()
|
|
f.set_result((b'', b'Error: App not found'))
|
|
mock_proc.communicate.return_value = f
|
|
|
|
with patch('asyncio.create_subprocess_exec', new_callable=AsyncMock) as mock_exec:
|
|
mock_exec.return_value = mock_proc
|
|
|
|
result = await bot.check_fly_status()
|
|
|
|
self.assertIn("failed", result.lower())
|
|
self.assertIn("Error: App not found", result)
|
|
|
|
asyncio.run(run_test())
|
|
|
|
def test_check_fly_status_timeout(self):
|
|
"""Test check_fly_status handles timeout"""
|
|
async def run_test():
|
|
mock_proc = MagicMock()
|
|
|
|
# Simulate create_subprocess_exec returning our mock process
|
|
with patch('asyncio.create_subprocess_exec', new_callable=AsyncMock) as mock_exec:
|
|
mock_exec.return_value = mock_proc
|
|
|
|
# Mock wait_for to raise TimeoutError
|
|
with patch('asyncio.wait_for', side_effect=asyncio.TimeoutError):
|
|
result = await bot.check_fly_status()
|
|
|
|
self.assertIn("timed out", result.lower())
|
|
# Ensure kill was called
|
|
mock_proc.kill.assert_called_once()
|
|
|
|
asyncio.run(run_test())
|
|
|
|
def test_file_not_found(self):
|
|
"""Test check_fly_status handles missing executable"""
|
|
async def run_test():
|
|
with patch('asyncio.create_subprocess_exec', side_effect=FileNotFoundError):
|
|
result = await bot.check_fly_status()
|
|
self.assertIn("flyctl not found", result)
|
|
|
|
asyncio.run(run_test())
|
|
|
|
def test_check_fly_status_special_chars(self):
|
|
"""Test check_fly_status escapes HTML special characters"""
|
|
async def run_test():
|
|
mock_proc = MagicMock()
|
|
mock_proc.returncode = 0
|
|
|
|
f = asyncio.Future()
|
|
# Output with special characters
|
|
f.set_result((b'Status: <running> & happy', b''))
|
|
mock_proc.communicate.return_value = f
|
|
|
|
with patch('asyncio.create_subprocess_exec', new_callable=AsyncMock) as mock_exec:
|
|
mock_exec.return_value = mock_proc
|
|
|
|
result = await bot.check_fly_status()
|
|
|
|
# Check that output is escaped
|
|
self.assertIn("<running> & happy", result)
|
|
self.assertNotIn("<running>", result)
|
|
|
|
asyncio.run(run_test())
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|