Files
AstrBot/tests/test_kook/shared.py
shuiping233 1199b704a8 feat: implements support for KOOK role mentions (#7626)
* feat: 实现kook适配器响应`@`角色(role)的能力

* refactor: kook适配器处理role时,`At`组件保留`@`角色的名称而不是id

* fix: kook适配器处理role时,role_id的判断问题

* refactor: 移除kook适配器中的一个# type: ignore

* fix: 修复kook适配器 role mention转换成`At`组件时保留不是角色名称的bug;

* unittest: 给kook适配器添加带有role mention的事件消息的单测,并添加消息组件转换判断单测

* unittest: 部分重构test_kook_event.py和test_kook_types.py 单测

* unittest: 添加kook适配器的 `user/me` `user/view` 接口响应数据验证单测

* fix: 修复kook适配器接收频道权限更新消息会报错的bug

* fix:  不额外处理kook的道具消息

* fix: 使用async with self._http_client.get

* refactor: kook适配器转换文本内容为消息组件时,只strip mention之间的空格

* fix: 修复 role_mention_counter 计数不正确的问题

* fix: 修复kook适配器发送卡片失败的问题;区分两类kook 数据类的to_dict to_json行为

* chore: 添加注释

* refactor: 重构kook适配器的角色缓存功能,使其无锁,性能更好且具备良好的重试机制

* refactor: kook适配器的channel_id 改为 guild_id

* feat: kook适配器响应频道角色更新事件时不再清空整个角色id缓存,而是只清理特定频道的角色id缓存

* unittest: 添加kook适配器的update_role事件的数据类验证单测

* refactor: 补上了一些打印的日志消息文本

refactor: 补上了一些打印的日志消息文本

refactor: 补上了一些打印的日志消息文本

* refactor: 修复kook适配器潜在可能的类型问题

* refactor: `clean_roles_cache`重命名为`clear_guild_roles_cache`
2026-04-19 14:18:16 +08:00

112 lines
3.5 KiB
Python

import json
from unittest.mock import AsyncMock, MagicMock
from unittest.mock import AsyncMock
import aiohttp
from astrbot.api.platform import AstrBotMessage, MessageType
from astrbot.core.message.components import (
File,
Record,
)
from pathlib import Path
CURRENT_DIR = Path(__file__).parent
TEST_DATA_DIR = CURRENT_DIR / "data"
class KookEventDataPath:
GROUP_MESSAGE_WITH_MENTION = (
TEST_DATA_DIR / "kook_ws_event_group_message_with_mention.json"
)
GROUP_MESSAGE = TEST_DATA_DIR / "kook_ws_event_group_message.json"
HELLO = TEST_DATA_DIR / "kook_ws_event_hello.json"
MESSAGE_WITH_CARD_1 = TEST_DATA_DIR / "kook_ws_event_message_with_card_1.json"
MESSAGE_WITH_CARD_2 = TEST_DATA_DIR / "kook_ws_event_message_with_card_2.json"
PING = TEST_DATA_DIR / "kook_ws_event_ping.json"
PONG = TEST_DATA_DIR / "kook_ws_event_pong.json"
PRIVATE_MESSAGE = TEST_DATA_DIR / "kook_ws_event_private_message.json"
PRIVATE_SYSTEM_MESSAGE = TEST_DATA_DIR / "kook_ws_event_private_system_message.json"
RECONNECT_ERR = TEST_DATA_DIR / "kook_ws_event_reconnect_err.json"
RESUME_ACK = TEST_DATA_DIR / "kook_ws_event_resume_ack.json"
RESUME = TEST_DATA_DIR / "kook_ws_event_resume.json"
GROUP_SYSTEM_MESSAGE_UPDATE_ROLE = TEST_DATA_DIR / "kook_ws_event_group_system_message_update_role.json"
class KookApiDataPath:
USER_ME = TEST_DATA_DIR / "kook_api_response_user_me.json"
USER_VIEW = TEST_DATA_DIR / "kook_api_response_user_view.json"
def mock_kook_client(upload_asset_return: str, send_text_return: str):
client = MagicMock()
client.upload_asset = AsyncMock(return_value=upload_asset_return)
client.send_text = AsyncMock(return_value=send_text_return)
return client
def mock_http_client(
http_method: str = "get",
return_value: str | dict | list | None = None,
status: int = 200,
):
"""Mock aiohttp ClientSession"""
if isinstance(return_value, (dict, list)):
response_text = json.dumps(return_value)
else:
response_text = return_value or "{}"
mock_response = MagicMock()
mock_response.status = status
mock_response.text = AsyncMock(return_value=response_text)
mock_response.json = AsyncMock(
return_value=json.loads(response_text) if response_text else {}
)
mock_response.read = AsyncMock(return_value=response_text.encode())
mock_response.__aenter__ = AsyncMock(return_value=mock_response)
mock_response.__aexit__ = AsyncMock(return_value=None)
mock_session = MagicMock()
async def mock_method(*args, **kwargs):
return mock_response
setattr(mock_session, http_method.lower(), mock_method)
mock_session.__aenter__ = AsyncMock(return_value=mock_session)
mock_session.__aexit__ = AsyncMock(return_value=None)
mock_session.close = AsyncMock()
return mock_session
def mock_file_message(input: str):
message = MagicMock(spec=File)
message.get_file = AsyncMock(return_value=input)
return message
def mock_record_message(input: str):
message = MagicMock(spec=Record)
message.text = input
message.convert_to_file_path = AsyncMock(return_value=input)
return message
def mock_astrbot_message():
message = AstrBotMessage()
message.type = MessageType.OTHER_MESSAGE
message.group_id = "test"
message.session_id = "test"
message.message_id = "test"
return message
def mock_kook_roles_record(bot_id: str, http_client: aiohttp.ClientSession):
instance = AsyncMock()
instance.has_role_in_channel = AsyncMock(return_value=True)
return instance