contextquery-api / tests /test_concurrency_ingestion.py
RamshaAnwar's picture
fix(documents): serialize process stages with atomic update (#11)
cc78da3 unverified
Raw History Blame Contribute Delete
1.9 kB
import pytest
import time
from uuid import uuid4
from unittest.mock import patch
from concurrent.futures import ThreadPoolExecutor
from fastapi.testclient import TestClient
from app.main import app
from app.models import Chunk
from app.chunking import chunk_text as original_chunk_text
def test_concurrent_process_locks(client, db_session):
client.post("/api/v1/auth/signup", json={"email": "race_doc@test.com", "password": "Password123"})
token = client.post("/api/v1/auth/login", json={"email": "race_doc@test.com", "password": "Password123"}).json()["access_token"]
headers = {"Authorization": f"Bearer {token}"}
hub_res = client.post("/api/v1/hubs", headers={**headers, "X-Idempotency-Key": str(uuid4())}, json={"name": "Race Hub"})
hub_id = hub_res.json()["id"]
files = {"file": ("test.txt", b"Test text for race condition.", "text/plain")}
upload_res = client.post(f"/api/v1/hubs/{hub_id}/documents", headers={**headers, "X-Idempotency-Key": str(uuid4())}, files=files)
doc_id = upload_res.json()["id"]
client.post(f"/api/v1/hubs/{hub_id}/documents/{doc_id}/process", headers=headers)
def send_process(_):
with TestClient(app) as c:
return c.post(f"/api/v1/hubs/{hub_id}/documents/{doc_id}/process", headers=headers)
def slow_chunk_text(*args, **kwargs):
time.sleep(0.5)
return original_chunk_text(*args, **kwargs)
with patch("app.routers.documents.chunk_text", side_effect=slow_chunk_text) as mock_chunk:
with ThreadPoolExecutor(max_workers=2) as executor:
future1 = executor.submit(send_process, 1)
future2 = executor.submit(send_process, 2)
r1 = future1.result()
r2 = future2.result()
assert r1.status_code == 200
assert r2.status_code == 200
assert mock_chunk.call_count == 1
assert db_session.query(Chunk).count() > 0