Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions apps/api/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
from app.routes.intent import router as intent_router
from app.routes.receipt import router as receipt_router
from app.routes.yellow import router as yellow_router
<<<<<<< copilot/fix-concurrent-order-processing
=======
from app.routes.audit import router as audit_router
from app.routes.session import router as session_router
from app.routes.settlement import router as settlement_router

logger = logging.getLogger(__name__)
>>>>>>> main

app = FastAPI(title="CompliFlow API", version="0.1.0")

Expand All @@ -25,6 +28,9 @@
app.include_router(health_router, tags=["health"])
app.include_router(intent_router, prefix="/v1/intent", tags=["intent"])
app.include_router(receipt_router, prefix="/v1/receipt", tags=["receipt"])
<<<<<<< copilot/fix-concurrent-order-processing
app.include_router(yellow_router, prefix="/v1/orders", tags=["orders"])
=======
app.include_router(yellow_router, prefix="/v1/yellow", tags=["yellow"])
app.include_router(audit_router, prefix="/v1/audit", tags=["audit"])
app.include_router(session_router, prefix="/v1/session", tags=["session"])
Expand All @@ -44,3 +50,4 @@ async def startup() -> None:
logger.info("Database tables created / verified.")
except Exception as exc:
logger.error("Failed to initialise database tables: %s", exc)
>>>>>>> main
31 changes: 31 additions & 0 deletions apps/api/app/routes/yellow.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,33 @@
<<<<<<< copilot/fix-concurrent-order-processing
import threading

from fastapi import APIRouter, HTTPException

router = APIRouter()

_orders: dict[int, dict] = {}
_order_counter: int = 0
_lock = threading.Lock()


@router.post("/submit")
def order_submit(order: dict):
global _order_counter
with _lock:
_order_counter += 1
order_id = _order_counter
_orders[order_id] = order
return {"order_id": order_id}


@router.get("/{order_id}")
def order_get(order_id: int):
with _lock:
order = _orders.get(order_id)
if order is None:
raise HTTPException(status_code=404, detail="Order not found")
return {"order_id": order_id, "order": order}
=======
from fastapi import APIRouter, HTTPException
from app.models.yellow import (
SessionPreflightRequest,
Expand Down Expand Up @@ -238,3 +268,4 @@ async def market_data(asset_pair: str = None):
)

return result
>>>>>>> main
63 changes: 63 additions & 0 deletions apps/api/app/tests/test_yellow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import threading

from fastapi.testclient import TestClient

from app.main import app
import app.routes.yellow as yellow_module

client = TestClient(app)


def _reset_state():
with yellow_module._lock:
yellow_module._orders.clear()
yellow_module._order_counter = 0


def test_order_submit_returns_order_id():
_reset_state()
r = client.post("/v1/orders/submit", json={"item": "widget", "qty": 1})
assert r.status_code == 200
assert r.json()["order_id"] == 1


def test_order_get_returns_order():
_reset_state()
client.post("/v1/orders/submit", json={"item": "widget", "qty": 1})
r = client.get("/v1/orders/1")
assert r.status_code == 200
assert r.json()["order"]["item"] == "widget"


def test_order_get_not_found():
_reset_state()
r = client.get("/v1/orders/9999")
assert r.status_code == 404


def test_concurrent_orders_have_unique_ids():
"""Concurrent submissions must produce unique order IDs with no overwrites."""
_reset_state()

results = []
errors = []

def submit():
try:
r = client.post("/v1/orders/submit", json={"item": "concurrent"})
results.append(r.json()["order_id"])
except Exception as exc: # noqa: BLE001
errors.append(exc)

threads = [threading.Thread(target=submit) for _ in range(50)]
for t in threads:
t.start()
for t in threads:
t.join()

assert not errors, f"Unexpected errors: {errors}"
assert len(results) == 50, f"Expected 50 results, got {len(results)}"
assert len(set(results)) == 50, "Duplicate order IDs detected – race condition present"

with yellow_module._lock:
assert len(yellow_module._orders) == 50, "Orders were silently overwritten"
Loading