piker/tests/replay/test_contract.py

101 lines
2.9 KiB
Python
Raw Normal View History

'''
Offline replay provider contract tests.
'''
from datetime import (
UTC,
datetime,
)
from pathlib import Path
import numpy as np
import pytest
import trio
from piker.brokers import DataUnavailable
from piker.brokers import replay
INPUTS: Path = (
Path(__file__).parents[1]
/ '_inputs'
/ 'replay'
)
def test_versioned_scenario_normalizes_market_data() -> None:
'''
Reject fixture drift before a datad actor obscures its cause.
Replay scenarios are durable test inputs rather than loose mock
dictionaries. Decode the versioned basic scenario through the
production loader and prove its market identity, Decimal fields,
contiguous event IDs, and normalized tick records survive typed
decoding. These assertions catch schema or symbology changes at
the provider boundary without starting services or using network
resources.
'''
scenario: replay.ReplayScenario = replay.load_scenario(
INPUTS / 'basic-v1.json'
)
assert scenario.version == 1
assert scenario.scenario_id == 'basic-v1'
assert scenario.markets[0].fqme == 'btcusd.test.replay'
assert str(scenario.markets[0].price_tick) == '0.01'
assert [quote.sequence for quote in scenario.quotes] == [
1,
2,
3,
4,
]
assert scenario.quotes[1].ticks[0].type == 'trade'
def test_history_queries_are_bounded_and_repeatable(
monkeypatch: pytest.MonkeyPatch,
) -> None:
'''
Keep history replay finite, offline, and repeatable.
A history fixture which mutates a cursor per request can make the
two concurrent 1-second and 1-minute backfill tasks race,
while an unbounded latest frame can make datad backfill
forever. Select the same 1-minute frame twice, then request
data ending at its first timestamp. Equal arrays prove calls
are immutable and the explicit `DataUnavailable` proves
reverse backfill terminates at the fixture boundary without
a clock delay or external request.
'''
scenario_path: Path = INPUTS / 'basic-v1.json'
monkeypatch.setenv(
'PIKER_REPLAY_SCENARIO',
str(scenario_path),
)
scenario: replay.ReplayScenario = replay.load_scenario(
scenario_path
)
mkt = scenario.markets[0]
async def main() -> None:
async with replay.open_history_client(mkt) as (
get_hist,
config,
):
first, start, end = await get_hist(60)
second, second_start, second_end = await get_hist(60)
np.testing.assert_array_equal(first, second)
assert (start, end) == (second_start, second_end)
assert config == {'erlangs': 1, 'rate': 1}
boundary: datetime = datetime.fromtimestamp(
int(first['time'][0]),
tz=UTC,
)
with pytest.raises(DataUnavailable):
await get_hist(60, end_dt=boundary)
trio.run(main)