test(V2): add /mcp unified-interface smoke script
tests/smoke/run_unified.sh exercises the common interface against a live server + real upstreams (Deribit/Hyperliquid public endpoints): get_instruments (single + fan-out, asserting fees/history_start), get_historical for both venues, and a 422 for an unsupported exchange. Refresh tests/smoke/README.md (drop stale Bybit/Alpaca references). Verified green end-to-end. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+18
-17
@@ -1,25 +1,26 @@
|
|||||||
# Smoke locale Cerbero_mcp
|
# Smoke locale Cerbero_mcp
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# da repo root Cerbero_mcp/
|
# da repo root, con il server attivo (docker compose up -d)
|
||||||
docker compose up -d
|
PORT=9000 TESTNET_TOKEN="$TESTNET_TOKEN" bash tests/smoke/run.sh
|
||||||
bash tests/smoke/run.sh
|
MAINNET_TOKEN="$MAINNET_TOKEN" bash tests/smoke/run_unified.sh
|
||||||
docker compose down
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Il file `run.sh` verifica:
|
## `run.sh` — endpoint pubblici + un tool per-exchange
|
||||||
- `/health` di tutti i 6 MCP (atteso `200`)
|
Verifica `/health`, `/apidocs`, `/openapi.json` (schema bearer) e, se
|
||||||
- `environment_info` dei 4 exchange (atteso shape `{environment, source, env_value, base_url, max_leverage}`)
|
`TESTNET_TOKEN` è settato, che un tool senza bearer dia `401` e con bearer
|
||||||
- live tool check read-only contro upstream testnet:
|
testnet venga instradato (deribit `get_ticker BTC-PERPETUAL`).
|
||||||
- deribit `get_ticker BTC-PERPETUAL`
|
|
||||||
- bybit `get_ticker BTCUSDT` (linear)
|
## `run_unified.sh` — interfaccia comune `/mcp` (upstream reali)
|
||||||
- hyperliquid `get_ticker BTC`
|
Verifica end-to-end contro Deribit/Hyperliquid (endpoint pubblici):
|
||||||
- alpaca `get_clock` (richiede credenziali paper valide)
|
- `get_instruments exchange=deribit` → `fees` e `history_start` popolati live
|
||||||
- macro `get_treasury_yields`
|
- `get_instruments` fan-out → contribuiscono sia deribit sia hyperliquid
|
||||||
- sentiment `get_funding_rates BTC`
|
- `get_historical` deribit + hyperliquid → candele non vuote, schema uniforme
|
||||||
|
- `get_historical exchange=bybit` → `422` (rifiutato a livello schema)
|
||||||
|
|
||||||
Variabili di ambiente:
|
Variabili di ambiente:
|
||||||
- `GATEWAY` — URL base gateway (default `http://localhost`; in produzione `https://cerbero-mcp.tielogic.xyz`)
|
- `PORT` (default `9000`) o `GATEWAY` (URL base, default `http://localhost:PORT`)
|
||||||
- `TOKEN_FILE` — path al token bearer di lettura (default `secrets/observer.token`)
|
- `MAINNET_TOKEN` / `TESTNET_TOKEN` — bearer (uno dei due basta; mainnet per dati reali)
|
||||||
|
- `BOT_TAG` (default `smoke`) — header `X-Bot-Tag`
|
||||||
|
|
||||||
Exit code 0 = tutto OK, 1 = uno o più check falliti.
|
Exit code 0 = tutto OK, 1 = uno o più check falliti, 0 con skip se nessun token.
|
||||||
|
|||||||
Executable
+60
@@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Smoke test interfaccia comune /mcp contro un server vivo + upstream reali.
|
||||||
|
# get_instruments e get_historical di Deribit/Hyperliquid sono pubblici, ma il
|
||||||
|
# bearer (testnet o mainnet) e X-Bot-Tag sono comunque richiesti dall'auth.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
PORT="${PORT:-9000}"
|
||||||
|
BASE="${GATEWAY:-http://localhost:${PORT}}"
|
||||||
|
TOKEN="${MAINNET_TOKEN:-${TESTNET_TOKEN:-}}"
|
||||||
|
TAG="${BOT_TAG:-smoke}"
|
||||||
|
|
||||||
|
if [[ -z "${TOKEN}" ]]; then
|
||||||
|
echo "==> skip: né MAINNET_TOKEN né TESTNET_TOKEN settati"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
PY="$(command -v python3 || command -v python)"
|
||||||
|
auth=(-H "Authorization: Bearer ${TOKEN}" -H "X-Bot-Tag: ${TAG}" -H "Content-Type: application/json")
|
||||||
|
start="$(date -u -d '7 days ago' +%F)"
|
||||||
|
end="$(date -u +%F)"
|
||||||
|
|
||||||
|
# post PATH JSON_BODY EXPECTED_STATUS PY_ASSERT
|
||||||
|
post() {
|
||||||
|
local path="$1" body="$2" want="$3" assert="${4:-}"
|
||||||
|
local resp status out
|
||||||
|
resp="$(curl -s -w '\n%{http_code}' -X POST "${BASE}${path}" "${auth[@]}" -d "${body}")"
|
||||||
|
status="$(printf '%s' "${resp}" | tail -n1)"
|
||||||
|
out="$(printf '%s' "${resp}" | sed '$d')"
|
||||||
|
if [[ "${status}" != "${want}" ]]; then
|
||||||
|
echo " FAIL ${path}: atteso HTTP ${want}, got ${status}"
|
||||||
|
printf '%s\n' "${out}" | head -c 400; echo
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [[ -n "${assert}" ]]; then
|
||||||
|
printf '%s' "${out}" | "${PY}" -c "import sys,json; d=json.load(sys.stdin); ${assert}" \
|
||||||
|
|| { echo " FAIL ${path}: assert"; exit 1; }
|
||||||
|
fi
|
||||||
|
echo " OK ${path} → HTTP ${status}"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "==> get_instruments exchange=deribit (fees + history_start live)"
|
||||||
|
post "/mcp/tools/get_instruments" '{"exchange":"deribit","currency":"BTC","kind":"future"}' 200 \
|
||||||
|
"assert d['instruments'], 'no instruments'; i=d['instruments'][0]; assert i['exchange']=='deribit'; assert 'fees' in i and 'history_start' in i; print(' ', i['symbol'], i['fees'], i['history_start'])"
|
||||||
|
|
||||||
|
echo "==> get_instruments fan-out (deribit + hyperliquid)"
|
||||||
|
post "/mcp/tools/get_instruments" '{}' 200 \
|
||||||
|
"exs={i['exchange'] for i in d['instruments']}; assert {'deribit','hyperliquid'} <= exs, exs; print(' venues:', sorted(exs), '| failed:', d['failed_sources'])"
|
||||||
|
|
||||||
|
echo "==> get_historical deribit BTC-PERPETUAL 1h"
|
||||||
|
post "/mcp/tools/get_historical" "{\"exchange\":\"deribit\",\"instrument\":\"BTC-PERPETUAL\",\"interval\":\"1h\",\"start_date\":\"${start}\",\"end_date\":\"${end}\"}" 200 \
|
||||||
|
"assert d['exchange']=='deribit'; assert d['candles'], 'no candles'; c=d['candles'][0]; assert {'timestamp','open','high','low','close','volume'} <= set(c); print(' candles:', len(d['candles']))"
|
||||||
|
|
||||||
|
echo "==> get_historical hyperliquid BTC 1h"
|
||||||
|
post "/mcp/tools/get_historical" "{\"exchange\":\"hyperliquid\",\"instrument\":\"BTC\",\"interval\":\"1h\",\"start_date\":\"${start}\",\"end_date\":\"${end}\"}" 200 \
|
||||||
|
"assert d['exchange']=='hyperliquid'; assert d['candles'], 'no candles'; print(' candles:', len(d['candles']))"
|
||||||
|
|
||||||
|
echo "==> get_historical exchange non supportato → 422"
|
||||||
|
post "/mcp/tools/get_historical" "{\"exchange\":\"bybit\",\"instrument\":\"BTCUSDT\",\"interval\":\"1h\",\"start_date\":\"${start}\",\"end_date\":\"${end}\"}" 422
|
||||||
|
|
||||||
|
echo "==> SMOKE /mcp OK"
|
||||||
Reference in New Issue
Block a user