77 lines
3.0 KiB
Python
77 lines
3.0 KiB
Python
"""Unit tests for /handoff platform aliasing over relay (Phase 1 parity).
|
|
|
|
Symptom fixed: on a relay-fronted gateway, ``/handoff discord`` was rejected
|
|
in TWO places even though "discord" is deliverable through the relay adapter:
|
|
|
|
1. The CLI pre-check (``cli_commands_mixin._handle_handoff_command``) looked
|
|
up ``gw_config.platforms.get(DISCORD)`` — only a RELAY entry exists.
|
|
2. The gateway watcher (``run.py _process_handoff``) did a literal
|
|
``adapters.get(discord)`` — the adapter is registered under RELAY.
|
|
|
|
Both now resolve fronted platforms through the same alias-aware machinery the
|
|
delivery router uses (``resolve_delivery_transport`` — native adapter wins;
|
|
relay eligible only when its authenticated transport advertises the logical
|
|
platform). These tests cover the resolver semantics the watcher depends on,
|
|
plus the CLI pre-check's env-derived fronted set.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from gateway.config import GatewayConfig, Platform, PlatformConfig
|
|
from gateway.delivery import resolve_delivery_transport
|
|
|
|
|
|
class _RelayStub:
|
|
"""Minimal relay adapter double advertising a fronted-platform set."""
|
|
|
|
def __init__(self, fronted):
|
|
self._fronted = set(fronted)
|
|
self.sent = []
|
|
|
|
def fronts_platform(self, platform):
|
|
value = getattr(platform, "value", platform)
|
|
return str(value) in self._fronted
|
|
|
|
async def send_for_platform(self, logical_platform, chat_id, content, reply_to=None, metadata=None):
|
|
self.sent.append((getattr(logical_platform, "value", logical_platform), chat_id, content, metadata))
|
|
return type("R", (), {"success": True, "message_id": "m-1", "error": None})()
|
|
|
|
async def send(self, chat_id, content, reply_to=None, metadata=None): # pragma: no cover
|
|
raise AssertionError("relay transport must use send_for_platform, not send")
|
|
|
|
|
|
def _config_with(platforms):
|
|
cfg = GatewayConfig()
|
|
cfg.platforms = platforms
|
|
return cfg
|
|
|
|
|
|
class TestHandoffRelayAliasing:
|
|
def test_fronted_platform_resolves_to_relay_adapter(self):
|
|
"""The watcher's exact miss: adapters holds only RELAY, target is discord."""
|
|
relay = _RelayStub({"discord"})
|
|
cfg = _config_with({Platform.RELAY: PlatformConfig(enabled=True)})
|
|
transport = resolve_delivery_transport(
|
|
Platform.DISCORD, cfg, {Platform.RELAY: relay}
|
|
)
|
|
assert transport is not None
|
|
assert transport.adapter is relay
|
|
assert transport.is_relay is True
|
|
|
|
|
|
class TestCliHandoffFrontedSet:
|
|
"""The CLI pre-check derives the fronted set from deploy env (no live adapter)."""
|
|
|
|
def test_fronted_set_from_env(self, monkeypatch):
|
|
monkeypatch.setenv("GATEWAY_RELAY_PLATFORMS", "discord,telegram")
|
|
monkeypatch.delenv("GATEWAY_RELAY_BOT_IDS", raising=False)
|
|
from gateway.relay import relay_platform_identities
|
|
|
|
fronted = {p for p, _ in relay_platform_identities()}
|
|
assert "discord" in fronted
|
|
assert "telegram" in fronted
|
|
assert "slack" not in fronted
|
|
|