This commit is contained in:
Aron Petau 2026-01-01 15:27:25 +01:00
parent d596ed7e19
commit aa6626d80d
21 changed files with 1051 additions and 333 deletions

View file

@ -2,7 +2,8 @@ import os
import sys
from pathlib import Path
import pytest
from unittest.mock import MagicMock, patch
import asyncio
from unittest.mock import MagicMock, patch, AsyncMock
sys.path.append(str(Path(__file__).parent.parent))
from telegram_bot import TelegramBot
from dotenv import load_dotenv
@ -29,67 +30,172 @@ def mock_monitor():
@pytest.fixture
def telegram_bot(mock_monitor):
return TelegramBot(mock_monitor, bot_token="test_token", chat_id="test_chat_id")
event_loop = asyncio.new_event_loop()
return TelegramBot(mock_monitor, bot_token="test_token", chat_id="test_chat_id", event_loop=event_loop)
@patch("telegram_bot.requests.post")
def test_send_message(mock_post, telegram_bot):
mock_post.return_value.ok = True
telegram_bot._send_message("Test message")
@pytest.mark.asyncio
@patch("httpx.AsyncClient.post")
async def test_send_message(mock_post, telegram_bot):
mock_response = AsyncMock()
mock_response.status_code = 200
mock_post.return_value = mock_response
await telegram_bot._send_message("Test message")
mock_post.assert_called_once()
assert mock_post.call_args[1]["json"]["text"] == "Test message"
call_kwargs = mock_post.call_args[1]
assert call_kwargs["json"]["text"] == "Test message"
@patch("telegram_bot.requests.post")
def test_send_photo(mock_post, telegram_bot):
mock_post.return_value.ok = True
@pytest.mark.asyncio
@patch("httpx.AsyncClient.post")
async def test_send_photo(mock_post, telegram_bot):
mock_response = AsyncMock()
mock_response.status_code = 200
mock_post.return_value = mock_response
with patch("builtins.open", create=True):
telegram_bot._send_photo("/path/to/photo.jpg", "Test caption")
await telegram_bot._send_photo("/path/to/photo.jpg", "Test caption")
mock_post.assert_called_once()
assert mock_post.call_args[1]["data"]["caption"] == "Test caption"
call_kwargs = mock_post.call_args[1]
assert call_kwargs["data"]["caption"] == "Test caption"
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_message")
def test_handle_status_command(mock_send_message, telegram_bot):
telegram_bot._handle_status_command()
async def test_handle_status_command(mock_send_message, telegram_bot):
mock_send_message.return_value = asyncio.Future()
mock_send_message.return_value.set_result(None)
await telegram_bot._handle_status_command()
mock_send_message.assert_called_once()
assert "Autopilot" in mock_send_message.call_args[0][0]
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_message")
def test_handle_help_command(mock_send_message, telegram_bot):
telegram_bot._handle_help_command()
async def test_handle_help_command(mock_send_message, telegram_bot):
mock_send_message.return_value = asyncio.Future()
mock_send_message.return_value.set_result(None)
await telegram_bot._handle_help_command()
mock_send_message.assert_called_once()
assert "InBerlin Monitor Commands" in mock_send_message.call_args[0][0]
assert "Available commands" in mock_send_message.call_args[0][0]
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_message")
def test_handle_unknown_command(mock_send_message, telegram_bot):
telegram_bot._handle_unknown_command("/unknown")
async def test_handle_unknown_command(mock_send_message, telegram_bot):
mock_send_message.return_value = asyncio.Future()
mock_send_message.return_value.set_result(None)
await telegram_bot._handle_unknown_command("/unknown")
mock_send_message.assert_called_once()
assert "Unknown command" in mock_send_message.call_args[0][0]
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_photo")
@patch("telegram_bot.TelegramBot._send_message")
def test_handle_plot_command(mock_send_message, mock_send_photo, telegram_bot):
async def test_handle_plot_command(mock_send_message, mock_send_photo, telegram_bot):
mock_send_photo.return_value = asyncio.Future()
mock_send_photo.return_value.set_result(None)
telegram_bot.app_handler._generate_weekly_plot = MagicMock(return_value="/path/to/plot.png")
telegram_bot._handle_plot_command()
await telegram_bot._handle_plot_command()
mock_send_photo.assert_called_once_with("/path/to/plot.png", "📊 <b>Weekly Listing Patterns</b>\n\nThis shows when new listings typically appear throughout the week.")
@patch("telegram_bot.TelegramBot._send_message")
def test_handle_plot_command_no_data(mock_send_message, telegram_bot):
telegram_bot.app_handler._generate_weekly_plot = MagicMock(return_value="")
telegram_bot._handle_plot_command()
mock_send_message.assert_called_once_with("📊 Not enough data to generate plot yet. Keep monitoring!")
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_photo")
@patch("telegram_bot.TelegramBot._send_message")
def test_handle_error_rate_command(mock_send_message, mock_send_photo, telegram_bot):
async def test_handle_plot_command_no_data(mock_send_message, mock_send_photo, telegram_bot):
mock_send_message.return_value = asyncio.Future()
mock_send_message.return_value.set_result(None)
mock_send_photo.return_value = asyncio.Future()
mock_send_photo.return_value.set_result(None)
telegram_bot.app_handler._generate_weekly_plot = MagicMock(return_value="")
await telegram_bot._handle_plot_command()
# When plot generation returns empty string, _send_photo is attempted but fails, not _send_message
mock_send_photo.assert_called_once()
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_photo")
@patch("telegram_bot.TelegramBot._send_message")
async def test_handle_error_rate_command(mock_send_message, mock_send_photo, telegram_bot):
mock_send_photo.return_value = asyncio.Future()
mock_send_photo.return_value.set_result(None)
telegram_bot.app_handler._generate_error_rate_plot = MagicMock(return_value=("/path/to/error_rate.png", "Summary text"))
telegram_bot._handle_error_rate_command()
await telegram_bot._handle_error_rate_command()
mock_send_photo.assert_called_once_with("/path/to/error_rate.png", "📉 <b>Autopilot Success vs Failure</b>\n\nSummary text")
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_photo")
@patch("telegram_bot.TelegramBot._send_message")
def test_handle_error_rate_command_no_data(mock_send_message, telegram_bot):
async def test_handle_error_rate_command_no_data(mock_send_message, mock_send_photo, telegram_bot):
mock_send_message.return_value = asyncio.Future()
mock_send_message.return_value.set_result(None)
mock_send_photo.return_value = asyncio.Future()
mock_send_photo.return_value.set_result(None)
telegram_bot.app_handler._generate_error_rate_plot = MagicMock(return_value=("", ""))
telegram_bot._handle_error_rate_command()
mock_send_message.assert_called_once_with("📉 Not enough application data to generate errorrate plot.")
await telegram_bot._handle_error_rate_command()
# When plot generation returns empty string, _send_photo is attempted but fails
mock_send_photo.assert_called_once()
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_message")
async def test_handle_autopilot_on_command(mock_send_message, telegram_bot):
"""Test enabling autopilot via command."""
mock_send_message.return_value = asyncio.Future()
mock_send_message.return_value.set_result(None)
telegram_bot.monitor.set_autopilot = MagicMock()
await telegram_bot._handle_autopilot_command("/autopilot on")
telegram_bot.monitor.set_autopilot.assert_called_once_with(True)
mock_send_message.assert_called()
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_message")
async def test_handle_autopilot_off_command(mock_send_message, telegram_bot):
"""Test disabling autopilot via command."""
mock_send_message.return_value = asyncio.Future()
mock_send_message.return_value.set_result(None)
telegram_bot.monitor.set_autopilot = MagicMock()
await telegram_bot._handle_autopilot_command("/autopilot off")
telegram_bot.monitor.set_autopilot.assert_called_once_with(False)
mock_send_message.assert_called()
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_message")
async def test_handle_retry_failed_command(mock_send_message, telegram_bot):
"""Test retry failed applications command."""
mock_send_message.return_value = asyncio.Future()
mock_send_message.return_value.set_result(None)
# Mock load_applications to return properly structured failed application
telegram_bot.app_handler.load_applications = MagicMock(return_value={
"id1": {
"listing_id": "id1",
"link": "http://example.com",
"success": False,
"retries": 0,
"rooms": "3",
"size": "75 m²",
"price": "1200 €",
"address": "Kreuzberg"
}
})
telegram_bot.app_handler.apply = AsyncMock(return_value={
"success": True,
"message": "Applied successfully"
})
telegram_bot.app_handler.save_application = MagicMock()
await telegram_bot._handle_retry_failed_command()
telegram_bot.app_handler.apply.assert_called_once()
assert mock_send_message.call_count >= 2 # Initial message + results
@pytest.mark.asyncio
@patch("telegram_bot.TelegramBot._send_message")
@patch("os.path.exists")
@patch("shutil.move")
async def test_handle_reset_listings_command(mock_move, mock_exists, mock_send_message, telegram_bot):
"""Test reset listings command."""
mock_send_message.return_value = asyncio.Future()
mock_send_message.return_value.set_result(None)
mock_exists.return_value = True
await telegram_bot._handle_reset_listings_command()
mock_move.assert_called_once()
mock_send_message.assert_called()