Skip to content

Commit aea5475

Browse files
whatevertogoclaude
andcommitted
test: refactor and enhance P1 platform adapter tests
- Refactor Telegram adapter tests to use shared mocks - Refactor Discord adapter tests to use shared mocks - Refactor Aiocqhttp adapter tests to use shared mocks - Fix sender name handling and command registration Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 94736ff commit aea5475

8 files changed

Lines changed: 4214 additions & 132 deletions

File tree

astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
import re
33
from collections.abc import AsyncGenerator
44

5-
from aiocqhttp import CQHttp, Event
5+
import aiocqhttp
66

7-
from astrbot.api.event import AstrMessageEvent, MessageChain
8-
from astrbot.api.message_components import (
7+
from astrbot.core.message.components import (
98
BaseMessageComponent,
109
File,
1110
Image,
@@ -15,7 +14,8 @@
1514
Record,
1615
Video,
1716
)
18-
from astrbot.api.platform import Group, MessageMember
17+
from astrbot.core.message.message_event_result import MessageChain
18+
from astrbot.core.platform import AstrMessageEvent, Group, MessageMember
1919

2020

2121
class AiocqhttpMessageEvent(AstrMessageEvent):
@@ -25,7 +25,7 @@ def __init__(
2525
message_obj,
2626
platform_meta,
2727
session_id,
28-
bot: CQHttp,
28+
bot: aiocqhttp.CQHttp,
2929
) -> None:
3030
super().__init__(message_str, message_obj, platform_meta, session_id)
3131
self.bot = bot
@@ -67,8 +67,8 @@ async def _parse_onebot_json(message_chain: MessageChain):
6767
@classmethod
6868
async def _dispatch_send(
6969
cls,
70-
bot: CQHttp,
71-
event: Event | None,
70+
bot: aiocqhttp.CQHttp,
71+
event: aiocqhttp.Event | None,
7272
is_group: bool,
7373
session_id: str | None,
7474
messages: list[dict],
@@ -82,7 +82,7 @@ async def _dispatch_send(
8282
await bot.send_group_msg(group_id=session_id_int, message=messages)
8383
elif not is_group and isinstance(session_id_int, int):
8484
await bot.send_private_msg(user_id=session_id_int, message=messages)
85-
elif isinstance(event, Event): # 最后兜底
85+
elif isinstance(event, aiocqhttp.Event): # 最后兜底
8686
await bot.send(event=event, message=messages)
8787
else:
8888
raise ValueError(
@@ -92,9 +92,9 @@ async def _dispatch_send(
9292
@classmethod
9393
async def send_message(
9494
cls,
95-
bot: CQHttp,
95+
bot: aiocqhttp.CQHttp,
9696
message_chain: MessageChain,
97-
event: Event | None = None,
97+
event: aiocqhttp.Event | None = None,
9898
is_group: bool = False,
9999
session_id: str | None = None,
100100
) -> None:

astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,37 @@
11
import asyncio
2+
import importlib
23
import itertools
34
import logging
45
import time
56
import uuid
6-
from collections.abc import Awaitable
7+
from collections.abc import Awaitable, Callable
78
from typing import Any, cast
89

9-
from aiocqhttp import CQHttp, Event
10+
import aiocqhttp
1011
from aiocqhttp.exceptions import ActionFailed
1112

12-
from astrbot.api import logger
13-
from astrbot.api.event import MessageChain
14-
from astrbot.api.message_components import *
15-
from astrbot.api.platform import (
13+
from astrbot import logger
14+
from astrbot.core.message.components import (
15+
At,
16+
ComponentTypes,
17+
File,
18+
Image,
19+
Plain,
20+
Poke,
21+
Reply,
22+
)
23+
from astrbot.core.message.message_event_result import MessageChain
24+
from astrbot.core.platform import (
1625
AstrBotMessage,
26+
Group,
1727
MessageMember,
1828
MessageType,
1929
Platform,
2030
PlatformMetadata,
2131
)
2232
from astrbot.core.platform.astr_message_event import MessageSesion
33+
from astrbot.core.platform.register import register_platform_adapter
2334

24-
from ...register import register_platform_adapter
25-
from .aiocqhttp_message_event import *
2635
from .aiocqhttp_message_event import AiocqhttpMessageEvent
2736

2837

@@ -37,6 +46,7 @@ def __init__(
3746
platform_config: dict,
3847
platform_settings: dict,
3948
event_queue: asyncio.Queue,
49+
bot_factory: Callable[..., Any] | None = None,
4050
) -> None:
4151
super().__init__(platform_config, event_queue)
4252

@@ -51,17 +61,10 @@ def __init__(
5161
support_streaming_message=False,
5262
)
5363

54-
self.bot = CQHttp(
55-
use_ws_reverse=True,
56-
import_name="aiocqhttp",
57-
api_timeout_sec=180,
58-
access_token=platform_config.get(
59-
"ws_reverse_token",
60-
), # 以防旧版本配置不存在
61-
)
64+
self.bot = self._create_bot(platform_config, bot_factory=bot_factory)
6265

6366
@self.bot.on_request()
64-
async def request(event: Event) -> None:
67+
async def request(event: aiocqhttp.Event) -> None:
6568
try:
6669
abm = await self.convert_message(event)
6770
if not abm:
@@ -72,7 +75,7 @@ async def request(event: Event) -> None:
7275
return
7376

7477
@self.bot.on_notice()
75-
async def notice(event: Event) -> None:
78+
async def notice(event: aiocqhttp.Event) -> None:
7679
try:
7780
abm = await self.convert_message(event)
7881
if abm:
@@ -82,7 +85,7 @@ async def notice(event: Event) -> None:
8285
return
8386

8487
@self.bot.on_message("group")
85-
async def group(event: Event) -> None:
88+
async def group(event: aiocqhttp.Event) -> None:
8689
try:
8790
abm = await self.convert_message(event)
8891
if abm:
@@ -92,7 +95,7 @@ async def group(event: Event) -> None:
9295
return
9396

9497
@self.bot.on_message("private")
95-
async def private(event: Event) -> None:
98+
async def private(event: aiocqhttp.Event) -> None:
9699
try:
97100
abm = await self.convert_message(event)
98101
if abm:
@@ -105,6 +108,29 @@ async def private(event: Event) -> None:
105108
def on_websocket_connection(_) -> None:
106109
logger.info("aiocqhttp(OneBot v11) 适配器已连接。")
107110

111+
@staticmethod
112+
def _create_bot(
113+
platform_config: dict,
114+
bot_factory: Callable[..., Any] | None = None,
115+
) -> aiocqhttp.CQHttp:
116+
if bot_factory is None:
117+
# Resolve aiocqhttp at runtime so tests that swap sys.modules later
118+
# still affect bot creation even if this module was imported earlier.
119+
aiocqhttp_module = importlib.import_module("aiocqhttp")
120+
bot_factory = aiocqhttp_module.CQHttp
121+
122+
return cast(
123+
aiocqhttp.CQHttp,
124+
bot_factory(
125+
use_ws_reverse=True,
126+
import_name="aiocqhttp",
127+
api_timeout_sec=180,
128+
access_token=platform_config.get(
129+
"ws_reverse_token",
130+
), # 以防旧版本配置不存在
131+
),
132+
)
133+
108134
async def send_by_session(
109135
self,
110136
session: MessageSesion,
@@ -124,7 +150,7 @@ async def send_by_session(
124150
)
125151
await super().send_by_session(session, message_chain)
126152

127-
async def convert_message(self, event: Event) -> AstrBotMessage | None:
153+
async def convert_message(self, event: aiocqhttp.Event) -> AstrBotMessage | None:
128154
logger.debug(f"[aiocqhttp] RawMessage {event}")
129155

130156
if event["post_type"] == "message":
@@ -139,7 +165,9 @@ async def convert_message(self, event: Event) -> AstrBotMessage | None:
139165

140166
return abm
141167

142-
async def _convert_handle_request_event(self, event: Event) -> AstrBotMessage:
168+
async def _convert_handle_request_event(
169+
self, event: aiocqhttp.Event
170+
) -> AstrBotMessage:
143171
"""OneBot V11 请求类事件"""
144172
abm = AstrBotMessage()
145173
abm.self_id = str(event.self_id)
@@ -164,7 +192,9 @@ async def _convert_handle_request_event(self, event: Event) -> AstrBotMessage:
164192
abm.raw_message = event
165193
return abm
166194

167-
async def _convert_handle_notice_event(self, event: Event) -> AstrBotMessage:
195+
async def _convert_handle_notice_event(
196+
self, event: aiocqhttp.Event
197+
) -> AstrBotMessage:
168198
"""OneBot V11 通知类事件"""
169199
abm = AstrBotMessage()
170200
abm.self_id = str(event.self_id)
@@ -196,7 +226,7 @@ async def _convert_handle_notice_event(self, event: Event) -> AstrBotMessage:
196226

197227
async def _convert_handle_message_event(
198228
self,
199-
event: Event,
229+
event: aiocqhttp.Event,
200230
get_reply=True,
201231
) -> AstrBotMessage:
202232
"""OneBot V11 消息类事件
@@ -309,7 +339,7 @@ async def _convert_handle_message_event(
309339
)
310340
# 添加必要的 post_type 字段,防止 Event.from_payload 报错
311341
reply_event_data["post_type"] = "message"
312-
new_event = Event.from_payload(reply_event_data)
342+
new_event = aiocqhttp.Event.from_payload(reply_event_data)
313343
if not new_event:
314344
logger.error(
315345
f"无法从回复消息数据构造 Event 对象: {reply_event_data}",
@@ -401,6 +431,14 @@ async def _convert_handle_message_event(
401431
f"不支持的消息段类型,已忽略: {t}, data={m['data']}"
402432
)
403433
continue
434+
if (
435+
t == "image"
436+
and not m["data"].get("file")
437+
and m["data"].get("url")
438+
):
439+
a = Image(file=m["data"]["url"], url=m["data"]["url"])
440+
abm.message.append(a)
441+
continue
404442
a = ComponentTypes[t](**m["data"])
405443
abm.message.append(a)
406444
except Exception as e:
@@ -456,5 +494,5 @@ async def handle_msg(self, message: AstrBotMessage) -> None:
456494

457495
self.commit_event(message_event)
458496

459-
def get_client(self) -> CQHttp:
497+
def get_client(self) -> aiocqhttp.CQHttp:
460498
return self.bot

0 commit comments

Comments
 (0)