mirror of
https://github.com/AstrBotDevs/AstrBot
synced 2026-07-16 01:40:15 +08:00
- Introduced LoadedCapability class to manage plugin capabilities. - Updated load_plugin function to discover and load capabilities alongside handlers. - Enhanced Peer class to handle remote provided capabilities during initialization. - Added tests for capability registration and invocation in legacy plugins. - Improved MessageChain and message component handling in legacy plugins. - Added comprehensive tests for legacy plugin integration and compatibility. - Updated protocol messages to include provided capabilities in initialization. - Enhanced top-level module imports to include capability-related functions.
241 lines
8.0 KiB
Python
241 lines
8.0 KiB
Python
"""
|
|
Tests for clients/platform.py - PlatformClient implementation.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import AsyncMock, MagicMock
|
|
|
|
import pytest
|
|
|
|
from astrbot_sdk.clients.platform import PlatformClient
|
|
from astrbot_sdk.clients._proxy import CapabilityProxy
|
|
from astrbot_sdk.protocol.descriptors import SessionRef
|
|
|
|
|
|
class TestPlatformClientInit:
|
|
"""Tests for PlatformClient initialization."""
|
|
|
|
def test_init_with_proxy(self):
|
|
"""PlatformClient should store proxy reference."""
|
|
proxy = MagicMock(spec=CapabilityProxy)
|
|
client = PlatformClient(proxy)
|
|
assert client._proxy is proxy
|
|
|
|
|
|
class TestPlatformClientSend:
|
|
"""Tests for PlatformClient.send() method."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_returns_response(self):
|
|
"""send() should return response dict."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={"message_id": "msg_123", "sent": True})
|
|
|
|
client = PlatformClient(proxy)
|
|
result = await client.send("session-1", "Hello")
|
|
|
|
proxy.call.assert_called_once_with(
|
|
"platform.send",
|
|
{"session": "session-1", "text": "Hello"},
|
|
)
|
|
assert result["message_id"] == "msg_123"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_with_empty_text(self):
|
|
"""send() should work with empty text."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={})
|
|
|
|
client = PlatformClient(proxy)
|
|
await client.send("session-1", "")
|
|
|
|
call_args = proxy.call.call_args[0][1]
|
|
assert call_args["text"] == ""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_with_special_characters(self):
|
|
"""send() should handle special characters in text."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={})
|
|
|
|
client = PlatformClient(proxy)
|
|
await client.send("session-1", "Hello\nWorld\t! @#$%")
|
|
|
|
call_args = proxy.call.call_args[0][1]
|
|
assert call_args["text"] == "Hello\nWorld\t! @#$%"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_with_session_ref_adds_target_payload(self):
|
|
"""send() should preserve structured session targets while keeping session string."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={})
|
|
|
|
client = PlatformClient(proxy)
|
|
await client.send(
|
|
SessionRef(
|
|
conversation_id="session-1",
|
|
platform="test",
|
|
raw={"trace_id": "trace-1"},
|
|
),
|
|
"Hello",
|
|
)
|
|
|
|
proxy.call.assert_called_once_with(
|
|
"platform.send",
|
|
{
|
|
"session": "session-1",
|
|
"target": {
|
|
"conversation_id": "session-1",
|
|
"platform": "test",
|
|
"raw": {"trace_id": "trace-1"},
|
|
},
|
|
"text": "Hello",
|
|
},
|
|
)
|
|
|
|
|
|
class TestPlatformClientSendImage:
|
|
"""Tests for PlatformClient.send_image() method."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_image_returns_response(self):
|
|
"""send_image() should return response dict."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={"image_id": "img_456"})
|
|
|
|
client = PlatformClient(proxy)
|
|
result = await client.send_image("session-1", "https://example.com/image.png")
|
|
|
|
proxy.call.assert_called_once_with(
|
|
"platform.send_image",
|
|
{"session": "session-1", "image_url": "https://example.com/image.png"},
|
|
)
|
|
assert result["image_id"] == "img_456"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_image_with_file_url(self):
|
|
"""send_image() should work with file:// URL."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={})
|
|
|
|
client = PlatformClient(proxy)
|
|
await client.send_image("session-1", "file:///path/to/image.jpg")
|
|
|
|
call_args = proxy.call.call_args[0][1]
|
|
assert call_args["image_url"] == "file:///path/to/image.jpg"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_image_with_base64_url(self):
|
|
"""send_image() should work with data URL."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={})
|
|
|
|
client = PlatformClient(proxy)
|
|
await client.send_image("session-1", "data:image/png;base64,abc123")
|
|
|
|
call_args = proxy.call.call_args[0][1]
|
|
assert call_args["image_url"] == "data:image/png;base64,abc123"
|
|
|
|
|
|
class TestPlatformClientSendChain:
|
|
"""Tests for PlatformClient.send_chain() method."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_chain_returns_response(self):
|
|
"""send_chain() should return response dict."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={"message_id": "chain_123"})
|
|
|
|
client = PlatformClient(proxy)
|
|
result = await client.send_chain(
|
|
"session-1",
|
|
[{"type": "Plain", "text": "Hello"}],
|
|
)
|
|
|
|
proxy.call.assert_called_once_with(
|
|
"platform.send_chain",
|
|
{"session": "session-1", "chain": [{"type": "Plain", "text": "Hello"}]},
|
|
)
|
|
assert result["message_id"] == "chain_123"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_send_chain_with_multiple_components(self):
|
|
"""send_chain() should preserve the original component payloads."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={})
|
|
|
|
client = PlatformClient(proxy)
|
|
await client.send_chain(
|
|
"session-1",
|
|
[
|
|
{"type": "Plain", "text": "Hello"},
|
|
{"type": "Image", "file": "https://example.com/a.png"},
|
|
],
|
|
)
|
|
|
|
call_args = proxy.call.call_args[0][1]
|
|
assert call_args["chain"][0]["text"] == "Hello"
|
|
assert call_args["chain"][1]["file"] == "https://example.com/a.png"
|
|
|
|
|
|
class TestPlatformClientGetMembers:
|
|
"""Tests for PlatformClient.get_members() method."""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_members_returns_list(self):
|
|
"""get_members() should return list of members."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(
|
|
return_value={
|
|
"members": [
|
|
{"id": "user1", "name": "Alice"},
|
|
{"id": "user2", "name": "Bob"},
|
|
]
|
|
}
|
|
)
|
|
|
|
client = PlatformClient(proxy)
|
|
result = await client.get_members("group-1")
|
|
|
|
proxy.call.assert_called_once_with(
|
|
"platform.get_members",
|
|
{"session": "group-1"},
|
|
)
|
|
assert len(result) == 2
|
|
assert result[0]["name"] == "Alice"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_members_returns_empty_list(self):
|
|
"""get_members() should return empty list when no members."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={})
|
|
|
|
client = PlatformClient(proxy)
|
|
result = await client.get_members("empty-group")
|
|
|
|
assert result == []
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_members_returns_empty_list_for_malformed_payload(self):
|
|
"""get_members() should ignore malformed non-list payloads."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={"members": "bad"})
|
|
|
|
client = PlatformClient(proxy)
|
|
result = await client.get_members("group-1")
|
|
|
|
assert result == []
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_members_with_private_session(self):
|
|
"""get_members() should work with private session."""
|
|
proxy = AsyncMock(spec=CapabilityProxy)
|
|
proxy.call = AsyncMock(return_value={"members": [{"id": "single_user"}]})
|
|
|
|
client = PlatformClient(proxy)
|
|
await client.get_members("private-123")
|
|
|
|
call_args = proxy.call.call_args[0][1]
|
|
assert call_args["session"] == "private-123"
|