158 lines
5.8 KiB
Python
158 lines
5.8 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from unittest.mock import AsyncMock
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
from yuxi.channels.adapters.imessage.probe import (
|
||
|
|
clear_rpc_support_cache,
|
||
|
|
get_rpc_support_cached,
|
||
|
|
set_rpc_support_cached,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
class TestRpcSupportCache:
|
||
|
|
def test_default_not_cached(self):
|
||
|
|
assert get_rpc_support_cached("http://new-server:1234") is None
|
||
|
|
|
||
|
|
def test_set_and_get(self):
|
||
|
|
set_rpc_support_cached("http://server:1234", True)
|
||
|
|
assert get_rpc_support_cached("http://server:1234") is True
|
||
|
|
|
||
|
|
def test_set_false(self):
|
||
|
|
set_rpc_support_cached("http://server:1234", False)
|
||
|
|
assert get_rpc_support_cached("http://server:1234") is False
|
||
|
|
|
||
|
|
def test_different_servers(self):
|
||
|
|
set_rpc_support_cached("http://s1:1234", True)
|
||
|
|
set_rpc_support_cached("http://s2:1234", False)
|
||
|
|
assert get_rpc_support_cached("http://s1:1234") is True
|
||
|
|
assert get_rpc_support_cached("http://s2:1234") is False
|
||
|
|
|
||
|
|
def test_clear(self):
|
||
|
|
set_rpc_support_cached("http://server:1234", True)
|
||
|
|
clear_rpc_support_cache()
|
||
|
|
assert get_rpc_support_cached("http://server:1234") is None
|
||
|
|
|
||
|
|
|
||
|
|
class TestProbeFunctions:
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_probe_bridge_returns_complete_info(self):
|
||
|
|
from yuxi.channels.adapters.imessage.probe import probe_bridge
|
||
|
|
|
||
|
|
mock_bridge = AsyncMock()
|
||
|
|
mock_bridge.probe_server = AsyncMock(
|
||
|
|
return_value={"version": "2.0.0", "os_version": "15.2"}
|
||
|
|
)
|
||
|
|
mock_bridge.get_handle = AsyncMock(
|
||
|
|
return_value={"connected": True, "handle": "bot@icloud.com"}
|
||
|
|
)
|
||
|
|
|
||
|
|
result = await probe_bridge(mock_bridge)
|
||
|
|
assert result["bridge_version"] == "2.0.0"
|
||
|
|
assert result["bridge_os_version"] == "15.2"
|
||
|
|
assert result["imessage_connected"] is True
|
||
|
|
assert result["imessage_handle"] == "bot@icloud.com"
|
||
|
|
|
||
|
|
@pytest.mark.asyncio
|
||
|
|
async def test_probe_bridge_disconnected(self):
|
||
|
|
from yuxi.channels.adapters.imessage.probe import probe_bridge
|
||
|
|
|
||
|
|
mock_bridge = AsyncMock()
|
||
|
|
mock_bridge.probe_server = AsyncMock(return_value={"version": "1.0"})
|
||
|
|
mock_bridge.get_handle = AsyncMock(
|
||
|
|
return_value={"connected": False, "handle": None}
|
||
|
|
)
|
||
|
|
|
||
|
|
result = await probe_bridge(mock_bridge)
|
||
|
|
assert result["imessage_connected"] is False
|
||
|
|
|
||
|
|
|
||
|
|
class TestSentMessageCache:
|
||
|
|
def test_cache_record_and_get(self):
|
||
|
|
from yuxi.channels.adapters.imessage.sent_cache import SentMessageCache
|
||
|
|
|
||
|
|
cache = SentMessageCache()
|
||
|
|
cache.record("msg_001", "Hello world", "chat_001")
|
||
|
|
entry = cache.get("msg_001")
|
||
|
|
assert entry is not None
|
||
|
|
assert entry["message_id"] == "msg_001"
|
||
|
|
assert entry["content"] == "Hello world"
|
||
|
|
assert entry["chat_guid"] == "chat_001"
|
||
|
|
|
||
|
|
def test_cache_get_content(self):
|
||
|
|
from yuxi.channels.adapters.imessage.sent_cache import SentMessageCache
|
||
|
|
|
||
|
|
cache = SentMessageCache()
|
||
|
|
cache.record("msg_001", "Hello world", "chat_001")
|
||
|
|
assert cache.get_content("msg_001") == "Hello world"
|
||
|
|
|
||
|
|
def test_cache_get_missing(self):
|
||
|
|
from yuxi.channels.adapters.imessage.sent_cache import SentMessageCache
|
||
|
|
|
||
|
|
cache = SentMessageCache()
|
||
|
|
assert cache.get("nonexistent") is None
|
||
|
|
assert cache.get_content("nonexistent") is None
|
||
|
|
|
||
|
|
def test_cache_list_recent(self):
|
||
|
|
from yuxi.channels.adapters.imessage.sent_cache import SentMessageCache
|
||
|
|
|
||
|
|
cache = SentMessageCache()
|
||
|
|
for i in range(10):
|
||
|
|
cache.record(f"msg_{i:03d}", f"Message {i}", "chat_001")
|
||
|
|
recent = cache.list_recent(5)
|
||
|
|
assert len(recent) == 5
|
||
|
|
recent_all = cache.list_recent(100)
|
||
|
|
assert len(recent_all) == 10
|
||
|
|
|
||
|
|
def test_cache_content_truncation(self):
|
||
|
|
from yuxi.channels.adapters.imessage.sent_cache import SentMessageCache
|
||
|
|
|
||
|
|
cache = SentMessageCache()
|
||
|
|
long_text = "X" * 1000
|
||
|
|
cache.record("msg_001", long_text, "chat_001")
|
||
|
|
assert len(cache.get_content("msg_001")) <= 500
|
||
|
|
|
||
|
|
|
||
|
|
class TestStickerCache:
|
||
|
|
def test_add_and_get(self, tmp_path):
|
||
|
|
from yuxi.channels.adapters.imessage.sticker_cache import StickerCache
|
||
|
|
|
||
|
|
cache = StickerCache(cache_dir=str(tmp_path))
|
||
|
|
cache.add("sticker_001", "https://example.com/sticker.png", {"type": "image"})
|
||
|
|
entry = cache.get("sticker_001")
|
||
|
|
assert entry is not None
|
||
|
|
assert entry["url"] == "https://example.com/sticker.png"
|
||
|
|
assert entry["metadata"]["type"] == "image"
|
||
|
|
|
||
|
|
def test_get_url(self, tmp_path):
|
||
|
|
from yuxi.channels.adapters.imessage.sticker_cache import StickerCache
|
||
|
|
|
||
|
|
cache = StickerCache(cache_dir=str(tmp_path))
|
||
|
|
cache.add("sticker_001", "https://example.com/sticker.png")
|
||
|
|
assert cache.get_url("sticker_001") == "https://example.com/sticker.png"
|
||
|
|
|
||
|
|
def test_get_missing(self, tmp_path):
|
||
|
|
from yuxi.channels.adapters.imessage.sticker_cache import StickerCache
|
||
|
|
|
||
|
|
cache = StickerCache(cache_dir=str(tmp_path))
|
||
|
|
assert cache.get("nonexistent") is None
|
||
|
|
assert cache.get_url("nonexistent") is None
|
||
|
|
|
||
|
|
def test_clear(self, tmp_path):
|
||
|
|
from yuxi.channels.adapters.imessage.sticker_cache import StickerCache
|
||
|
|
|
||
|
|
cache = StickerCache(cache_dir=str(tmp_path))
|
||
|
|
cache.add("sticker_001", "https://example.com/1.png")
|
||
|
|
cache.add("sticker_002", "https://example.com/2.png")
|
||
|
|
cache.clear()
|
||
|
|
assert cache.get("sticker_001") is None
|
||
|
|
assert cache.get("sticker_002") is None
|
||
|
|
|
||
|
|
def test_max_entries_eviction(self, tmp_path):
|
||
|
|
from yuxi.channels.adapters.imessage.sticker_cache import StickerCache
|
||
|
|
|
||
|
|
cache = StickerCache(cache_dir=str(tmp_path), max_entries=3)
|
||
|
|
for i in range(5):
|
||
|
|
cache.add(f"sticker_{i}", f"https://example.com/{i}.png")
|
||
|
|
assert len(cache._index) <= 3
|