malkhut(tests): 1140 test functions across 46 test files
CWM (103): core mechanics, exhaustive edge cases, numba, exchange mechanics Replay (118): exhaustive verification, microstructure, trajectory Training (190): asset classification, phase0 extensive, pipeline, exhaustive DSL (102): v2 syntax, expanded, new features ASEx (33): validate-before-mutate, single-writer Planner (48): MCTS, alternatives, hooks Counterparties (19): 9 adversarial agent policies Clock (30): event-driven reactor BingX (28): venue adapter IPC (8): Zinc SHM Storage (9): ClickHouse Risk (4): hard invariants State (17): frozen dataclass invariants Integration: E2E, concurrency, sync/async seams, hypothesis, fuzz, adversarial
This commit is contained in:
158
MALKHUT/malkhut/tests/test_concurrency.py
Normal file
158
MALKHUT/malkhut/tests/test_concurrency.py
Normal file
@@ -0,0 +1,158 @@
|
||||
"""
|
||||
Concurrency / race condition tests.
|
||||
|
||||
Verifies Zinc SHM IPC is safe under concurrent reader/writer access.
|
||||
Uses threading to simulate real multi-process patterns.
|
||||
"""
|
||||
import threading
|
||||
import time
|
||||
import pytest
|
||||
from malkhut.ipc.zinc_plane import MalkhutZincPlane
|
||||
from malkhut.ipc.control_plane import MalkhutControlPlane, ControlPlaneFrame
|
||||
|
||||
|
||||
class TestZincSHMConcurrency:
|
||||
def test_writer_reader_concurrent(self):
|
||||
"""Writer and reader operate concurrently without corruption."""
|
||||
plane = MalkhutZincPlane(prefix="concurrent_test")
|
||||
errors = []
|
||||
|
||||
def writer():
|
||||
try:
|
||||
for i in range(20):
|
||||
plane.publish_book({"seq": i, "ts": time.time_ns()})
|
||||
time.sleep(0.001)
|
||||
except Exception as e:
|
||||
errors.append(("writer", e))
|
||||
|
||||
def reader():
|
||||
try:
|
||||
for _ in range(20):
|
||||
try:
|
||||
data, seq = plane.read_book(timeout_ms=50)
|
||||
except Exception:
|
||||
pass # timeout is acceptable
|
||||
time.sleep(0.002)
|
||||
except Exception as e:
|
||||
errors.append(("reader", e))
|
||||
|
||||
t1 = threading.Thread(target=writer)
|
||||
t2 = threading.Thread(target=reader)
|
||||
t1.start()
|
||||
t2.start()
|
||||
t1.join(timeout=5)
|
||||
t2.join(timeout=5)
|
||||
plane.close_all()
|
||||
assert len(errors) == 0, f"Errors: {errors}"
|
||||
|
||||
def test_multiple_readers(self):
|
||||
"""Multiple readers can read from the same region without conflict."""
|
||||
plane = MalkhutZincPlane(prefix="multi_reader_test")
|
||||
plane.publish_book({"test": "data"})
|
||||
results = []
|
||||
errors = []
|
||||
|
||||
def reader(idx):
|
||||
try:
|
||||
for _ in range(10):
|
||||
try:
|
||||
data, seq = plane.read_book(timeout_ms=50)
|
||||
results.append((idx, seq))
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(0.001)
|
||||
except Exception as e:
|
||||
errors.append((idx, e))
|
||||
|
||||
threads = [threading.Thread(target=reader, args=(i,)) for i in range(3)]
|
||||
for t in threads:
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join(timeout=5)
|
||||
plane.close_all()
|
||||
assert len(errors) == 0
|
||||
assert len(results) > 0
|
||||
|
||||
def test_rapid_write_read_cycles(self):
|
||||
"""Rapid write/read cycles don't corrupt the region."""
|
||||
plane = MalkhutZincPlane(prefix="rapid_test")
|
||||
for i in range(100):
|
||||
plane.publish_book({"cycle": i})
|
||||
data, seq = plane.read_book(timeout_ms=50)
|
||||
assert data["cycle"] == i
|
||||
plane.close_all()
|
||||
|
||||
|
||||
class TestControlPlaneConcurrency:
|
||||
def test_command_write_read(self):
|
||||
"""Control plane commands can be written and read."""
|
||||
cp = MalkhutControlPlane()
|
||||
frame = ControlPlaneFrame(
|
||||
command="START", ts_ns=time.time_ns(),
|
||||
target_symbols=("BTCUSDT",), source="test",
|
||||
)
|
||||
cp.publish_command(frame)
|
||||
cmd = cp.read_command(timeout_ms=50)
|
||||
assert cmd is not None
|
||||
assert cmd.command == "START"
|
||||
assert cmd.target_symbols == ("BTCUSDT",)
|
||||
cp.close()
|
||||
|
||||
def test_ack_write_read(self):
|
||||
"""ACK frames can be written and read."""
|
||||
cp = MalkhutControlPlane()
|
||||
cp.publish_ack("START", time.time_ns(), "ok", "engine started")
|
||||
cmd = cp.read_command(timeout_ms=50)
|
||||
assert cmd is not None
|
||||
assert "ACK_START" in cmd.command
|
||||
cp.close()
|
||||
|
||||
def test_emergency_stop(self):
|
||||
"""Emergency stop command is processed."""
|
||||
cp = MalkhutControlPlane()
|
||||
frame = ControlPlaneFrame(
|
||||
command="EMERGENCY_STOP", ts_ns=time.time_ns(), source="test",
|
||||
)
|
||||
cp.publish_command(frame)
|
||||
cmd = cp.read_command(timeout_ms=50)
|
||||
assert cmd is not None
|
||||
assert cmd.command == "EMERGENCY_STOP"
|
||||
cp.close()
|
||||
|
||||
|
||||
class TestZincRegionIsolation:
|
||||
def test_different_prefixes_independent(self):
|
||||
"""Different prefixes create independent regions."""
|
||||
p1 = MalkhutZincPlane(prefix="iso_a")
|
||||
p2 = MalkhutZincPlane(prefix="iso_b")
|
||||
|
||||
p1.publish_book({"source": "a"})
|
||||
p2.publish_book({"source": "b"})
|
||||
|
||||
d1, _ = p1.read_book()
|
||||
d2, _ = p2.read_book()
|
||||
assert d1["source"] == "a"
|
||||
assert d2["source"] == "b"
|
||||
|
||||
p1.close_all()
|
||||
p2.close_all()
|
||||
|
||||
def test_multiple_region_types(self):
|
||||
"""Different region types (book, account, fulfilment, risk) are independent."""
|
||||
plane = MalkhutZincPlane(prefix="multi_region")
|
||||
plane.publish_book({"type": "book"})
|
||||
plane.publish_account({"type": "account"})
|
||||
plane.publish_fulfilment({"type": "fulfilment"})
|
||||
plane.publish_risk({"type": "risk"})
|
||||
|
||||
b, _ = plane.read_book()
|
||||
a, _ = plane.read_account()
|
||||
f, _ = plane.read_fulfilment()
|
||||
r, _ = plane.read_risk()
|
||||
|
||||
assert b["type"] == "book"
|
||||
assert a["type"] == "account"
|
||||
assert f["type"] == "fulfilment"
|
||||
assert r["type"] == "risk"
|
||||
|
||||
plane.close_all()
|
||||
Reference in New Issue
Block a user