from __future__ import annotations import base64 from fastapi.testclient import TestClient from external_connector.app import create_app from external_connector.providers.fake import FakeProvider from external_connector.state import SidecarStateStore def test_fake_provider_lists_weixin_and_feishu(tmp_path) -> None: provider = FakeProvider(SidecarStateStore(tmp_path / "state.json")) connectors = provider.connectors() assert [item["kind"] for item in connectors] == ["weixin", "feishu"] assert connectors[0]["authType"] == "qr" def test_fake_provider_session_flow(tmp_path) -> None: provider = FakeProvider(SidecarStateStore(tmp_path / "state.json")) session = provider.start_session( { "kind": "weixin", "connectionId": "conn_1", "channelId": "weixin-main", "displayName": "Weixin Main", "callbackBaseUrl": "http://beaver:8080", "options": {}, } ) loaded = provider.get_session(session["sessionId"]) assert session["status"] == "qr_ready" prefix = "data:image/svg+xml;base64," assert session["qrImage"].startswith(prefix) svg = base64.b64decode(session["qrImage"][len(prefix) :]).decode("utf-8") assert svg.startswith(" None: provider = FakeProvider(SidecarStateStore(tmp_path / "state.json")) payload = { "requestId": "out_1", "connectionId": "conn_1", "channelId": "weixin-main", "kind": "weixin", "target": {"peerId": "peer-1", "peerType": "dm", "threadId": None}, "content": "hello", "metadata": {}, } first = provider.send(payload) second = provider.send(payload) assert first == second assert first["ok"] is True def test_sidecar_http_api_requires_bearer_token(tmp_path) -> None: app = create_app(provider=FakeProvider(SidecarStateStore(tmp_path / "state.json")), api_token="sidecar-token") with TestClient(app) as client: response = client.get("/connectors") assert response.status_code == 401 def test_sidecar_http_api_session_and_send(tmp_path) -> None: app = create_app(provider=FakeProvider(SidecarStateStore(tmp_path / "state.json")), api_token="sidecar-token") headers = {"Authorization": "Bearer sidecar-token"} with TestClient(app) as client: connectors = client.get("/connectors", headers=headers) session = client.post( "/connector-sessions", headers=headers, json={ "kind": "weixin", "connectionId": "conn_1", "channelId": "weixin-main", "displayName": "Weixin Main", "callbackBaseUrl": "http://beaver:8080", "options": {}, }, ) session_id = session.json()["sessionId"] loaded = client.get(f"/connector-sessions/{session_id}", headers=headers) sent = client.post( "/send", headers=headers, json={ "requestId": "out_1", "connectionId": "conn_1", "channelId": "weixin-main", "kind": "weixin", "target": {"peerId": "peer-1", "peerType": "dm", "threadId": None}, "content": "hello", "metadata": {}, }, ) assert connectors.status_code == 200 assert session.status_code == 200 assert loaded.json()["sessionId"] == session_id assert sent.json()["ok"] is True def test_sidecar_http_api_returns_conflict_for_processing_send(tmp_path) -> None: store = SidecarStateStore(tmp_path / "state.json", send_processing_ttl_seconds=60) store.begin_send(connection_id="conn_1", request_id="out_1") app = create_app(provider=FakeProvider(store), api_token="sidecar-token") headers = {"Authorization": "Bearer sidecar-token"} with TestClient(app) as client: response = client.post( "/send", headers=headers, json={ "requestId": "out_1", "connectionId": "conn_1", "channelId": "weixin-main", "kind": "weixin", "target": {"peerId": "peer-1", "peerType": "dm", "threadId": None}, "content": "hello", "metadata": {}, }, ) assert response.status_code == 409 assert response.json()["retryAfterSeconds"] == 5