Files
openworker/tests/test_slack_status.py
T
Rohit C PrasadandDevika 2b45018ffa OpenWorker: initial import
Imported from andrewyng/aisuite@1b4bbf303e
(contents of its platform/ directory, hoisted to the repo root).
Development history prior to this commit lives in that repository.

Co-authored-by: Devika <devikaverma11@gmail.com>
2026-07-21 11:09:41 -07:00

228 lines
7.1 KiB
Python

"""Slack connection health (M3.6 Step 2) — three honest layers: the
desktop↔relay socket, the cloud sign-in, and per-workspace bot tokens.
The endpoint aggregates what the adapter observed; it never invents a
Slack↔cloud claim (that leg is invisible from the desktop).
"""
from __future__ import annotations
import asyncio
from types import SimpleNamespace
import pytest
from fastapi.testclient import TestClient
from coworker.connectors.base import SendResult
from coworker.connectors.relay_client import SlackRelayAdapter
from coworker.server import SessionManager, create_app
@pytest.fixture
def client(tmp_path, monkeypatch):
monkeypatch.setenv("COWORKER_STATE_DIR", str(tmp_path / "state"))
manager = SessionManager(workspace=tmp_path)
app = create_app(manager)
with TestClient(app) as c:
c.manager = manager
yield c
class _StubAdapter:
"""Quacks like SlackRelayAdapter.status() without a socket."""
def __init__(self, state="live", teams=None):
self._state = state
self._teams = teams or {}
def status(self):
return {
"state": self._state,
"reconnects": 2,
"last_event_at": 1751970000.0,
"last_error": "" if self._state == "live" else "boom",
"teams": self._teams,
}
async def _noop_stop():
return None
def _gateway_with(adapter) -> SimpleNamespace:
# `stop` because app shutdown tears the gateway down.
return SimpleNamespace(
_adapters={"slack": adapter} if adapter else {}, stop=_noop_stop
)
# --- endpoint aggregation ----------------------------------------------------
def test_status_live_relay_with_teams(client):
client.manager.secrets.put("slack:default", {"mode": "relay", "enabled": True})
client.manager.secrets.put(
"cloud:auth", {"access_token": "jwt", "account": "rohit@x.com"}
)
client.manager.gateway = _gateway_with(
_StubAdapter("live", {"T1": {"token_ok": True}, "T2": {"token_ok": False}})
)
data = client.get("/v1/connectors/slack/status").json()
assert data["mode"] == "relay"
assert data["signed_in"] is True
assert data["relay"]["state"] == "live"
assert data["relay"]["last_event_at"] == 1751970000.0
assert data["teams"]["T1"]["token_ok"] is True
assert data["teams"]["T2"]["token_ok"] is False
assert "teams" not in data["relay"] # folded up, not duplicated
def test_status_reconnecting_carries_last_error(client):
client.manager.secrets.put("slack:default", {"mode": "relay", "enabled": True})
client.manager.gateway = _gateway_with(_StubAdapter("reconnecting"))
data = client.get("/v1/connectors/slack/status").json()
assert data["relay"]["state"] == "reconnecting"
assert data["relay"]["last_error"] == "boom"
assert data["signed_in"] is False
def test_status_offline_when_no_adapter(client):
# Relay mode configured but the gateway has no slack adapter (e.g. signed
# out at startup so it never built) → offline, not a crash.
client.manager.secrets.put("slack:default", {"mode": "relay", "enabled": True})
client.manager.gateway = _gateway_with(None)
data = client.get("/v1/connectors/slack/status").json()
assert data["relay"]["state"] == "offline"
assert data["teams"] == {}
def test_status_manual_socket_mode_has_no_relay_layer(client):
# Socket-Mode adapters expose no status(); the endpoint still answers.
client.manager.secrets.put("slack:default", {"bot_token": "xoxb", "enabled": True})
client.manager.gateway = None
data = client.get("/v1/connectors/slack/status").json()
assert data["mode"] == "" # not relay
assert data["relay"]["state"] == "offline"
# --- adapter state tracking --------------------------------------------------
def _adapter(**kw) -> SlackRelayAdapter:
return SlackRelayAdapter(
"wss://relay.test/ws",
token_provider=lambda: "jwt",
teams={"T1": {"bot_token": "xoxb-1", "bot_user_id": "UBOT"}},
reconnect_delay=0.0,
**kw,
)
def test_adapter_status_offline_before_connect():
st = _adapter().status()
assert st["state"] == "offline"
assert st["last_event_at"] is None
assert st["teams"] == {"T1": {"token_ok": True}} # unknown ⇒ assumed good
async def test_adapter_stamps_last_event_and_reports_live():
class _Blocking:
async def open(self):
pass
async def recv(self):
await asyncio.Event().wait()
async def close(self):
pass
adapter = _adapter(transport_factory=lambda: _Blocking())
assert await adapter.connect() is True
try:
assert adapter.status()["state"] == "live"
assert adapter.status()["last_event_at"] is None
await adapter._dispatch_slack_event(
"T1",
{
"type": "app_mention",
"user": "U1",
"channel": "C1",
"text": "x",
"ts": "1",
},
)
assert adapter.status()["last_event_at"] is not None
finally:
await adapter.disconnect()
assert adapter.status()["state"] == "offline"
async def test_adapter_connect_failure_records_last_error():
class _Broken:
async def open(self):
raise OSError("relay unreachable")
async def recv(self):
return None
async def close(self):
pass
adapter = _adapter(transport_factory=lambda: _Broken())
assert await adapter.connect() is False
assert "relay unreachable" in adapter.status()["last_error"]
async def test_send_error_marks_token_dead_and_recovers(monkeypatch):
from coworker.connectors import relay_client
results = iter(
[SendResult(False, error="invalid_auth"), SendResult(True, message_id="ts")]
)
monkeypatch.setattr(relay_client, "_send_slack", lambda *a, **k: next(results))
adapter = _adapter()
await adapter.send("T1/C1", "hi")
assert adapter.status()["teams"]["T1"]["token_ok"] is False
await adapter.send("T1/C1", "hi again")
assert adapter.status()["teams"]["T1"]["token_ok"] is True
async def test_non_token_send_error_does_not_flag_token(monkeypatch):
from coworker.connectors import relay_client
monkeypatch.setattr(
relay_client,
"_send_slack",
lambda *a, **k: SendResult(False, error="channel_not_found"),
)
adapter = _adapter()
await adapter.send("T1/C1", "hi")
assert adapter.status()["teams"]["T1"]["token_ok"] is True
async def test_slack_get_token_error_marks_team(monkeypatch):
adapter = _adapter()
class _Resp:
def json(self):
return {"ok": False, "error": "account_inactive"}
class _Http:
def __init__(self, *a, **k):
pass
async def __aenter__(self):
return self
async def __aexit__(self, *a):
return False
async def get(self, *a, **k):
return _Resp()
import httpx
monkeypatch.setattr(httpx, "AsyncClient", _Http)
assert await adapter._slack_get("T1", "users.info", {"user": "U1"}) is None
assert adapter.status()["teams"]["T1"]["token_ok"] is False