This commit is contained in:
@@ -162,7 +162,7 @@ async def test_official_sdk_client_and_error_contract(mcp_app):
|
||||
async with ClientSession(streams[0], streams[1]) as client:
|
||||
await client.initialize()
|
||||
listed = await client.list_tools()
|
||||
assert len(listed.tools) == 15
|
||||
assert len(listed.tools) == 17
|
||||
caps = await client.call_tool("get_research_capabilities", {})
|
||||
assert caps.structured_content["max_candidates"] == 100
|
||||
result = await client.call_tool("submit_backtests", submission())
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
"""Exercise MCP through the durable runner; the fake rejects any submit request."""
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
from app.models import Alpha, SelfCorrelation
|
||||
from tests.conftest import alpha
|
||||
from tests.test_mcp import credentials, invoke
|
||||
from tests.test_mcp import mcp_app as mcp_app
|
||||
from tests.test_submission import FIELDS, Description, setup
|
||||
|
||||
|
||||
@pytest.mark.parametrize("kind", ["REGULAR", "SUPER"])
|
||||
@pytest.mark.parametrize("result", ["PASS", "FAIL"])
|
||||
async def test_mcp_check_never_submits(mcp_app, kind, result, monkeypatch):
|
||||
from tests import test_submission
|
||||
|
||||
checks = [{"name": "PROD_CORRELATION", "result": result}]
|
||||
monkeypatch.setattr(test_submission, "CHECKS", checks)
|
||||
sections = ["regular"] if kind == "REGULAR" else ["selection", "combo"]
|
||||
platform = await setup(mcp_app, alpha(type=kind, **{s: {"code": "rank(close)"} for s in sections}))
|
||||
platform.pending = 1
|
||||
principal, _ = await credentials(mcp_app)
|
||||
caps = await invoke(mcp_app, principal, "get_research_capabilities")
|
||||
assert caps["submission_check"]["production_submission"] is False
|
||||
state = await invoke(mcp_app, principal, "get_submission_check", {"alpha_id": "alpha1"})
|
||||
assert platform.calls == []
|
||||
args = {"alpha_id": "alpha1", "snapshot": state["snapshot"],
|
||||
"descriptions": dict.fromkeys(sections, Description(**FIELDS).text())}
|
||||
started = await invoke(mcp_app, principal, "check_submission", args)
|
||||
replay = await invoke(mcp_app, principal, "check_submission", args)
|
||||
assert replay["job_id"] == started["job_id"]
|
||||
await mcp_app.state.runner.execute(started["job_id"])
|
||||
job = await invoke(mcp_app, principal, "get_refresh_job", {"job_id": started["job_id"]})
|
||||
assert job["status"] == "completed", job
|
||||
data = await invoke(mcp_app, principal, "get_submission_check", {"alpha_id": "alpha1"})
|
||||
assert data["checks"] == checks and data["checked_at"]
|
||||
assert data["production_submission"] is False
|
||||
assert platform.patches == [{s: {"description": args["descriptions"][s]} for s in sections}]
|
||||
assert platform.calls.count(("GET", "/alphas/alpha1/check")) == 2
|
||||
assert set(platform.calls) <= {("POST", "/authentication"), ("GET", "/alphas/alpha1"),
|
||||
("PATCH", "/alphas/alpha1"), ("GET", "/alphas/alpha1/check")}
|
||||
async with mcp_app.state.sessions() as db:
|
||||
assert (await db.get(Alpha, "alpha1")).status == "UNSUBMITTED"
|
||||
|
||||
|
||||
async def test_mcp_check_scope_and_guards(mcp_app):
|
||||
platform = await setup(mcp_app)
|
||||
reader, _ = await credentials(mcp_app, {"research:read"})
|
||||
state = await invoke(mcp_app, reader, "get_submission_check", {"alpha_id": "alpha1"})
|
||||
args = {"alpha_id": "alpha1", "snapshot": state["snapshot"], "descriptions": {"regular": "reviewed"}}
|
||||
with pytest.raises(HTTPException) as exc:
|
||||
await mcp_app.state.mcp.invoke(reader, "check_submission", args)
|
||||
assert exc.value.status_code == 403
|
||||
principal, _ = await credentials(mcp_app)
|
||||
for extra in [{"snapshot": "0" * 64}, {"descriptions": {"combo": "wrong"}}, {"submit": True}]:
|
||||
response = await mcp_app.state.mcp.invoke(principal, "check_submission", args | extra)
|
||||
assert response.is_error
|
||||
async with mcp_app.state.sessions.begin() as db:
|
||||
(await db.get(SelfCorrelation, "alpha1")).result = {"status": "high"}
|
||||
response = await mcp_app.state.mcp.invoke(principal, "check_submission", args)
|
||||
assert response.is_error
|
||||
assert platform.calls == []
|
||||
@@ -0,0 +1,56 @@
|
||||
import pytest
|
||||
|
||||
from app.alphas import snapshot_columns, upsert_alpha
|
||||
from tests.conftest import alpha
|
||||
|
||||
|
||||
@pytest.mark.parametrize("value", [0.6988, 0.0])
|
||||
async def test_submitted_metrics_map_without_check_history(app, logged_in, value):
|
||||
raw = alpha(status="ACTIVE", **{"is": {"prodCorrelation": value, "selfCorrelation": 0.0,
|
||||
"checks": [{"name": "LOW_2Y_SHARPE", "result": "PASS", "value": 2.1}]},
|
||||
"os": {"checks": [{"name": "PROD_CORRELATION", "result": "PENDING"}]}})
|
||||
async with app.state.sessions.begin() as db:
|
||||
await upsert_alpha(db, raw)
|
||||
detail = (await logged_in.get('/api/v1/alphas/alpha1')).json()
|
||||
assert detail['prod_correlation'] == value
|
||||
assert detail['is_metrics']['selfCorrelation'] == 0.0
|
||||
assert detail['os_metrics']['checks'][0]['result'] == 'PENDING'
|
||||
assert detail['two_year_sharpe'] == 2.1
|
||||
assert detail['check_type'] != 'PASS'
|
||||
|
||||
|
||||
def test_check_value_takes_precedence_over_cached_metric():
|
||||
assert snapshot_columns({}, {'prodCorrelation': 0.4}, [
|
||||
{'name': 'PROD_CORRELATION', 'value': 0.0, 'result': 'PASS'}
|
||||
])['prod_correlation'] == 0.0
|
||||
|
||||
|
||||
def test_migration_recovers_saved_values_without_overwriting_existing():
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import sqlalchemy as sa
|
||||
|
||||
path = Path(__file__).parents[1] / 'migrations/versions/0013_submitted_correlation.py'
|
||||
spec = importlib.util.spec_from_file_location('migration_0013', path)
|
||||
migration = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(migration)
|
||||
engine = sa.create_engine('sqlite://')
|
||||
metadata = sa.MetaData()
|
||||
table = sa.Table('alphas', metadata, sa.Column('id', sa.String, primary_key=True),
|
||||
sa.Column('is_metrics', sa.JSON), sa.Column('prod_correlation', sa.Float))
|
||||
metadata.create_all(engine)
|
||||
with engine.begin() as db:
|
||||
db.execute(table.insert(), [
|
||||
{'id': 'zero', 'is_metrics': {'prodCorrelation': 0.0}, 'prod_correlation': None},
|
||||
{'id': 'saved', 'is_metrics': {'prodCorrelation': 0.6988}, 'prod_correlation': None},
|
||||
{'id': 'existing', 'is_metrics': {'prodCorrelation': 0.4}, 'prod_correlation': 0.2},
|
||||
{'id': 'missing', 'is_metrics': {}, 'prod_correlation': None},
|
||||
])
|
||||
migration.op = SimpleNamespace(get_bind=lambda: db)
|
||||
migration.upgrade()
|
||||
migration.upgrade()
|
||||
assert dict(db.execute(sa.select(table.c.id, table.c.prod_correlation)).all()) == {
|
||||
'zero': 0.0, 'saved': 0.6988, 'existing': 0.2, 'missing': None}
|
||||
engine.dispose()
|
||||
Reference in New Issue
Block a user