mirror of
https://github.com/bytedance/deer-flow.git
synced 2026-10-26 13:16:24 +00:00
* fix(channels): pin JSON state encoding across platforms * test(channels): check encoding pins at each state I/O call --------- Co-authored-by: huyengiang101086-spec <270684046+huyengiang101086-spec@users.noreply.github.com> Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
60 lines
2.8 KiB
Python
60 lines
2.8 KiB
Python
"""Pin the cross-platform byte contract for IM channel JSON state writers."""
|
|
|
|
import ast
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
CHANNELS = Path(__file__).parents[1] / "app" / "channels"
|
|
|
|
|
|
def _state_io_calls(filename: str, class_name: str, method_name: str, call_name: str) -> list[ast.Call]:
|
|
module = ast.parse((CHANNELS / filename).read_text(encoding="utf-8"))
|
|
owner = next(node for node in module.body if isinstance(node, ast.ClassDef) and node.name == class_name)
|
|
method = next(node for node in owner.body if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)) and node.name == method_name)
|
|
calls = [node for node in ast.walk(method) if isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) and node.func.attr == call_name]
|
|
assert calls, f"{filename}:{class_name}.{method_name} has no {call_name} call"
|
|
return calls
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("filename", "class_name", "method_name", "call_name"),
|
|
[
|
|
("store.py", "JsonChannelStore", "_save", "NamedTemporaryFile"),
|
|
("discord.py", "DiscordChannel", "_persist_thread_mappings", "write_text"),
|
|
("runtime_config_store.py", "ChannelRuntimeConfigStore", "_save", "NamedTemporaryFile"),
|
|
("buzz_seen_events.py", "BuzzSeenEventStore", "_write_snapshot", "NamedTemporaryFile"),
|
|
("wechat.py", "WechatChannel", "_save_state", "write_text"),
|
|
("wechat.py", "WechatChannel", "_save_auth_state", "NamedTemporaryFile"),
|
|
],
|
|
)
|
|
def test_json_channel_state_writers_pin_utf8_and_lf(filename: str, class_name: str, method_name: str, call_name: str) -> None:
|
|
for call in _state_io_calls(filename, class_name, method_name, call_name):
|
|
keywords = {keyword.arg: keyword.value for keyword in call.keywords}
|
|
for name, expected in (("encoding", "utf-8"), ("newline", "")):
|
|
value = keywords.get(name)
|
|
assert isinstance(value, ast.Constant) and value.value == expected, f"{filename}:{call.lineno} must pin {name}={expected!r}"
|
|
|
|
|
|
def test_json_channel_store_writes_utf8_lf_bytes(tmp_path: Path) -> None:
|
|
from app.channels.store import JsonChannelStore
|
|
|
|
path = tmp_path / "channels" / "store.json"
|
|
store = JsonChannelStore(path)
|
|
store._set_sync("微信:资源", "thread-讨论", "用户")
|
|
|
|
text = path.read_bytes().decode("utf-8")
|
|
assert "\r" not in text
|
|
assert "\\u5fae\\u4fe1" in text
|
|
entry = json.loads(text)["微信:资源"]
|
|
assert entry["thread_id"] == "thread-讨论"
|
|
assert entry["user_id"] == "用户"
|
|
|
|
|
|
def test_discord_state_read_is_explicitly_utf8() -> None:
|
|
for call in _state_io_calls("discord.py", "DiscordChannel", "_load_active_threads", "read_text"):
|
|
keywords = {keyword.arg: keyword.value for keyword in call.keywords}
|
|
encoding = keywords.get("encoding")
|
|
assert isinstance(encoding, ast.Constant) and encoding.value == "utf-8"
|