130 lines
5.5 KiB
Python
130 lines
5.5 KiB
Python
|
|
"""管理员可管理原始读取任务;权限、幂等和异常脱敏由真实接口验证。"""
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
from sqlalchemy import select
|
||
|
|
|
||
|
|
from app.core.db import get_session_factory
|
||
|
|
from app.models import TPlusSyncBatch, TPlusSyncError
|
||
|
|
|
||
|
|
pytestmark = pytest.mark.integration
|
||
|
|
BASE = "/api/v1/system/tplus"
|
||
|
|
|
||
|
|
|
||
|
|
def test_未登录和普通用户不能访问管理(client, admin, normal, tplus_tasks):
|
||
|
|
assert client.get(BASE + "/overview").status_code == 401
|
||
|
|
assert client.get(BASE + "/overview", headers=normal["headers"]).status_code == 403
|
||
|
|
assert (
|
||
|
|
client.post(BASE + "/batches", json=tplus_tasks(), headers=normal["headers"]).status_code
|
||
|
|
== 403
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def test_创建重复请求返回同一批次并可分页查看(client, admin, tplus_tasks):
|
||
|
|
payload = tplus_tasks()
|
||
|
|
first = client.post(BASE + "/batches", json=payload, headers=admin["headers"])
|
||
|
|
assert first.status_code == 200
|
||
|
|
second = client.post(BASE + "/batches", json=payload, headers=admin["headers"])
|
||
|
|
assert second.status_code == 200
|
||
|
|
number = first.json()["data"]["batch_no"]
|
||
|
|
assert second.json()["data"]["batch_no"] == number
|
||
|
|
page = client.get(
|
||
|
|
BASE + "/batches", params={"pageSize": 1, "status": "QUEUED"}, headers=admin["headers"]
|
||
|
|
)
|
||
|
|
assert page.status_code == 200 and page.json()["data"]["pageSize"] == 1
|
||
|
|
detail = client.get(BASE + "/batches/" + number, headers=admin["headers"])
|
||
|
|
assert detail.status_code == 200
|
||
|
|
assert detail.json()["data"]["status"] == "QUEUED"
|
||
|
|
|
||
|
|
|
||
|
|
def test_异常返回固定说明不泄漏数据库参数(client, admin, tplus_tasks):
|
||
|
|
response = client.post(BASE + "/batches", json=tplus_tasks(), headers=admin["headers"])
|
||
|
|
assert response.status_code == 200
|
||
|
|
number = response.json()["data"]["batch_no"]
|
||
|
|
with get_session_factory()() as db:
|
||
|
|
batch = db.scalar(select(TPlusSyncBatch).where(TPlusSyncBatch.batch_no == number))
|
||
|
|
batch.status, batch.error_message = "FAILED", "password=private-value phone=13800000000"
|
||
|
|
db.add(
|
||
|
|
TPlusSyncError(
|
||
|
|
batch_no=number,
|
||
|
|
entity_type="personnel",
|
||
|
|
source_table="AA_Person",
|
||
|
|
source_id="12",
|
||
|
|
error_code="READ_ERROR",
|
||
|
|
error_message=batch.error_message,
|
||
|
|
)
|
||
|
|
)
|
||
|
|
db.commit()
|
||
|
|
for path in (f"/batches/{number}", f"/batches/{number}/errors"):
|
||
|
|
result = client.get(BASE + path, headers=admin["headers"])
|
||
|
|
assert result.status_code == 200
|
||
|
|
assert "private-value" not in result.text and "13800000000" not in result.text
|
||
|
|
|
||
|
|
|
||
|
|
def test_不支持的实体和不存在的批次有明确错误(client, admin, tplus_tasks):
|
||
|
|
payload = tplus_tasks()
|
||
|
|
payload["entity_types"] = ["users;drop"]
|
||
|
|
assert client.post(BASE + "/batches", json=payload, headers=admin["headers"]).status_code == 400
|
||
|
|
assert client.get(BASE + "/batches/TPmissing", headers=admin["headers"]).status_code == 404
|
||
|
|
|
||
|
|
|
||
|
|
def test_配置关闭时可查询历史但不能排队(client, admin, tplus_tasks, monkeypatch):
|
||
|
|
from app.services.tplus import task_service
|
||
|
|
|
||
|
|
settings = task_service.get_settings().model_copy(update={"t_plus_enabled": False})
|
||
|
|
monkeypatch.setattr(task_service, "get_settings", lambda: settings)
|
||
|
|
response = client.get(BASE + "/overview", headers=admin["headers"])
|
||
|
|
assert response.status_code == 200
|
||
|
|
assert response.json()["data"]["is_configured"] is False
|
||
|
|
assert response.json()["data"]["business_import_enabled"] is False
|
||
|
|
assert response.json()["data"]["compatibility_status"] == "PENDING"
|
||
|
|
assert (
|
||
|
|
client.post(BASE + "/batches", json=tplus_tasks(), headers=admin["headers"]).status_code
|
||
|
|
== 400
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
def test_失败批次重试保留异常并返回新批次(client, admin, tplus_tasks):
|
||
|
|
from app.models import OperationLog
|
||
|
|
|
||
|
|
parent = client.post(BASE + "/batches", json=tplus_tasks(), headers=admin["headers"]).json()[
|
||
|
|
"data"
|
||
|
|
]
|
||
|
|
number = parent["batch_no"]
|
||
|
|
with get_session_factory()() as db:
|
||
|
|
batch = db.scalar(select(TPlusSyncBatch).where(TPlusSyncBatch.batch_no == number))
|
||
|
|
batch.status, batch.failed_record_count = "FAILED", 1
|
||
|
|
db.add(
|
||
|
|
TPlusSyncError(
|
||
|
|
batch_no=number,
|
||
|
|
entity_type="personnel",
|
||
|
|
source_table="AA_Person",
|
||
|
|
source_id="1",
|
||
|
|
error_code="READ_ERROR",
|
||
|
|
error_message="读取失败",
|
||
|
|
)
|
||
|
|
)
|
||
|
|
db.commit()
|
||
|
|
request = {"request_key": tplus_tasks()["request_key"]}
|
||
|
|
first = client.post(BASE + f"/batches/{number}/retry", json=request, headers=admin["headers"])
|
||
|
|
replay = client.post(BASE + f"/batches/{number}/retry", json=request, headers=admin["headers"])
|
||
|
|
assert first.status_code == replay.status_code == 200
|
||
|
|
child = first.json()["data"]
|
||
|
|
assert child["parent_batch_no"] == number and child["batch_no"] != number
|
||
|
|
assert replay.json()["data"]["batch_no"] == child["batch_no"]
|
||
|
|
detail = client.get(BASE + f"/batches/{number}", headers=admin["headers"]).json()["data"]
|
||
|
|
assert detail["can_retry"] is False
|
||
|
|
with get_session_factory()() as db:
|
||
|
|
assert (
|
||
|
|
db.scalar(select(TPlusSyncError.retry_count).where(TPlusSyncError.batch_no == number))
|
||
|
|
== 1
|
||
|
|
)
|
||
|
|
assert db.scalar(
|
||
|
|
select(OperationLog.id)
|
||
|
|
.where(
|
||
|
|
OperationLog.user_id == admin["id"],
|
||
|
|
OperationLog.module == "T+数据同步",
|
||
|
|
OperationLog.action == "重试读取任务",
|
||
|
|
)
|
||
|
|
.limit(1)
|
||
|
|
)
|