Files
aios/tests/v2r1/test_message_ledger_append.py
T

121 lines
6.0 KiB
Python

"""Executable completeness contract for the exact-ID message ledger."""
from __future__ import annotations
from concurrent.futures import ThreadPoolExecutor
from dataclasses import replace
from pathlib import Path
import sqlite3
import pytest
from aios_v2r1.message_ledger import MessageLedger
from aios_v2r1.tenant_context import CanonicalMessage, ConflictError, ScopeError
def message(**changes: object) -> CanonicalMessage:
value = CanonicalMessage(
tenant_id="tenant-a", cell_id="cell-a", principal_id="user-a",
principal_type="authenticated_user", origin_type="channel_user",
channel="weixin", channel_account_id="account-a", peer_id="peer-a",
conversation_id="conversation-a", session_id="session-a", task_id=None,
event_id="event-a", message_id="message-a", reply_to_message_id=None,
direction="inbound", command_capable=True,
occurred_at="2026-07-13T00:00:00+00:00",
received_at="2026-07-13T00:00:01+00:00", body="hello",
quoted_body=None, adapter_name="weixin", adapter_version="v2")
return replace(value, **changes)
@pytest.fixture
def ledger(tmp_path: Path) -> MessageLedger:
return MessageLedger(tmp_path / "ledger.sqlite3")
def test_append_writes_directly_without_using_remember(ledger: MessageLedger) -> None:
ledger.remember = lambda _: (_ for _ in ()).throw(AssertionError("remember called")) # type: ignore[method-assign]
assert ledger.append(message()).message_id == "message-a"
assert ledger.count() == 1
def test_append_rejects_same_message_id_with_different_content(ledger: MessageLedger) -> None:
ledger.append(message(body="first"))
with pytest.raises(ConflictError):
ledger.append(message(event_id="event-b", body="second"))
assert ledger.count() == 1
def test_append_is_idempotent_when_only_event_id_changes(ledger: MessageLedger) -> None:
stored = ledger.append(message(event_id="event-a", body="same body"))
replay = ledger.append(message(event_id="event-b", body="same body"))
assert replay == stored
assert replay.event_id == "event-a"
assert ledger.count() == 1
@pytest.mark.parametrize("candidate", ["message", "message-a-extra", "MESSAGE-A"])
def test_quote_lookup_has_no_prefix_similarity_or_case_fallback(
ledger: MessageLedger, candidate: str
) -> None:
ledger.append(message(message_id="message-a"))
with pytest.raises(ScopeError, match="quoted_text_unavailable"):
ledger.resolve_quote(message(event_id="reply-event", message_id="reply-message",
reply_to_message_id=candidate))
def test_explicit_quoted_body_never_falls_back_to_storage(ledger: MessageLedger) -> None:
assert ledger.resolve_quote(message(quoted_body="exact transport quote")) == "exact transport quote"
assert ledger.count() == 0
@pytest.mark.parametrize("scope_change", [{"tenant_id": "tenant-b"}, {"cell_id": "cell-b"}])
def test_quote_lookup_is_tenant_and_cell_isolated(
ledger: MessageLedger, scope_change: dict[str, str]
) -> None:
ledger.append(message())
with pytest.raises(ScopeError, match="quoted_text_unavailable"):
ledger.resolve_quote(message(**scope_change, event_id="reply-event",
message_id="reply-message",
reply_to_message_id="message-a"))
def test_same_id_across_directions_is_ambiguous_not_guessed(ledger: MessageLedger) -> None:
ledger.append(message(direction="inbound", body="in"))
ledger.append(message(direction="outbound", event_id="event-b", body="out"))
with pytest.raises(ConflictError, match="ambiguous"):
ledger.resolve_quote(message(event_id="event-c", message_id="message-c",
reply_to_message_id="message-a"))
def test_expired_record_is_not_resolved(ledger: MessageLedger) -> None:
ledger.append(message())
with sqlite3.connect(ledger.database) as db:
db.execute("UPDATE message_ledger SET expires_at='2000-01-01T00:00:00+00:00'")
with pytest.raises(ScopeError, match="quoted_text_unavailable"):
ledger.resolve_quote(message(event_id="event-b", message_id="message-b",
reply_to_message_id="message-a"))
def test_purge_removes_only_expired_records(ledger: MessageLedger) -> None:
ledger.append(message())
ledger.append(message(event_id="event-b", message_id="message-b"))
with sqlite3.connect(ledger.database) as db:
db.execute("UPDATE message_ledger SET expires_at='2000-01-01T00:00:00+00:00' "
"WHERE message_id='message-a'")
assert ledger.purge_expired() == 1
assert ledger.count() == 1
def test_restart_preserves_exact_resolution(tmp_path: Path) -> None:
database = tmp_path / "ledger.sqlite3"
MessageLedger(database).append(message())
reopened = MessageLedger(database)
assert reopened.resolve_quote(message(event_id="event-b", message_id="message-b",
reply_to_message_id="message-a")) == "hello"
def test_concurrent_identical_append_is_one_record(ledger: MessageLedger) -> None:
with ThreadPoolExecutor(max_workers=16) as executor:
records = list(executor.map(lambda _: ledger.append(message()), range(16)))
assert ledger.count() == 1
assert {record.message_id for record in records} == {"message-a"}
def test_concurrent_distinct_appends_are_not_lost(ledger: MessageLedger) -> None:
def append(index: int) -> None:
ledger.append(message(event_id=f"event-{index}", message_id=f"message-{index}"))
with ThreadPoolExecutor(max_workers=16) as executor:
list(executor.map(append, range(16)))
assert ledger.count() == 16
def test_sqlite_failures_are_sanitized(ledger: MessageLedger) -> None:
ledger.database.write_bytes(b"not-a-sqlite-database")
with pytest.raises(ConflictError, match="ledger storage unavailable") as raised:
ledger.count()
assert not isinstance(raised.value, sqlite3.Error)
assert "sqlite" not in str(raised.value).lower()
assert raised.value.__cause__ is None
assert raised.value.__context__ is None