后端: - 拆分出 agent_service, runtime_service, trading_service, news_service - Gateway 模块化拆分 (gateway_*.py) - 添加 domains/ 领域层 - 新增 control_client, runtime_client - 更新 start-dev.sh 支持 split 服务模式 前端: - 完善 API 服务层 (newsApi, tradingApi) - 更新 vite.config.js - Explain 组件优化 测试: - 添加多个服务 app 测试 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
108 lines
3.1 KiB
Python
108 lines
3.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Tests for split-aware shared service clients."""
|
|
|
|
import pytest
|
|
|
|
from shared.client.control_client import ControlPlaneClient
|
|
from shared.client.runtime_client import RuntimeServiceClient
|
|
|
|
|
|
class _DummyResponse:
|
|
def __init__(self, payload):
|
|
self._payload = payload
|
|
|
|
def raise_for_status(self):
|
|
return None
|
|
|
|
def json(self):
|
|
return self._payload
|
|
|
|
|
|
class _DummyAsyncClient:
|
|
def __init__(self):
|
|
self.calls = []
|
|
|
|
async def get(self, path, params=None):
|
|
self.calls.append(("get", path, params))
|
|
return _DummyResponse({"path": path, "params": params})
|
|
|
|
async def post(self, path, json=None):
|
|
self.calls.append(("post", path, json))
|
|
return _DummyResponse({"path": path, "json": json})
|
|
|
|
async def put(self, path, json=None):
|
|
self.calls.append(("put", path, json))
|
|
return _DummyResponse({"path": path, "json": json})
|
|
|
|
async def aclose(self):
|
|
return None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_control_plane_client_hits_current_workspace_and_guard_routes():
|
|
client = ControlPlaneClient()
|
|
client._client = _DummyAsyncClient()
|
|
|
|
await client.list_workspaces()
|
|
await client.get_workspace("demo")
|
|
await client.list_agents("demo")
|
|
await client.get_agent("demo", "risk_manager")
|
|
await client.fetch_pending_approvals()
|
|
await client.approve_pending_approval("ap-1")
|
|
await client.deny_pending_approval("ap-2", reason="nope")
|
|
|
|
assert client._client.calls == [
|
|
("get", "/workspaces", None),
|
|
("get", "/workspaces/demo", None),
|
|
("get", "/workspaces/demo/agents", None),
|
|
("get", "/workspaces/demo/agents/risk_manager", None),
|
|
("get", "/guard/pending", None),
|
|
(
|
|
"post",
|
|
"/guard/approve",
|
|
{
|
|
"approval_id": "ap-1",
|
|
"one_time": True,
|
|
"expires_in_minutes": 30,
|
|
},
|
|
),
|
|
(
|
|
"post",
|
|
"/guard/deny",
|
|
{
|
|
"approval_id": "ap-2",
|
|
"reason": "nope",
|
|
},
|
|
),
|
|
]
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_runtime_service_client_hits_current_runtime_routes():
|
|
client = RuntimeServiceClient()
|
|
client._client = _DummyAsyncClient()
|
|
|
|
await client.fetch_context()
|
|
await client.fetch_agents()
|
|
await client.fetch_events()
|
|
await client.fetch_gateway_port()
|
|
await client.start_runtime({"tickers": ["AAPL"]})
|
|
await client.stop_runtime(force=True)
|
|
await client.restart_runtime({"tickers": ["MSFT"]})
|
|
await client.fetch_current_runtime()
|
|
await client.get_runtime_config()
|
|
await client.update_runtime_config({"schedule_mode": "intraday"})
|
|
|
|
assert client._client.calls == [
|
|
("get", "/context", None),
|
|
("get", "/agents", None),
|
|
("get", "/events", None),
|
|
("get", "/gateway/port", None),
|
|
("post", "/start", {"tickers": ["AAPL"]}),
|
|
("post", "/stop?force=true", None),
|
|
("post", "/restart", {"tickers": ["MSFT"]}),
|
|
("get", "/current", None),
|
|
("get", "/config", None),
|
|
("put", "/config", {"schedule_mode": "intraday"}),
|
|
]
|