blob: a245e174cd4cc4ba5e471128c2202dc69c2c6e11 [file] [log] [blame] [raw]
"""
Telegram Bot集成测试
"""
import pytest
import tempfile
from unittest.mock import Mock, AsyncMock, patch
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / "src"))
from claude_agent.telegram.bot import TelegramBot
class TestTelegramBotIntegration:
"""Telegram Bot集成测试"""
@pytest.fixture
def temp_config_dir(self):
"""创建临时配置目录"""
with tempfile.TemporaryDirectory() as tmpdir:
yield tmpdir
@pytest.fixture
def mock_config(self, temp_config_dir):
"""创建测试配置"""
config_content = """
[telegram]
bot_token = "123456:TEST_TOKEN"
allowed_users = [12345]
allowed_groups = [-67890]
[telegram.message]
stream_update_interval = 0.1
max_message_length = 4096
enable_markdown = true
context_history_limit = 10
[telegram.files]
supported_image_formats = ["jpg", "png"]
supported_document_formats = ["txt", "pdf"]
max_file_size_mb = 5
temp_dir = "temp/test"
[agent]
default_mode = "interactive"
max_conversation_history = 100
[logging]
level = "INFO"
colored = true
"""
config_file = Path(temp_config_dir) / "test.toml"
config_file.write_text(config_content)
return temp_config_dir
@pytest.mark.asyncio
async def test_bot_initialization(self, mock_config):
"""测试Bot初始化"""
with patch('claude_agent.utils.config.get_config_manager') as mock_get_config:
# Mock配置管理器
mock_config_manager = Mock()
mock_config_manager.get_telegram_config.return_value = {
'bot_token': '123456:TEST_TOKEN',
'allowed_users': [12345],
'allowed_groups': [-67890],
'message': {
'stream_update_interval': 0.1,
'context_history_limit': 10
},
'files': {
'temp_dir': '/tmp/test',
'max_file_size_mb': 5
}
}
mock_get_config.return_value = mock_config_manager
# 创建Bot
bot = TelegramBot(config_name="test")
# 验证配置加载
assert bot.telegram_config['bot_token'] == '123456:TEST_TOKEN'
assert 12345 in bot.telegram_config['allowed_users']
assert -67890 in bot.telegram_config['allowed_groups']
@pytest.mark.asyncio
async def test_bot_invalid_token(self, mock_config):
"""测试无效Token的处理"""
with patch('claude_agent.utils.config.get_config_manager') as mock_get_config:
mock_config_manager = Mock()
mock_config_manager.get_telegram_config.return_value = {
'bot_token': 'YOUR_BOT_TOKEN_HERE', # 无效token
'allowed_users': [12345],
'allowed_groups': []
}
mock_get_config.return_value = mock_config_manager
# 应该抛出配置错误
with pytest.raises(ValueError, match="请配置有效的Telegram Bot Token"):
TelegramBot(config_name="test")
@pytest.mark.asyncio
async def test_bot_missing_config(self):
"""测试缺少配置的处理"""
with patch('claude_agent.utils.config.get_config_manager') as mock_get_config:
mock_config_manager = Mock()
mock_config_manager.get_telegram_config.return_value = {
'bot_token': '123456:TEST_TOKEN',
# 缺少 allowed_users 和 allowed_groups
}
mock_get_config.return_value = mock_config_manager
# 应该抛出配置错误
with pytest.raises(ValueError, match="缺少必需的配置项"):
TelegramBot(config_name="test")
@pytest.mark.asyncio
async def test_component_integration(self, mock_config):
"""测试组件集成"""
with patch('claude_agent.utils.config.get_config_manager') as mock_get_config:
# Mock配置
mock_config_manager = Mock()
mock_config_manager.get_telegram_config.return_value = {
'bot_token': '123456:TEST_TOKEN',
'allowed_users': [12345],
'allowed_groups': [-67890],
'message': {
'stream_update_interval': 0.1,
'context_history_limit': 10
},
'files': {
'temp_dir': '/tmp/test',
'max_file_size_mb': 5
}
}
mock_get_config.return_value = mock_config_manager
# Mock Application创建
with patch('claude_agent.telegram.bot.Application') as mock_app_class:
mock_builder = Mock()
mock_app = Mock()
mock_app.bot = Mock()
mock_app.initialize = AsyncMock()
mock_app.start = AsyncMock()
mock_app.updater = Mock()
mock_app.updater.start_polling = AsyncMock()
mock_app.add_handler = Mock()
mock_app.add_error_handler = Mock()
mock_builder.token.return_value = mock_builder
mock_builder.build.return_value = mock_app
mock_app_class.builder.return_value = mock_builder
# 创建并初始化Bot
bot = TelegramBot(config_name="test")
await bot.initialize()
# 验证组件创建
assert bot.context_manager is not None
assert bot.file_handler is not None
assert bot.claude_agent is not None
assert bot.stream_sender is not None
assert bot.message_handler is not None
assert bot.telegram_client is not None
# 验证Application配置
mock_builder.token.assert_called_with('123456:TEST_TOKEN')
mock_app.add_handler.assert_called()
mock_app.add_error_handler.assert_called()
@pytest.mark.asyncio
async def test_dependency_injection(self, mock_config):
"""测试依赖注入功能"""
with patch('claude_agent.utils.config.get_config_manager') as mock_get_config:
mock_config_manager = Mock()
mock_config_manager.get_telegram_config.return_value = {
'bot_token': '123456:TEST_TOKEN',
'allowed_users': [12345],
'allowed_groups': [-67890],
'message': {'context_history_limit': 10},
'files': {'temp_dir': '/tmp', 'max_file_size_mb': 5}
}
mock_get_config.return_value = mock_config_manager
# 创建Bot
bot = TelegramBot(config_name="test")
# 创建Mock组件
mock_context_manager = Mock()
mock_file_handler = Mock()
mock_claude_agent = Mock()
mock_stream_sender = Mock()
# 注入依赖
bot.set_context_manager(mock_context_manager)
bot.set_file_handler(mock_file_handler)
bot.set_claude_agent(mock_claude_agent)
bot.set_stream_sender(mock_stream_sender)
# 验证依赖注入
assert bot.context_manager == mock_context_manager
assert bot.file_handler == mock_file_handler
assert bot.claude_agent == mock_claude_agent
assert bot.stream_sender == mock_stream_sender
@pytest.mark.asyncio
async def test_get_stats(self, mock_config):
"""测试获取统计信息"""
with patch('claude_agent.utils.config.get_config_manager') as mock_get_config:
mock_config_manager = Mock()
mock_config_manager.get_telegram_config.return_value = {
'bot_token': '123456:TEST_TOKEN',
'allowed_users': [111, 222],
'allowed_groups': [-333, -444],
'message': {'context_history_limit': 10},
'files': {'temp_dir': '/tmp', 'max_file_size_mb': 5}
}
mock_get_config.return_value = mock_config_manager
# 创建Bot
bot = TelegramBot(config_name="test")
# Mock上下文管理器
mock_context_manager = Mock()
mock_context_manager.get_chat_count.return_value = 5
bot.set_context_manager(mock_context_manager)
# 获取统计信息
stats = bot.get_stats()
# 验证统计信息
assert stats['is_running'] is False
assert stats['config_name'] == "test"
assert stats['allowed_users_count'] == 2
assert stats['allowed_groups_count'] == 2
assert stats['active_chats'] == 5
@pytest.mark.asyncio
async def test_send_admin_message(self, mock_config):
"""测试发送管理员消息"""
with patch('claude_agent.utils.config.get_config_manager') as mock_get_config:
mock_config_manager = Mock()
mock_config_manager.get_telegram_config.return_value = {
'bot_token': '123456:TEST_TOKEN',
'allowed_users': [111, 222],
'allowed_groups': [],
'message': {'context_history_limit': 10},
'files': {'temp_dir': '/tmp', 'max_file_size_mb': 5}
}
mock_get_config.return_value = mock_config_manager
# 创建Bot
bot = TelegramBot(config_name="test")
# Mock Telegram客户端
mock_client = Mock()
mock_client.send_message = AsyncMock()
bot.telegram_client = mock_client
# 发送管理员消息
await bot.send_admin_message("Test admin message")
# 验证发送给所有允许的用户
assert mock_client.send_message.call_count == 2
calls = mock_client.send_message.call_args_list
# 验证消息内容
for call in calls:
assert call[1]['text'].startswith("📢 管理员消息:")
assert "Test admin message" in call[1]['text']
# 验证发送给正确的用户
sent_to_users = {call[1]['chat_id'] for call in calls}
assert sent_to_users == {111, 222}
@pytest.mark.asyncio
async def test_configuration_validation_edge_cases(self):
"""测试配置验证的边缘情况"""
with patch('claude_agent.utils.config.get_config_manager') as mock_get_config:
mock_config_manager = Mock()
# 测试空Token
mock_config_manager.get_telegram_config.return_value = {
'bot_token': '',
'allowed_users': [123],
'allowed_groups': []
}
mock_get_config.return_value = mock_config_manager
with pytest.raises(ValueError, match="请配置有效的Telegram Bot Token"):
TelegramBot(config_name="test")
# 测试空的allowed_users和allowed_groups
mock_config_manager.get_telegram_config.return_value = {
'bot_token': '123:valid_token',
'allowed_users': [],
'allowed_groups': []
}
# 应该能够创建(虽然没有授权用户)
bot = TelegramBot(config_name="test")
assert bot.telegram_config['allowed_users'] == []
assert bot.telegram_config['allowed_groups'] == []