75 lines
3.9 KiB
Python
75 lines
3.9 KiB
Python
|
|
"""Disposable PostgreSQL compatibility/concurrency acceptance, no external platform calls.
|
||
|
|
|
||
|
|
SUPER_TEST_DATABASE_URL must point to the local wq_superalpha_test database.
|
||
|
|
"""
|
||
|
|
import asyncio
|
||
|
|
import os
|
||
|
|
from urllib.parse import urlsplit
|
||
|
|
|
||
|
|
import httpx
|
||
|
|
from alembic import command
|
||
|
|
from alembic.config import Config
|
||
|
|
from cryptography.fernet import Fernet
|
||
|
|
from sqlalchemy import select
|
||
|
|
|
||
|
|
from app.alphas import upsert_alpha
|
||
|
|
from app.config import Settings
|
||
|
|
from app.main import create_app
|
||
|
|
from app.models import BacktestItem, Research
|
||
|
|
from app.superalpha.contracts import PlanSave
|
||
|
|
from app.superalpha.service import SuperResearch
|
||
|
|
from app.worldquant import WqClient
|
||
|
|
from tests.backtest_fake import Platform
|
||
|
|
from tests.test_backtests import execute, preview, setup, start
|
||
|
|
from tests.test_superalpha import plan, test_plan_selection_build_versions_and_generic_run
|
||
|
|
|
||
|
|
|
||
|
|
async def seed(settings):
|
||
|
|
app = create_app(settings, WqClient(settings, transport=httpx.MockTransport(Platform())))
|
||
|
|
async with app.router.lifespan_context(app):
|
||
|
|
_, lane = await setup(app)
|
||
|
|
async with app.state.sessions.begin() as db:
|
||
|
|
await upsert_alpha(db, {"id": "legacy-super", "type": "SUPER", "selection": {"code": "turnover < 0.2"}, "combo": {"code": "1"}})
|
||
|
|
(await db.get(Research, "legacy-super")).note = "keep historical note"
|
||
|
|
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://testserver", headers={"X-WQ-Request": "1"}) as client:
|
||
|
|
await client.post("/api/v1/auth/login", json={"username": "admin", "password": "synthetic-admin-only"})
|
||
|
|
run = await start(client, await preview(client), "legacy")
|
||
|
|
await execute(app, lane, run["backtest_run_id"])
|
||
|
|
|
||
|
|
|
||
|
|
async def verify(settings):
|
||
|
|
app = create_app(settings, WqClient(settings, transport=httpx.MockTransport(Platform())))
|
||
|
|
async with app.router.lifespan_context(app):
|
||
|
|
async with app.state.sessions() as db:
|
||
|
|
assert (await db.get(Research, "legacy-super")).note == "keep historical note"
|
||
|
|
item = await db.scalar(select(BacktestItem))
|
||
|
|
assert item.alpha_type == "REGULAR" and item.selection is None and item.combo is None
|
||
|
|
assert item.persistence_status == "saved"
|
||
|
|
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=app), base_url="http://testserver", headers={"X-WQ-Request": "1"}) as client:
|
||
|
|
await client.post("/api/v1/auth/login", json={"username": "admin", "password": "synthetic-admin-only"})
|
||
|
|
await test_plan_selection_build_versions_and_generic_run(app, client)
|
||
|
|
imported = (await client.get("/api/v1/alphas?management_scope=super&q=legacy-super")).json()
|
||
|
|
assert imported["total"] == 1
|
||
|
|
async def save_same():
|
||
|
|
async with app.state.sessions.begin() as db:
|
||
|
|
return await SuperResearch(db).save(PlanSave(plan=plan(), idempotency_key="concurrent-save"))
|
||
|
|
first, second = await asyncio.gather(save_same(), save_same())
|
||
|
|
assert first == second
|
||
|
|
print("PostgreSQL: preserved REGULAR backtest and existing SUPER/notes; SUPER lifecycle and concurrent save replay passed")
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
url = os.environ["SUPER_TEST_DATABASE_URL"]
|
||
|
|
parsed = urlsplit(url)
|
||
|
|
if parsed.hostname not in {"127.0.0.1", "localhost"} or parsed.path != "/wq_superalpha_test":
|
||
|
|
raise SystemExit("Refusing non-local/non-disposable database")
|
||
|
|
key = Fernet.generate_key().decode()
|
||
|
|
os.environ.update(DATABASE_URL=url, ADMIN_PASSWORD="synthetic-admin-only", ENCRYPTION_KEY=key, WQ_EMAIL="", WQ_PASSWORD="")
|
||
|
|
settings = Settings(_env_file=None, database_url=url, admin_password="synthetic-admin-only", encryption_key=key, enable_runner=False, public_origin="http://testserver")
|
||
|
|
config = Config("alembic.ini")
|
||
|
|
command.upgrade(config, "head")
|
||
|
|
asyncio.run(seed(settings))
|
||
|
|
command.downgrade(config, "0020")
|
||
|
|
command.upgrade(config, "head")
|
||
|
|
asyncio.run(verify(settings))
|