9afe5757be
* docs: align deployment sections across multilingual readmes * docs: normalize deployment punctuation and AUR guidance * docs: fix french and russian deployment wording * perf: optimize async io hot paths and extend benchmarks * fix: address async io review feedback * fix: address follow-up async io review comments * fix: align base64 io error handling in message components * fix: harden attachment export ids and tune io chunking * fix: preserve best-effort attachment export and batch writes * test: expand path conversion and helper coverage
179 lines
5.5 KiB
Python
179 lines
5.5 KiB
Python
import base64
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from aiohttp import web
|
|
|
|
from astrbot.core.message import components as components_module
|
|
from astrbot.core.message.components import File, Image, Record
|
|
from tests.fixtures.helpers import get_bound_tcp_port
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_image_convert_to_file_path_returns_absolute_path(tmp_path):
|
|
file_path = tmp_path / "img.bin"
|
|
file_path.write_bytes(b"img")
|
|
|
|
image = Image(file=str(file_path))
|
|
resolved = await image.convert_to_file_path()
|
|
|
|
assert resolved == os.path.abspath(str(file_path))
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_record_convert_to_file_path_returns_absolute_path(tmp_path):
|
|
file_path = tmp_path / "record.bin"
|
|
file_path.write_bytes(b"record")
|
|
|
|
record = Record(file=str(file_path))
|
|
resolved = await record.convert_to_file_path()
|
|
|
|
assert resolved == os.path.abspath(str(file_path))
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_file_component_get_file_returns_absolute_path(tmp_path):
|
|
file_path = tmp_path / "file.bin"
|
|
file_path.write_bytes(b"file")
|
|
|
|
file_component = File(name="file.bin", file=str(file_path))
|
|
resolved = await file_component.get_file()
|
|
|
|
assert resolved == os.path.abspath(str(file_path))
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_image_convert_to_base64_raises_on_missing_file(tmp_path):
|
|
image = Image(file=str(tmp_path / "missing.bin"))
|
|
|
|
with pytest.raises(Exception, match="not a valid file"):
|
|
await image.convert_to_base64()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_record_convert_to_base64_raises_on_missing_file(tmp_path):
|
|
record = Record(file=str(tmp_path / "missing.bin"))
|
|
|
|
with pytest.raises(Exception, match="not a valid file"):
|
|
await record.convert_to_base64()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_image_convert_to_base64_reads_existing_local_file(tmp_path):
|
|
raw = b"image-bytes"
|
|
file_path = tmp_path / "exists_image.bin"
|
|
file_path.write_bytes(raw)
|
|
|
|
image = Image(file=str(file_path))
|
|
encoded = await image.convert_to_base64()
|
|
|
|
assert base64.b64decode(encoded) == raw
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_record_convert_to_base64_reads_existing_local_file(tmp_path):
|
|
raw = b"record-bytes"
|
|
file_path = tmp_path / "exists_record.bin"
|
|
file_path.write_bytes(raw)
|
|
|
|
record = Record(file=str(file_path))
|
|
encoded = await record.convert_to_base64()
|
|
|
|
assert base64.b64decode(encoded) == raw
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_image_convert_to_base64_maps_permission_error(monkeypatch):
|
|
async def _raise_permission_error(_path: str) -> str:
|
|
raise PermissionError("permission denied")
|
|
|
|
monkeypatch.setattr(components_module, "file_to_base64", _raise_permission_error)
|
|
|
|
image = Image(file="/tmp/forbidden-image")
|
|
with pytest.raises(Exception, match="not a valid file"):
|
|
await image.convert_to_base64()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_record_convert_to_base64_maps_permission_error(monkeypatch):
|
|
async def _raise_permission_error(_path: str) -> str:
|
|
raise PermissionError("permission denied")
|
|
|
|
monkeypatch.setattr(components_module, "file_to_base64", _raise_permission_error)
|
|
|
|
record = Record(file="/tmp/forbidden-record")
|
|
with pytest.raises(Exception, match="not a valid file"):
|
|
await record.convert_to_base64()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_image_convert_to_file_path_from_base64_creates_absolute_file():
|
|
payload = b"image-base64-payload"
|
|
image = Image(file=f"base64://{base64.b64encode(payload).decode()}")
|
|
|
|
resolved = await image.convert_to_file_path()
|
|
resolved_path = Path(resolved)
|
|
|
|
assert resolved_path.is_absolute()
|
|
assert resolved_path.exists()
|
|
assert resolved_path.read_bytes() == payload
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_record_convert_to_file_path_from_base64_creates_absolute_file():
|
|
payload = b"record-base64-payload"
|
|
record = Record(file=f"base64://{base64.b64encode(payload).decode()}")
|
|
|
|
resolved = await record.convert_to_file_path()
|
|
resolved_path = Path(resolved)
|
|
|
|
assert resolved_path.is_absolute()
|
|
assert resolved_path.exists()
|
|
assert resolved_path.read_bytes() == payload
|
|
|
|
|
|
async def _serve_payload(payload: bytes, route: str):
|
|
async def handle(_request):
|
|
return web.Response(body=payload)
|
|
|
|
app = web.Application()
|
|
app.router.add_get(route, handle)
|
|
runner = web.AppRunner(app, access_log=None)
|
|
await runner.setup()
|
|
site = web.TCPSite(runner, "127.0.0.1", 0)
|
|
await site.start()
|
|
return runner, get_bound_tcp_port(site)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_image_convert_to_file_path_from_http_creates_absolute_file():
|
|
payload = b"image-http-payload"
|
|
runner, port = await _serve_payload(payload, "/img.bin")
|
|
try:
|
|
image = Image(file=f"http://127.0.0.1:{port}/img.bin")
|
|
resolved = await image.convert_to_file_path()
|
|
resolved_path = Path(resolved)
|
|
|
|
assert resolved_path.is_absolute()
|
|
assert resolved_path.exists()
|
|
assert resolved_path.read_bytes() == payload
|
|
finally:
|
|
await runner.cleanup()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_record_convert_to_file_path_from_http_creates_absolute_file():
|
|
payload = b"record-http-payload"
|
|
runner, port = await _serve_payload(payload, "/record.bin")
|
|
try:
|
|
record = Record(file=f"http://127.0.0.1:{port}/record.bin")
|
|
resolved = await record.convert_to_file_path()
|
|
resolved_path = Path(resolved)
|
|
|
|
assert resolved_path.is_absolute()
|
|
assert resolved_path.exists()
|
|
assert resolved_path.read_bytes() == payload
|
|
finally:
|
|
await runner.cleanup()
|