PayrollManagementSystem/backend/tests/integration/test_tplus_sync_console.py

80 lines
4.4 KiB
Python
Raw Normal View History

"""同步控制台的真实鉴权、配置保存、审计与进度契约。仅隔离库执行。"""
from pathlib import Path
from uuid import uuid4
import pytest
from sqlalchemy import select
from app.core.db import get_session_factory
from app.models import OperationLog, TPlusSyncBatch
from app.services.tplus import task_service
pytestmark = pytest.mark.integration
BASE = "/api/v1/system/tplus"
def test_不可逆迁移拒绝回退且不修改同步批次():
from alembic import command
from alembic.config import Config
from alembic.script import ScriptDirectory
from sqlalchemy import inspect, text
from app.core.db import get_engine
engine = get_engine()
assert engine.url.database.startswith("payroll_test_")
with engine.connect() as connection:
before = connection.exec_driver_sql('SELECT COUNT(*) FROM tplus_sync_batches').scalar_one()
config = Config(str(Path(__file__).resolve().parents[2] / "alembic.ini"))
with pytest.raises(RuntimeError, match="不可直接回退"):
command.downgrade(config, "26e7f8a9b0c1")
command.upgrade(config, "head")
assert inspect(engine).has_table("tplus_automation_configs")
with engine.connect() as connection:
assert connection.execute(text('SELECT version_num FROM alembic_version')).scalar_one() == ScriptDirectory.from_config(config).get_current_head()
assert connection.exec_driver_sql('SELECT COUNT(*) FROM tplus_sync_batches').scalar_one() == before
def test_开关保存后刷新生效且拒绝过期版本(client, admin, normal, tplus_tasks, monkeypatch):
settings = task_service.get_settings().model_copy(update={
"t_plus_database": "unit_auto_" + uuid4().hex[:8], "t_plus_automation_enabled": True})
monkeypatch.setattr(task_service, "get_settings", lambda: settings)
initial = client.get(BASE + "/overview", headers=admin["headers"]).json()["data"]["automation"]
assert initial["enabled"] and initial["editable"] and initial["version"] == 0
payload = {"enabled": False, "expected_version": 0}
assert client.put(BASE + "/automation", json=payload).status_code == 401
assert client.put(BASE + "/automation", json=payload, headers=normal["headers"]).status_code == 403
saved = client.put(BASE + "/automation", json=payload, headers=admin["headers"])
assert saved.status_code == 200 and not saved.json()["data"]["enabled"]
assert saved.json()["data"]["version"] == 1
refreshed = client.get(BASE + "/overview", headers=admin["headers"]).json()["data"]["automation"]
assert refreshed["enabled"] is False and refreshed["configuration_origin"] == "SAVED"
assert client.put(BASE + "/automation", json={"enabled": True, "expected_version": 0}, headers=admin["headers"]).status_code == 409
assert client.put(BASE + "/automation", json={"enabled": "false", "expected_version": 1}, headers=admin["headers"]).status_code == 400
with get_session_factory()() as session:
assert session.scalar(select(OperationLog.id).where(
OperationLog.user_id == admin["id"], OperationLog.action == "修改自动采集",
OperationLog.success == 1,
).limit(1))
def test_列表详情概况的进度一致且不透传原始报告(client, admin, tplus_tasks):
number = client.post(BASE + "/batches", json=tplus_tasks(), headers=admin["headers"]).json()["data"]["batch_no"]
with get_session_factory()() as session:
batch = session.scalar(select(TPlusSyncBatch).where(TPlusSyncBatch.batch_no == number))
batch.status, batch.source_record_count, batch.skipped_record_count = "RUNNING", 50, 50
batch.audit_result_json = {"password": "private-string-not-exposed", "progress": {
"phase": "READING", "total_records": 200, "active_entity": "personnel",
"entities": {"personnel": {"total": 200, "processed": 50, "status": "READING"}},
}}
session.commit()
for path in (f"/batches/{number}", "/batches", "/overview"):
response = client.get(BASE + path, headers=admin["headers"])
assert response.status_code == 200
assert "private-string-not-exposed" not in response.text
data = response.json()["data"]
batch = data["current_batch"] if path == "/overview" else next(b for b in data["list"] if b["batch_no"] == number) if path == "/batches" else data
assert batch["progress"]["percentage"] == 25
assert batch["progress"]["processed_records"] == 50