feat: implement blackout queue and recovery revalidation (TASK-CODE-008)
This commit is contained in:
81
tests/test_blackout_manager.py
Normal file
81
tests/test_blackout_manager.py
Normal file
@@ -0,0 +1,81 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from src.core.blackout_manager import (
|
||||
BlackoutOrderManager,
|
||||
QueuedOrderIntent,
|
||||
parse_blackout_windows_kst,
|
||||
)
|
||||
|
||||
|
||||
def test_parse_blackout_windows_kst() -> None:
|
||||
windows = parse_blackout_windows_kst("23:30-00:10,11:20-11:30,invalid")
|
||||
assert len(windows) == 2
|
||||
|
||||
|
||||
def test_blackout_manager_handles_cross_midnight_window() -> None:
|
||||
manager = BlackoutOrderManager(
|
||||
enabled=True,
|
||||
windows=parse_blackout_windows_kst("23:30-00:10"),
|
||||
max_queue_size=10,
|
||||
)
|
||||
# 2026-01-01 23:40 KST = 2026-01-01 14:40 UTC
|
||||
assert manager.in_blackout(datetime(2026, 1, 1, 14, 40, tzinfo=UTC))
|
||||
# 2026-01-02 00:20 KST = 2026-01-01 15:20 UTC
|
||||
assert not manager.in_blackout(datetime(2026, 1, 1, 15, 20, tzinfo=UTC))
|
||||
|
||||
|
||||
def test_recovery_batch_only_after_blackout_exit() -> None:
|
||||
manager = BlackoutOrderManager(
|
||||
enabled=True,
|
||||
windows=parse_blackout_windows_kst("23:30-00:10"),
|
||||
max_queue_size=10,
|
||||
)
|
||||
intent = QueuedOrderIntent(
|
||||
market_code="KR",
|
||||
exchange_code="KRX",
|
||||
stock_code="005930",
|
||||
order_type="BUY",
|
||||
quantity=1,
|
||||
price=100.0,
|
||||
source="test",
|
||||
queued_at=datetime.now(UTC),
|
||||
)
|
||||
assert manager.enqueue(intent)
|
||||
|
||||
# Inside blackout: no pop yet
|
||||
inside_blackout = datetime(2026, 1, 1, 14, 40, tzinfo=UTC)
|
||||
assert manager.pop_recovery_batch(inside_blackout) == []
|
||||
|
||||
# Outside blackout: pop full batch once
|
||||
outside_blackout = datetime(2026, 1, 1, 15, 20, tzinfo=UTC)
|
||||
batch = manager.pop_recovery_batch(outside_blackout)
|
||||
assert len(batch) == 1
|
||||
assert manager.pending_count == 0
|
||||
|
||||
|
||||
def test_requeued_intent_is_processed_next_non_blackout_cycle() -> None:
|
||||
manager = BlackoutOrderManager(
|
||||
enabled=True,
|
||||
windows=parse_blackout_windows_kst("23:30-00:10"),
|
||||
max_queue_size=10,
|
||||
)
|
||||
intent = QueuedOrderIntent(
|
||||
market_code="KR",
|
||||
exchange_code="KRX",
|
||||
stock_code="005930",
|
||||
order_type="BUY",
|
||||
quantity=1,
|
||||
price=100.0,
|
||||
source="test",
|
||||
queued_at=datetime.now(UTC),
|
||||
)
|
||||
manager.enqueue(intent)
|
||||
outside_blackout = datetime(2026, 1, 1, 15, 20, tzinfo=UTC)
|
||||
first_batch = manager.pop_recovery_batch(outside_blackout)
|
||||
assert len(first_batch) == 1
|
||||
|
||||
manager.requeue(first_batch[0])
|
||||
second_batch = manager.pop_recovery_batch(outside_blackout)
|
||||
assert len(second_batch) == 1
|
||||
Reference in New Issue
Block a user