"""同一意图不可重复排队,重试必须保留原始批次和范围。""" from uuid import uuid4 import pytest from sqlalchemy import func, select from app.core.exceptions import BadRequestError from app.models import TPlusSyncBatch, TPlusSyncError from app.schemas.tplus import TPlusCreateIn, TPlusRetryIn from app.services.tplus import task_service def _create(**kwargs): return TPlusCreateIn(request_key=uuid4(), entity_types=["products"], **kwargs) def test_同键同意图复用同一批次(tplus_session): request = _create() first = task_service.create_task(tplus_session, request) second = task_service.create_task(tplus_session, request) assert first.id == second.id assert first.status == "QUEUED" assert first.started_at is None assert first.entity_types_json == ["products"] assert tplus_session.scalar(select(func.count()).select_from(TPlusSyncBatch)) == 1 def test_同键不同范围拒绝(tplus_session): request = _create() task_service.create_task(tplus_session, request) changed = TPlusCreateIn(request_key=request.request_key, entity_types=["personnel"]) with pytest.raises(BadRequestError, match="幂等"): task_service.create_task(tplus_session, changed) def test_失败重试创建新批次并保留原错误(tplus_session): parent = task_service.create_task(tplus_session, _create()) parent.status = "FAILED" tplus_session.add( TPlusSyncError( batch_no=parent.batch_no, entity_type="products", source_table="AA_Inventory", error_code="READ_ERROR", error_message="读取失败", ) ) tplus_session.commit() retry = TPlusRetryIn(request_key=uuid4()) child = task_service.retry_task(tplus_session, parent.batch_no, retry) replay = task_service.retry_task(tplus_session, parent.batch_no, retry) assert child.id == replay.id and child.id != parent.id assert child.parent_batch_no == parent.batch_no assert parent.status == "FAILED" assert tplus_session.scalar(select(TPlusSyncError.retry_count)) == 1 def test_已有未完成重试时不重复排队(tplus_session): parent = task_service.create_task(tplus_session, _create()) parent.status = "FAILED" tplus_session.commit() task_service.retry_task(tplus_session, parent.batch_no, TPlusRetryIn(request_key=uuid4())) with pytest.raises(BadRequestError, match="重试任务"): task_service.retry_task(tplus_session, parent.batch_no, TPlusRetryIn(request_key=uuid4())) def test_成功或未知历史范围不能自动重试(tplus_session): parent = task_service.create_task(tplus_session, _create()) parent.status = "SUCCEEDED" tplus_session.commit() with pytest.raises(BadRequestError): task_service.retry_task(tplus_session, parent.batch_no, TPlusRetryIn(request_key=uuid4())) parent.status, parent.entity_types_json = "FAILED", None tplus_session.commit() with pytest.raises(BadRequestError, match="范围"): task_service.retry_task(tplus_session, parent.batch_no, TPlusRetryIn(request_key=uuid4())) def test_关联核验不需要读取实体范围(tplus_session): batch = task_service.create_task( tplus_session, TPlusCreateIn(task_type="AUDIT", request_key=uuid4()) ) assert batch.sync_mode == "AUDIT" assert batch.entity_types_json == [] def test_预留增量批次不得静默改为全量重试(tplus_session): batch = task_service.create_task(tplus_session, _create()) batch.status, batch.sync_mode = "FAILED", "INCREMENTAL" tplus_session.commit() with pytest.raises(BadRequestError, match="方式"): task_service.retry_task(tplus_session, batch.batch_no, TPlusRetryIn(request_key=uuid4()))