Files
poly-maker/tests/test_execution.py
T

71 lines
2.3 KiB
Python
Raw Normal View History

2026-07-05 17:50:04 -04:00
"""Tests for the rate budgeter and the paper-mode gateway."""
from __future__ import annotations
import asyncio
import time
import pytest
from polymaker.config import Config
from polymaker.domain import Quote, Side
from polymaker.execution.gateway import ExecutionGateway, _tick_str
from polymaker.execution.ratelimit import TokenBucket
def test_tick_str_formats():
assert _tick_str(0.01) == "0.01"
assert _tick_str(0.001) == "0.001"
assert _tick_str(0.0025) == "0.0025"
assert _tick_str(0.1) == "0.1"
async def test_token_bucket_limits_rate():
bucket = TokenBucket(rate_per_s=100.0, burst=5.0)
start = time.monotonic()
# burst of 5 is instant; the next 5 must wait ~ (5/100)s = 50ms
for _ in range(10):
await bucket.acquire(1)
elapsed = time.monotonic() - start
assert elapsed >= 0.04 # had to wait for refill
async def test_token_bucket_pressure_rises_when_drained():
bucket = TokenBucket(rate_per_s=10.0, burst=10.0)
assert bucket.pressure == pytest.approx(0.0, abs=0.01)
for _ in range(10):
await bucket.acquire(1)
assert bucket.pressure > 0.8
async def test_paper_gateway_places_and_cancels_without_wallet(meta):
cfg = Config() # defaults, no secrets
gw = ExecutionGateway(cfg, paper=True)
quotes = [
Quote(meta.yes.token_id, Side.BUY, 0.49, 100),
Quote(meta.no.token_id, Side.BUY, 0.48, 100),
]
placed = await gw.place(quotes, meta)
assert len(placed) == 2
assert all(o.order_id.startswith("paper-") for o in placed)
# cancel is a no-op in paper mode but must not raise
await gw.cancel([o.order_id for o in placed])
assert await gw.open_orders() == []
async def test_paper_gateway_heartbeat_and_cancel_all_noop():
gw = ExecutionGateway(Config(), paper=True)
2026-07-05 18:47:11 -04:00
assert await gw.heartbeat() is True # paper: healthy no-op
assert gw.heartbeat_failures == 0
2026-07-05 17:50:04 -04:00
await gw.cancel_all() # no client, must not raise
def test_gateway_requires_wallet_for_live_connect():
from polymaker.config import Secrets
# explicitly-empty secrets (don't read a real .env that may exist on disk)
cfg = Config(secrets=Secrets(_env_file=None))
gw = ExecutionGateway(cfg, paper=False)
with pytest.raises(RuntimeError, match="no wallet"):
asyncio.run(gw.connect())