61 lines
2.7 KiB
Python
61 lines
2.7 KiB
Python
"""Opt-in export concurrency tests, sharing the disposable-only database guard."""
|
|
import asyncio
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
from threading import Barrier
|
|
import pytest
|
|
from fastapi import HTTPException
|
|
from test_workflow_db import db
|
|
from app.workflows import export_guard as guard
|
|
|
|
@pytest.fixture
|
|
def draft(db,monkeypatch):
|
|
with db.cursor() as cursor:
|
|
cursor.execute('SELECT id FROM customers ORDER BY id LIMIT 1')
|
|
customer=cursor.fetchone()[0]
|
|
cursor.execute("INSERT INTO ordre_drafts(title,customer_id) VALUES('Workflow export concurrency test',%s) RETURNING id",(customer,))
|
|
draft_id=cursor.fetchone()[0]
|
|
monkeypatch.setattr(guard,'is_workflow_draft',lambda _:True)
|
|
yield draft_id,customer
|
|
with db.cursor() as cursor:
|
|
cursor.execute('DELETE FROM bmc_workflow_exports WHERE draft_id=%s',(draft_id,))
|
|
cursor.execute('DELETE FROM ordre_drafts WHERE id=%s',(draft_id,))
|
|
|
|
def test_concurrent_export_and_success_replay_make_one_external_call(db,draft):
|
|
draft_id,customer=draft
|
|
calls=[]
|
|
start=Barrier(2)
|
|
request={'customer_id':customer,'lines':[{'line_key':'test','selected':True}]}
|
|
async def exporter(**kwargs):
|
|
calls.append(kwargs)
|
|
await asyncio.sleep(.1)
|
|
return {'success':True,'dry_run':False,'economic_draft_id':12345}
|
|
def send():
|
|
start.wait(timeout=10)
|
|
try: return asyncio.run(guard.guarded_export(draft_id,exporter,request))
|
|
except HTTPException as exc: return exc.status_code
|
|
with ThreadPoolExecutor(max_workers=2) as pool:
|
|
results=list(pool.map(lambda _:send(),range(2)))
|
|
assert len(calls)==1
|
|
assert 409 in results
|
|
replay=asyncio.run(guard.guarded_export(draft_id,exporter,request))
|
|
assert replay['economic_draft_id']==12345
|
|
assert len(calls)==1
|
|
with db.cursor() as cursor:
|
|
cursor.execute('SELECT status FROM bmc_workflow_exports WHERE draft_id=%s',(draft_id,))
|
|
assert cursor.fetchone()[0]=='done'
|
|
|
|
def test_timeout_persists_uncertainty_and_blocks_forced_new_export(db,draft):
|
|
draft_id,customer=draft
|
|
calls=[]
|
|
request={'customer_id':customer,'lines':[],'force_export':True}
|
|
async def exporter(**kwargs):
|
|
calls.append(kwargs)
|
|
raise asyncio.TimeoutError()
|
|
with pytest.raises(asyncio.TimeoutError): asyncio.run(guard.guarded_export(draft_id,exporter,request))
|
|
with pytest.raises(HTTPException) as error: asyncio.run(guard.guarded_export(draft_id,exporter,request))
|
|
assert error.value.status_code==409
|
|
assert len(calls)==1
|
|
with db.cursor() as cursor:
|
|
cursor.execute('SELECT status FROM bmc_workflow_exports WHERE draft_id=%s',(draft_id,))
|
|
assert cursor.fetchone()[0]=='uncertain'
|