63 lines
2.3 KiB
Python
63 lines
2.3 KiB
Python
|
|
"""在显式指定的临时 MySQL 库中验证工资月份行锁。"""
|
||
|
|
|
||
|
|
import os
|
||
|
|
from concurrent.futures import ThreadPoolExecutor, TimeoutError
|
||
|
|
from datetime import datetime
|
||
|
|
from threading import Event
|
||
|
|
from types import SimpleNamespace
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from sqlalchemy import create_engine
|
||
|
|
from sqlalchemy.orm import Session
|
||
|
|
|
||
|
|
from app.models import PayrollMonth
|
||
|
|
from app.services.payroll_months import lock_month, lock_month_row
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.mark.skipif(not os.environ.get("PAYROLL_LOCK_TEST_URL"), reason="需要独立的临时 MySQL 测试库")
|
||
|
|
def test_同步等待工资事务提交并读取最新生成状态(monkeypatch):
|
||
|
|
from app.services import payroll_months
|
||
|
|
|
||
|
|
engine = create_engine(os.environ["PAYROLL_LOCK_TEST_URL"])
|
||
|
|
PayrollMonth.__table__.create(engine)
|
||
|
|
monkeypatch.setattr(payroll_months, "ensure_payroll_writer", lambda _operator: None)
|
||
|
|
actor = SimpleNamespace(id=1, username="test")
|
||
|
|
started = Event()
|
||
|
|
|
||
|
|
def check_sync():
|
||
|
|
with Session(engine) as session:
|
||
|
|
started.set()
|
||
|
|
control = lock_month_row(session, "2026-03", actor)
|
||
|
|
return control.generated_at
|
||
|
|
|
||
|
|
try:
|
||
|
|
with Session(engine) as generation, ThreadPoolExecutor(max_workers=1) as pool:
|
||
|
|
control = lock_month(generation, "2026-03", actor)
|
||
|
|
result = pool.submit(check_sync)
|
||
|
|
assert started.wait(5)
|
||
|
|
with pytest.raises(TimeoutError):
|
||
|
|
result.result(timeout=0.25)
|
||
|
|
control.generated_at = datetime(2026, 3, 31)
|
||
|
|
generation.commit()
|
||
|
|
assert result.result(timeout=10) == datetime(2026, 3, 31)
|
||
|
|
|
||
|
|
started.clear()
|
||
|
|
|
||
|
|
def generate():
|
||
|
|
with Session(engine) as session:
|
||
|
|
started.set()
|
||
|
|
control = lock_month(session, "2026-04", actor)
|
||
|
|
control.generated_at = datetime(2026, 4, 30)
|
||
|
|
session.commit()
|
||
|
|
|
||
|
|
with Session(engine) as sync, ThreadPoolExecutor(max_workers=1) as pool:
|
||
|
|
lock_month_row(sync, "2026-04", actor)
|
||
|
|
result = pool.submit(generate)
|
||
|
|
assert started.wait(5)
|
||
|
|
with pytest.raises(TimeoutError):
|
||
|
|
result.result(timeout=0.25)
|
||
|
|
sync.commit()
|
||
|
|
result.result(timeout=10)
|
||
|
|
finally:
|
||
|
|
engine.dispose()
|