feat: 领取 Admin 采集任务并保存本地 (#30)
This commit is contained in:
@@ -116,6 +116,109 @@ class HttpAdminGatewayTest(unittest.TestCase):
|
||||
key.lower(): value for key, value in opener.request.header_items()
|
||||
})
|
||||
|
||||
def test_claim_maps_real_admin_payload_and_only_reports_collect(self):
|
||||
opener = RecordingOpener(
|
||||
FakeResponse(
|
||||
200,
|
||||
{
|
||||
"task": {
|
||||
"id": "COL-8020a8729f111c15",
|
||||
"type": "collect",
|
||||
"version": 1,
|
||||
"priority": 0,
|
||||
"payload": {
|
||||
"goods_id": "737116531267",
|
||||
"goods_url": (
|
||||
"https://mobile.yangkeduo.com/goods.html"
|
||||
"?goods_id=737116531267"
|
||||
),
|
||||
},
|
||||
"created_at": "2026-08-07T03:19:49Z",
|
||||
"updated_at": "2026-08-07T03:19:49Z",
|
||||
}
|
||||
},
|
||||
)
|
||||
)
|
||||
gateway = HttpAdminGateway(opener=opener)
|
||||
|
||||
task = gateway.claim_next(
|
||||
ClientInfo("CLIENT-001", "办公室电脑"),
|
||||
self._capabilities(),
|
||||
)
|
||||
|
||||
self.assertIsNotNone(task)
|
||||
self.assertEqual(task.task_id, "COL-8020a8729f111c15")
|
||||
self.assertEqual(task.task_type.value, "collect")
|
||||
self.assertEqual(task.payload["goods_id"], "737116531267")
|
||||
self.assertEqual(opener.request.get_method(), "POST")
|
||||
self.assertEqual(
|
||||
opener.request.full_url,
|
||||
"http://127.0.0.1:8080/api/v1/client/tasks/claim",
|
||||
)
|
||||
headers = {
|
||||
key.lower(): value for key, value in opener.request.header_items()
|
||||
}
|
||||
self.assertEqual(headers["x-client-id"], "CLIENT-001")
|
||||
self.assertTrue(headers["x-request-id"])
|
||||
self.assertIn("application/json", headers["content-type"])
|
||||
body = json.loads(opener.request.data.decode("utf-8"))
|
||||
self.assertEqual(body["supported_types"], ["collect"])
|
||||
self.assertEqual(body["capabilities"]["purchase_mode"], "dry_run")
|
||||
|
||||
def test_claim_204_returns_none(self):
|
||||
gateway = HttpAdminGateway(opener=RecordingOpener(FakeResponse(204, {})))
|
||||
|
||||
task = gateway.claim_next(
|
||||
ClientInfo("CLIENT-001"),
|
||||
self._capabilities(),
|
||||
)
|
||||
|
||||
self.assertIsNone(task)
|
||||
|
||||
def test_claim_invalid_task_fields_include_request_id(self):
|
||||
gateway = HttpAdminGateway(
|
||||
opener=RecordingOpener(FakeResponse(200, {"task": {"id": None}}))
|
||||
)
|
||||
|
||||
with self.assertRaises(AdminGatewayError) as context:
|
||||
gateway.claim_next(
|
||||
ClientInfo("CLIENT-001"),
|
||||
self._capabilities(),
|
||||
)
|
||||
|
||||
self.assertEqual(context.exception.code, "ADMIN_INVALID_RESPONSE")
|
||||
self.assertTrue(context.exception.request_id)
|
||||
|
||||
def test_claim_http_error_keeps_server_request_id(self):
|
||||
error_body = json.dumps(
|
||||
{
|
||||
"error": {
|
||||
"code": "TASK_CLAIM_FAILED",
|
||||
"message": "领取任务失败",
|
||||
"retryable": True,
|
||||
"request_id": "claim-request-id",
|
||||
}
|
||||
}
|
||||
).encode("utf-8")
|
||||
error = HTTPError(
|
||||
"http://admin/api/v1/client/tasks/claim",
|
||||
500,
|
||||
"Internal Server Error",
|
||||
{},
|
||||
io.BytesIO(error_body),
|
||||
)
|
||||
gateway = HttpAdminGateway(opener=RecordingOpener(error))
|
||||
|
||||
with self.assertRaises(AdminGatewayError) as context:
|
||||
gateway.claim_next(
|
||||
ClientInfo("CLIENT-001"),
|
||||
self._capabilities(),
|
||||
)
|
||||
|
||||
self.assertEqual(context.exception.code, "TASK_CLAIM_FAILED")
|
||||
self.assertEqual(context.exception.request_id, "claim-request-id")
|
||||
self.assertTrue(context.exception.retryable)
|
||||
|
||||
def test_admin_error_preserves_code_retry_and_request_id(self):
|
||||
error_body = json.dumps(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user