bmc_hub/tests/test_workflow_exports_db.py

61 lines
2.7 KiB
Python
Raw Normal View History

"""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'