feat(strategy-state): persist instance-scoped slot maps
This commit is contained in:
@@ -155,8 +155,10 @@ def test_cancel_attempt_reservation_is_compare_and_set(pg_clean):
|
||||
assert repo.fetch_slot(decision.slot_id).cancel_state == "requested"
|
||||
|
||||
|
||||
# dcy-028 / REQ-079·081 (BAT-042): strategy-state store + occupancy_seq column
|
||||
# REQ-0009: slot-scoped strategy-instance state map.
|
||||
def test_strategy_state_store_pg(pg_clean):
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from trex_core.adapters.persistence.postgresql import PgStrategyStateStore
|
||||
from trex_core.application import strategy_state as ss
|
||||
|
||||
@@ -169,31 +171,30 @@ def test_strategy_state_store_pg(pg_clean):
|
||||
reason="buy", actor="t")
|
||||
svc.transit_slot(slot.slot_id, SlotState.PENDING_BUY, SlotState.HOLDING,
|
||||
reason="filled", actor="t", qty=10, avg_price=100)
|
||||
# occupancy_seq persisted
|
||||
held = repo.fetch_slot(slot.slot_id)
|
||||
assert held.occupancy_seq == 1
|
||||
|
||||
# first-create
|
||||
r1 = store.set(slot.slot_id, "tsl_v1", expected_version=0,
|
||||
expected_occupancy_seq=1, data="peak", current_occupancy_seq=1,
|
||||
slot_active=True)
|
||||
r1 = store.set(slot.slot_id, "instance-a", expected_version=0, data="peak", slot_active=True)
|
||||
assert r1.ok and r1.version == 1
|
||||
# version conflict
|
||||
r2 = store.set(slot.slot_id, "tsl_v1", expected_version=0,
|
||||
expected_occupancy_seq=1, data="stale", current_occupancy_seq=1,
|
||||
slot_active=True)
|
||||
r2 = store.set(slot.slot_id, "instance-a", expected_version=0, data="stale", slot_active=True)
|
||||
assert not r2.ok and r2.reason == ss.REASON_VERSION_CONFLICT
|
||||
# batched read
|
||||
got = store.get_for_slots([slot.slot_id], {slot.slot_id: 1})
|
||||
assert got[slot.slot_id]["tsl_v1"].data == "peak"
|
||||
missing = store.set(slot.slot_id, "instance-missing", expected_version=1, data="stale", slot_active=True)
|
||||
assert not missing.ok and missing.reason == ss.REASON_VERSION_CONFLICT and missing.version == 0
|
||||
store.set(slot.slot_id, "instance-b", expected_version=0, data="other", slot_active=True)
|
||||
got = store.get_for_slots([slot.slot_id])
|
||||
assert got[slot.slot_id]["instance-a"].data == "peak"
|
||||
assert got[slot.slot_id]["instance-b"].data == "other"
|
||||
|
||||
with ThreadPoolExecutor(max_workers=2) as executor:
|
||||
writes = list(executor.map(
|
||||
lambda item: store.set(slot.slot_id, item, expected_version=0, data=item, slot_active=True),
|
||||
("instance-c", "instance-d"),
|
||||
))
|
||||
assert all(write.ok for write in writes)
|
||||
assert {"instance-c", "instance-d"} <= set(store.get_for_slots([slot.slot_id])[slot.slot_id])
|
||||
|
||||
# close deletes state (C-3)
|
||||
svc.transit_slot(slot.slot_id, SlotState.HOLDING, SlotState.PENDING_SELL,
|
||||
reason="sell", actor="t")
|
||||
svc.transit_slot(slot.slot_id, SlotState.PENDING_SELL, SlotState.INACTIVE,
|
||||
reason="sold", actor="t")
|
||||
assert store.get_for_slots([slot.slot_id], {slot.slot_id: 1}) == {}
|
||||
# reuse bumps occupancy_seq
|
||||
assert store.get_for_slots([slot.slot_id])[slot.slot_id]["instance-a"].version == 1
|
||||
reused = svc.transit_slot(slot.slot_id, SlotState.INACTIVE, SlotState.PENDING_BUY,
|
||||
reason="buy", actor="t")
|
||||
assert reused.occupancy_seq == 2
|
||||
|
||||
Reference in New Issue
Block a user