实现租约恢复核对:verify_on_site 接真实订单列表反查

新增 SiteInteractor.list_recent_orders(分页拉 order.my.rakuten.co.jp 订单列表,
按商品 URL 反查)+ GatewayClient.get_task,替换掉恒返回 UNKNOWN 的桩。
NOT_ORDERED 分支目前只有逻辑验证、没有真实多单数据支撑,刻意仍路由到
needs_human,不自动重新下单。全程只读查询,未触发任何真实付款操作。
This commit is contained in:
2026-08-13 23:58:54 +08:00
parent 51e2538438
commit 93c1a83406
8 changed files with 868 additions and 22 deletions
+41 -6
View File
@@ -40,11 +40,18 @@ class FakeGateway:
renews: int = 0
fail_report_with: Exception | None = None
# verify_on_site 恢复核对会调 get_task 拿 created_at;测试默认给一个可解析
# 的时间戳,具体核对分支由 monkeypatch 替换 verify.verify_on_site 控制
task_created_at: str = "2026-01-01T00:00:00Z"
async def lease(
self, worker_id: str, *, wait: int = 30, site: str | None = None
) -> LeaseTask | None:
return None # 主循环测试不通过 lease 喂数据,直接调 handle
async def get_task(self, task_id: str) -> dict[str, Any]:
return {"task_id": task_id, "created_at": self.task_created_at}
async def renew(self, task_id: str, worker_id: str) -> dict[str, Any]:
self.renews += 1
return {"task_id": task_id, "lease_expires_at": "2099-01-01T00:00:00Z"}
@@ -193,15 +200,17 @@ async def test_already_finished_task_is_reported_not_re_executed(
async def test_recovery_task_with_unknown_verdict_reports_needs_human(
runner: WorkerRunner, local_db: LocalDB, monkeypatch
):
"""lease_count > 1 + verify 返回 unknown → 转 needs_human,不执行"""
"""lease_count > 1 + verify 返回 unknown(intent 缺 item_url)→ 转 needs_human,不执行"""
# verify 桩默认返回 unknown,不用 monkeypatch
# verify.verify_on_site 已是真实实现(2026-08-13),但 _make_task 默认 intent 为空,
# 缺 item_url 时函数第一步就短路返回 unknown,不用 monkeypatch 也能测这条分支
await runner.handle(_make_task(task_id="t1", lease_count=2))
gateway: FakeGateway = runner._gateway_for_test # type: ignore[attr-defined]
terminal = gateway.last_terminal_report()
assert terminal["terminal_status"] == TaskStatus.NEEDS_HUMAN
assert "无法定论" in terminal["detail"]
assert "unknown" in terminal["detail"]
assert "item_url" in terminal["detail"]
async def test_recovery_task_with_already_ordered_verdict_reports_succeeded(
@@ -209,7 +218,7 @@ async def test_recovery_task_with_already_ordered_verdict_reports_succeeded(
):
"""lease_count > 1 + verify 返回 already_ordered → 补报 succeeded,不重新下单"""
async def _already_ordered(task): # noqa: ANN001
async def _already_ordered(task, **kwargs): # noqa: ANN001
return verify.VerifyResult(
verdict=verify.VerifyVerdict.ALREADY_ORDERED,
site_order_id="ord-1",
@@ -226,8 +235,34 @@ async def test_recovery_task_with_already_ordered_verdict_reports_succeeded(
assert terminal["site_order_id"] == "ord-1"
assert terminal["terminal_status"] == TaskStatus.SUCCEEDED
# 本地 DB 也应当被标记为已完成
assert await local_db.has_finished("t1") is True
async def test_recovery_task_with_not_ordered_verdict_still_reports_needs_human(
runner: WorkerRunner, local_db: LocalDB, monkeypatch
):
"""lease_count > 1 + verify 确认 not_ordered → 仍转 needs_human,不自动重新下单
刻意的保守选择(见 runner._handle_recovery 里的注释):NOT_ORDERED 分支目前
只有逻辑正确性,没有被真实多单数据验证过,放开自动重新执行前必须显式决定。
"""
async def _not_ordered(task, **kwargs): # noqa: ANN001
return verify.VerifyResult(
verdict=verify.VerifyVerdict.NOT_ORDERED,
detail="已核对任务创建时间之后的全部订单,未找到匹配商品",
)
monkeypatch.setattr(verify, "verify_on_site", _not_ordered)
await runner.handle(_make_task(task_id="t1", lease_count=2))
gateway: FakeGateway = runner._gateway_for_test # type: ignore[attr-defined]
terminal = gateway.last_terminal_report()
assert terminal["terminal_status"] == TaskStatus.NEEDS_HUMAN
assert "not_ordered" in terminal["detail"]
# needs_human 分支不标记本地完成(与 UNKNOWN 分支一致):只有 ALREADY_ORDERED
# 才 mark_finished,避免把「转人工」误当成本地已完成的终态
assert await local_db.has_finished("t1") is False
# ---- 站点交互未实现 → needs_human(§10 接口缝)----