onmcp/scripts/test_cpp_config_loading.sh

81 lines
4.7 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
"$ROOT/scripts/build_cpp.sh" >/dev/null
mkdir -p "$ROOT/reports"
AMAP_PORT=19781
CAL_PORT=19782
MCPD_PORT=19780
CONFIG="$ROOT/reports/mcpd.generated.config.json"
cat > "$CONFIG" <<JSON
{
"server": {"listen_host": "127.0.0.1", "listen_port": $MCPD_PORT, "rpc_path": "/rpc"},
"services": [
{"service_id": "amap", "url": "http://127.0.0.1:$AMAP_PORT/rpc", "tool_prefix": "amap.", "enabled": true},
{"service_id": "calendar", "url": "http://127.0.0.1:$CAL_PORT/rpc", "tool_prefix": "calendar.", "enabled": true}
],
"agents": [
{"token": "demo-token", "agent_id": "trip_planner", "allow_services": ["amap", "calendar"], "allow_tools": ["amap.maps_weather", "amap.maps_text_search", "amap.maps_direction_transit_integrated_by_address", "amap.hotel_search", "amap.restaurant_search", "calendar.create_event", "calendar.list_events", "calendar.query_free_time"], "admin": true},
{"token": "weather-token", "agent_id": "weather_agent", "allow_services": ["amap"], "allow_tools": ["amap.maps_weather"], "admin": false},
{"token": "calendar-token", "agent_id": "calendar_agent", "allow_services": ["calendar"], "allow_tools": ["calendar.create_event", "calendar.list_events", "calendar.query_free_time"], "admin": false}
],
"cache": {"max_result_cache_entries": 2, "default_ttl_ms": 60000, "cache_key_hash": "fnv64"},
"security": {"require_token": true, "max_payload_bytes": 262144, "enable_nonce_replay_guard": true}
}
JSON
"$ROOT/build/cpp/mock_mcp_server" --port "$AMAP_PORT" >"$ROOT/reports/config_amap.log" 2>&1 &
AMAP_PID=$!
"$ROOT/build/cpp/mock_calendar_server" --port "$CAL_PORT" >"$ROOT/reports/config_calendar.log" 2>&1 &
CAL_PID=$!
for _ in $(seq 1 50); do
if curl -fsS -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' "http://127.0.0.1:$AMAP_PORT/rpc" >/dev/null 2>&1 \
&& curl -fsS -H 'Content-Type: application/json' --data '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' "http://127.0.0.1:$CAL_PORT/rpc" >/dev/null 2>&1; then
break
fi
sleep 0.1
done
"$ROOT/build/cpp/mcpd" --config "$CONFIG" >"$ROOT/reports/config_mcpd.log" 2>&1 &
MCPD_PID=$!
cleanup() {
kill "$MCPD_PID" "$AMAP_PID" "$CAL_PID" >/dev/null 2>&1 || true
wait "$MCPD_PID" "$AMAP_PID" "$CAL_PID" 2>/dev/null || true
}
trap cleanup EXIT
for _ in $(seq 1 50); do
if curl -fsS "http://127.0.0.1:$MCPD_PORT/healthz" >/dev/null 2>&1; then break; fi
sleep 0.1
done
ROOT="$ROOT" MCPD_PORT="$MCPD_PORT" python3 - <<'PY'
import json, os, sys, urllib.error, urllib.request
root=os.environ['ROOT']; port=os.environ['MCPD_PORT']; endpoint=f'http://127.0.0.1:{port}/rpc'; stats_endpoint=f'http://127.0.0.1:{port}/stats'; seq=0; checks=[]
def rpc(method, params=None, token='demo-token'):
global seq; seq+=1
payload={'jsonrpc':'2.0','id':seq,'method':method,'params':params or {}}
req=urllib.request.Request(endpoint, data=json.dumps(payload, ensure_ascii=False).encode(), headers={'Content-Type':'application/json','X-Agent-Token':token}, method='POST')
try:
with urllib.request.urlopen(req, timeout=5) as resp: return resp.status, json.loads(resp.read().decode())
except urllib.error.HTTPError as e:
try: body=json.loads(e.read().decode())
except Exception: body={}
return e.code, body
def check(name, cond, detail):
checks.append({'name':name,'pass':bool(cond),'detail':detail}); print(('[PASS]' if cond else '[FAIL]'), name, detail)
code, body = rpc('tools/list', {'compact': True})
names=[t.get('name','') for t in body.get('result',{}).get('tools',[])]
check('config loads two services', code==200 and any(n.startswith('amap.') for n in names) and any(n.startswith('calendar.') for n in names), names)
code2, body2 = rpc('tools/call', {'name':'calendar.list_events','arguments':{'date':'2026-05-14','limit':1}})
check('config routes calendar', code2==200 and body2.get('service_id')=='calendar', body2)
code3, body3 = rpc('tools/call', {'name':'calendar.list_events','arguments':{'date':'2026-05-14','limit':1}})
check('config cache policy works', code3==200 and body3.get('cached') is True, body3)
try:
with urllib.request.urlopen(stats_endpoint, timeout=5) as resp: st=json.loads(resp.read().decode())['stats']
except Exception as e:
st={'error':str(e)}
check('config max cache entries applied', st.get('result_cache_max_entries') == 2, st)
summary={'test':'config loading','pass':sum(1 for c in checks if c['pass']),'fail':sum(1 for c in checks if not c['pass']),'checks':checks,'stats':st}
out=os.path.join(root,'reports','config_loading_summary.json')
open(out,'w',encoding='utf-8').write(json.dumps(summary, ensure_ascii=False, indent=2))
print('summary:', out)
if summary['fail']: sys.exit(1)
PY