feat: 安全领取并分派采购任务 (#72)

This commit is contained in:
chengma
2026-08-10 00:05:40 +08:00
parent 460619392f
commit f201bcc4bf
12 changed files with 789 additions and 76 deletions
+53 -2
View File
@@ -14,6 +14,7 @@ from src.admin_gateway import (
ClientInfo,
)
from src.http_admin_gateway import HttpAdminGateway
from src.task_models import TaskType
class FakeResponse:
@@ -88,7 +89,7 @@ class HttpAdminGatewayTest(unittest.TestCase):
self.assertEqual(headers["authorization"], "Bearer secret-token")
body = json.loads(opener.request.data.decode("utf-8"))
self.assertEqual(body["client"]["name"], "办公室电脑")
self.assertEqual(body["supported_types"], ["collect", "purchase"])
self.assertEqual(body["supported_types"], ["collect"])
self.assertEqual(body["device"]["platform"], "android")
self.assertEqual(body["capabilities"]["purchase_mode"], "dry_run")
self.assertEqual(opener.timeout, 2.5)
@@ -218,7 +219,7 @@ class HttpAdminGatewayTest(unittest.TestCase):
self.assertTrue(raised.exception.retryable)
self.assertIn("可能已接收", str(raised.exception))
def test_claim_maps_real_admin_payload_and_only_reports_collect(self):
def test_claim_maps_payload_and_serializes_confirmed_capabilities(self):
opener = RecordingOpener(
FakeResponse(
200,
@@ -267,6 +268,56 @@ class HttpAdminGatewayTest(unittest.TestCase):
self.assertEqual(body["supported_types"], ["collect"])
self.assertEqual(body["capabilities"]["purchase_mode"], "dry_run")
def test_claim_purchase_requires_all_safety_fields(self):
valid_task = {
"id": "PUR-001",
"type": "purchase",
"version": 1,
"priority": 0,
"payload": {
"goods_url": "https://example.test/goods/PUR-001",
"goods_id": "737116531267",
"options": {"color": "黑色", "size": "L"},
"quantity": 2,
"max_price_cent": 4200,
},
"created_at": "2026-08-09T08:00:00Z",
"updated_at": "2026-08-09T08:00:00Z",
}
gateway = HttpAdminGateway(
opener=RecordingOpener(FakeResponse(200, {"task": valid_task}))
)
task = gateway.claim_next(
ClientInfo("CLIENT-001"),
ClaimCapabilities(
supported_types=(TaskType.COLLECT, TaskType.PURCHASE),
purchase_mode="dry_run",
),
)
self.assertEqual(task.task_type, TaskType.PURCHASE)
self.assertEqual(task.payload["max_price_cent"], 4200)
for missing in ("goods_id", "options", "quantity", "max_price_cent"):
with self.subTest(missing=missing):
invalid_task = dict(valid_task)
invalid_payload = dict(valid_task["payload"])
invalid_payload.pop(missing)
invalid_task["payload"] = invalid_payload
invalid_gateway = HttpAdminGateway(
opener=RecordingOpener(
FakeResponse(200, {"task": invalid_task})
)
)
with self.assertRaises(AdminGatewayError) as raised:
invalid_gateway.claim_next(
ClientInfo("CLIENT-001"), self._capabilities()
)
self.assertEqual(
raised.exception.code, "ADMIN_INVALID_RESPONSE"
)
def test_claim_204_returns_none(self):
gateway = HttpAdminGateway(opener=RecordingOpener(FakeResponse(204, {})))