feat: implement channel runtime connectors
This commit is contained in:
135
external-connector/tests/test_sidecar_api.py
Normal file
135
external-connector/tests/test_sidecar_api.py
Normal file
@ -0,0 +1,135 @@
|
||||
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("<svg")
|
||||
assert "FAKE QR" in svg
|
||||
assert loaded["sessionId"] == session["sessionId"]
|
||||
|
||||
|
||||
def test_fake_provider_send_returns_idempotent_result(tmp_path) -> 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
|
||||
Reference in New Issue
Block a user