Files
LangBot/tests/unit_tests/platform/onebot_mock.py
T
RockChinQandHyu ec021c3c41 fix(onebot): validate WebSocket protocol with independent mock peer (#2653)
* feat(onebot): support main-port reverse and forward WebSocket connections

* fix(onebot): keep protocol metadata out of business events

* test(onebot): validate WS events and APIs against independent protocol peer

---------

Co-authored-by: Hyu <[email protected]>
2026-10-12 13:59:25 +08:00

108 lines
4.2 KiB
Python

"""Independent OneBot v11 wire peer; no LangBot transport/converter imports.
Contract: https://github.com/botuniverse/onebot-11 (api/public.md,
communication/{ws,ws-reverse,http}.md and event/*.md).
Only test data is served; no real QQ account or vendor service is contacted.
"""
import asyncio
import json
class OneBotMock:
def __init__(self):
self.ready = asyncio.Event()
self.requests = []
self.send = None
self.response = None
self.user = {'user_id': 10001, 'nickname': 'Alice', 'sex': 'unknown', 'age': 20}
self.group = {'group_id': 20001, 'group_name': 'Mock group', 'member_count': 2, 'max_member_count': 200}
self.member = self.user | {'group_id': 20001, 'card': 'Card', 'role': 'admin', 'title': 'Title', 'join_time': 1}
async def run(self, send, receive):
self.send = send
self.ready.set()
while True:
request = json.loads(await receive())
self.requests.append(request)
if self.response is not None:
response = dict(self.response)
else:
response = self.handle(request)
await send(json.dumps(response | {'echo': request.get('echo')}))
def handle(self, request):
action, params = request['action'], request.get('params', {})
for key in ('user_id', 'group_id', 'message_id', 'duration'):
if key in params:
assert type(params[key]) is int, (action, key, params[key])
data = None
if action in ('send_msg', 'send_private_msg', 'send_group_msg'):
assert isinstance(params['message'], (list, str))
data = {'message_id': 123}
elif action == 'get_msg':
data = self.message('private', 'friend')
elif action == 'get_login_info':
data = {'user_id': 42, 'nickname': 'Mock bot'}
elif action == 'get_stranger_info':
data = self.user
elif action == 'get_friend_list':
data = [self.user | {'remark': 'Friend'}]
elif action == 'get_group_info':
data = self.group
elif action == 'get_group_list':
data = [self.group]
elif action == 'get_group_member_info':
data = self.member
elif action == 'get_group_member_list':
data = [self.member]
elif action == 'get_status':
data = {'online': True, 'good': True}
elif action == 'get_version_info':
data = {'app_name': 'onebot-test-peer', 'app_version': '1', 'protocol_version': 'v11'}
elif action in ('can_send_image', 'can_send_record'):
data = {'yes': True}
elif action in ('get_image', 'get_record'):
data = {'file': '/mock/media'}
elif action == 'get_forward_msg':
data = {'message': []}
elif action == 'get_group_honor_info':
data = {'group_id': 20001}
elif action not in {
'delete_msg',
'set_group_name',
'set_group_ban',
'set_group_kick',
'set_group_leave',
'set_friend_add_request',
'set_group_add_request',
'set_group_card',
'set_group_special_title',
'set_group_admin',
'set_group_whole_ban',
}:
return {'status': 'failed', 'retcode': 1404, 'data': None}
return {'status': 'ok', 'retcode': 0, 'data': data}
async def emit(self, payload):
await self.ready.wait()
await self.send(json.dumps({'time': 1700000000, 'self_id': 42} | payload))
def message(self, kind, subtype, message=None):
result = {
'post_type': 'message',
'message_type': kind,
'sub_type': subtype,
'time': 1700000000,
'self_id': 42,
'message_id': 9,
'user_id': 10001,
'message': message if message is not None else [{'type': 'text', 'data': {'text': 'hello'}}],
'raw_message': 'hello',
'font': 0,
'sender': self.user,
}
if kind == 'group':
result.update(group_id=20001, anonymous=None, sender=self.member)
return result