PayrollManagementSystem/backend/tests/unit/test_tplus_progress.py
liuwenxin 1461a8d113 feat(后端): 添加授权体系、系统监控与试用期计提
按 2026-11-02 需求补齐计划交付后端能力:
- 角色授权:权限目录化,接口统一准入校验,未登记默认拒绝;
  管理员判断改为按数据库角色重新判定,防止权限码持有者绕过
- 系统监控:单进程采集资源、请求与异常指标,分钟级聚合,
  阈值配置化;敏感配置增加 repr 保护,Redis 密码 URL 转义
- 试用期计提:按回款日判定并写入快照,年度结清与调整单联动;
  人员模型补试用期、离职日期与工资版本历史字段
- 计提模板:公式骨架受控,页面维护名称与参数绑定
- T+ 采集:自动化配置表与进度查询

内置角色禁停用保护对齐模块注释;核算规则版本提为常量并
补充批量核算失败堆栈日志。

影响范围:后端全部模块、数据库迁移 V22-V28
验证:uv run ruff check 通过;922 个单元测试全部通过;
集成测试因本机 MySQL 数据卷被其他容器锁定暂未运行
2026-11-03 11:20:55 +08:00

81 lines
3.2 KiB
Python

"""真实分页进度在每页提交后可读;总量未知或失败时不伪造成功。"""
from datetime import datetime
from unittest.mock import Mock
from sqlalchemy import select
from app.models import TPlusSyncBatch
from app.services.tplus import progress
from app.services.tplus.sync_service import TPlusSyncService
from tests.unit.test_tplus_sync import target as target
def test_每页提交真实已读数及类别(target):
service = TPlusSyncService(Mock(), target)
service.reader = Mock()
service.reader.count_entities.return_value = {"products": 2}
def rows(*args, **kwargs):
yield {"id": 1}
batch = target.scalar(select(TPlusSyncBatch))
item = progress.public(batch)
assert item["processed_records"] == 1 and item["total_records"] == 2
assert item["percentage"] == 50.0 and item["active_entity"] == "products"
yield {"id": 2}
service.reader.iter_entity.side_effect = rows
batch = service.run(entity_types=["products"], batch_size=1)
item = progress.public(batch)
assert batch.status == "SUCCEEDED" and item["percentage"] == 100.0
assert item["entities"][0]["status"] == "COMPLETED"
def test_总量统计失败仍可读且执行中总量未知(target):
source = Mock()
service = TPlusSyncService(source, target)
service.reader = Mock()
service.reader.count_entities.side_effect = RuntimeError("不得公开的数据库详情")
def rows(*args, **kwargs):
batch = target.scalar(select(TPlusSyncBatch))
assert progress.public(batch)["percentage"] is None
yield {"id": 1}
service.reader.iter_entity.side_effect = rows
batch = service.run(entity_types=["products"])
assert batch.status == "SUCCEEDED"
source.rollback.assert_called_once()
def test_读取中断保留进度及错误终态(target):
service = TPlusSyncService(Mock(), target)
service.reader = Mock()
service.reader.count_entities.return_value = {"products": 4}
def rows(*args, **kwargs):
yield {"id": 1}
raise TimeoutError("敏感详情")
service.reader.iter_entity.side_effect = rows
batch = service.run(entity_types=["products"], batch_size=1)
item = progress.public(batch)
assert batch.status == "FAILED" and item["percentage"] == 25.0
assert item["phase"] == "FAILED" and item["entities"][0]["status"] == "FAILED"
def test_旧批次未知总量不显示编造百分比():
batch = TPlusSyncBatch(batch_no="old", sync_mode="FULL", status="RUNNING",
source_record_count=1000, entity_types_json=["personnel"], started_at=datetime.now())
item = progress.public(batch)
assert item["percentage"] is None and item["total_records"] is None
assert item["processed_records"] == 1000
def test_读到预统计总量仍等终态才显示百分之百():
batch = TPlusSyncBatch(batch_no="b", sync_mode="FULL", status="RUNNING",
source_record_count=10, entity_types_json=["products"], started_at=datetime.now(),
audit_result_json={"progress": {"total_records": 10}})
assert progress.public(batch)["percentage"] == 99.9
batch.status = "SUCCEEDED"
assert progress.public(batch)["percentage"] == 100.0