CI / checks (push) Skipped
CI / checks (pull_request) Successful in 1m47s
Transport.post(text, thread=...) returns the event ID, which can root a thread; a threaded post carries m.thread with the reply fallback for clients without threads. Inbound messages carry their event ID and thread root: a message in a thread gives its root, a plain reply joins the thread of the message it replies to when known, and the quoted lines of a rich reply are no longer part of the text. The in-memory transport plays threads for tests. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
76 lines
2.8 KiB
Python
76 lines
2.8 KiB
Python
"""Live smoke test against the real homeserver, bound strictly to the
|
|
dedicated test room that nisse-test.yaml names (never the production room)."""
|
|
|
|
import uuid
|
|
|
|
import pytest
|
|
|
|
from nisse_dev.config import AgentConfig
|
|
from nisse_dev.matrix import MatrixConfig, MatrixTransport
|
|
|
|
pytestmark = pytest.mark.integration
|
|
|
|
|
|
def _assert_testing_identity(transport: MatrixTransport, config: MatrixConfig) -> None:
|
|
"""Two invariants that only a live homeserver can check.
|
|
|
|
The configured user id must be the token's real owner, because the
|
|
transport filters its own messages by comparing sender to that value —
|
|
a mismatch would make the bot read its own posts as operator input.
|
|
And tests must run as a testing identity, so a stray live run can never
|
|
act as the production agent.
|
|
"""
|
|
whoami = transport._http.get("/account/whoami")
|
|
whoami.raise_for_status()
|
|
actual = whoami.json()["user_id"]
|
|
assert actual == config.user_id, (
|
|
f"matrix.user_id is {config.user_id} but the token belongs to "
|
|
f"{actual}; the self-message filter would not match"
|
|
)
|
|
assert "testing" in actual, (
|
|
f"live tests must run as a testing identity, not {actual}"
|
|
)
|
|
|
|
|
|
def test_send_lands_in_test_room(live_config: AgentConfig) -> None:
|
|
config = live_config.matrix
|
|
marker = f"transport smoke test {uuid.uuid4().hex}"
|
|
transport = MatrixTransport(config)
|
|
try:
|
|
_assert_testing_identity(transport, config)
|
|
transport.send_message(marker)
|
|
response = transport._http.get(
|
|
f"/rooms/{config.room_id}/messages",
|
|
params={"dir": "b", "limit": "10"},
|
|
)
|
|
response.raise_for_status()
|
|
bodies = [
|
|
event.get("content", {}).get("body")
|
|
for event in response.json().get("chunk", [])
|
|
]
|
|
assert marker in bodies
|
|
finally:
|
|
transport.close()
|
|
|
|
|
|
def test_a_threaded_post_is_kept_in_its_thread(live_config: AgentConfig) -> None:
|
|
"""The homeserver accepts the thread relation and lists the reply under
|
|
its root (L5: a work item's conversation is a thread)."""
|
|
config = live_config.matrix
|
|
marker = uuid.uuid4().hex
|
|
transport = MatrixTransport(config)
|
|
try:
|
|
_assert_testing_identity(transport, config)
|
|
root = transport.post(f"thread smoke test root {marker}")
|
|
reply = transport.post(f"thread smoke test reply {marker}", thread=root)
|
|
# The relations API is v1, not the transport's v3.
|
|
response = transport._http.get(
|
|
f"{config.homeserver}/_matrix/client/v1/rooms/{config.room_id}"
|
|
f"/relations/{root}/m.thread"
|
|
)
|
|
response.raise_for_status()
|
|
in_thread = [e["event_id"] for e in response.json().get("chunk", [])]
|
|
assert reply in in_thread
|
|
finally:
|
|
transport.close()
|