PayrollManagementSystem/backend/tests/integration/test_tplus_supervisor.py

105 lines
3.7 KiB
Python
Raw Normal View History

"""在隔离 MySQL 中验证托管状态及命名锁,不连接 T+ 源库。"""
import threading
import time
from uuid import uuid4
from app.core.config import get_settings
from app.core.db import get_session_factory
from app.models import TPlusRuntimeControl
from app.services.tplus import supervisor
def test_托管服务在真实命名锁下启动并安全停止(monkeypatch):
factory = get_session_factory()
monkeypatch.setattr(supervisor, "LOCK_NAME", f"ys:test:supervisor:{uuid4().hex}")
monkeypatch.setattr(supervisor, "health_error", lambda _settings: None)
monkeypatch.setattr(supervisor, "tick", lambda *_args, **_kwargs: None)
entered, release, stop = threading.Event(), threading.Event(), threading.Event()
calls = []
def worker(_session, **_kwargs):
calls.append(1)
entered.set()
assert release.wait(15)
monkeypatch.setattr(supervisor, "run_once", worker)
with factory() as session:
row = session.get(TPlusRuntimeControl, 1)
row.desired_state = "RUNNING"
session.commit()
result = []
thread = threading.Thread(target=lambda: result.append(
supervisor.run(factory, get_settings(), interval=0.05, stop_event=stop)
))
thread.start()
try:
assert entered.wait(10), "托管服务未启动工作线程"
assert supervisor.run(factory, get_settings(), stop_event=threading.Event()) == 1
with factory() as session:
row = session.get(TPlusRuntimeControl, 1)
row.desired_state = "STOPPED"
session.commit()
deadline = time.monotonic() + 10
while time.monotonic() < deadline:
with factory() as session:
state = session.get(TPlusRuntimeControl, 1).actual_state
if state == "STOPPING":
break
time.sleep(0.05)
assert state == "STOPPING"
release.set()
deadline = time.monotonic() + 10
while time.monotonic() < deadline:
with factory() as session:
state = session.get(TPlusRuntimeControl, 1).actual_state
if state == "STOPPED":
break
time.sleep(0.05)
assert state == "STOPPED"
assert len(calls) == 1
finally:
release.set()
stop.set()
thread.join(15)
assert not thread.is_alive()
assert result == [0]
def test_来源异常时真实数据库记录降级状态且不领取任务(monkeypatch):
factory = get_session_factory()
monkeypatch.setattr(supervisor, "LOCK_NAME", f"ys:test:supervisor:{uuid4().hex}")
monkeypatch.setattr(supervisor, "health_error", lambda _settings: "T+ 数据库连接不可用")
claimed = threading.Event()
monkeypatch.setattr(supervisor, "run_once", lambda *_args, **_kwargs: claimed.set())
with factory() as session:
session.get(TPlusRuntimeControl, 1).desired_state = "RUNNING"
session.commit()
stop = threading.Event()
result = []
thread = threading.Thread(target=lambda: result.append(
supervisor.run(factory, get_settings(), interval=0.05, stop_event=stop)
))
thread.start()
try:
deadline = time.monotonic() + 10
state = None
while time.monotonic() < deadline:
with factory() as session:
row = session.get(TPlusRuntimeControl, 1)
state = row.actual_state
error = row.last_error
if state == "DEGRADED":
break
time.sleep(0.05)
assert state == "DEGRADED"
assert error == "T+ 数据库连接不可用"
assert not claimed.is_set()
finally:
stop.set()
thread.join(15)
assert not thread.is_alive()
assert result == [0]