113 lines
3.9 KiB
Python
113 lines
3.9 KiB
Python
import json
|
|
|
|
from rpa_yisaiqi.callback_client import StateCenterClient
|
|
from rpa_yisaiqi.contract_create_node import (
|
|
ContractCreateInput,
|
|
LoginFailed,
|
|
execute_contract_create,
|
|
)
|
|
|
|
|
|
class FakeHttp:
|
|
def __init__(self, responses=None):
|
|
self.requests = []
|
|
self.responses = list(responses or [{"ok": True}, {"ok": True, "next_node": "CONTRACT_APPROVE_WAIT"}])
|
|
|
|
def __call__(self, request, timeout):
|
|
body = json.loads(request.data.decode("utf-8")) if request.data else None
|
|
self.requests.append(
|
|
{
|
|
"url": request.full_url,
|
|
"headers": dict(request.header_items()),
|
|
"body": body,
|
|
"timeout": timeout,
|
|
}
|
|
)
|
|
return FakeResponse(self.responses.pop(0))
|
|
|
|
|
|
class FakeResponse:
|
|
def __init__(self, payload):
|
|
self.payload = payload
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc, tb):
|
|
return False
|
|
|
|
def read(self):
|
|
return json.dumps(self.payload).encode("utf-8")
|
|
|
|
|
|
def test_state_center_client_sends_agent_token_and_json_body():
|
|
http = FakeHttp([{"ok": True}])
|
|
client = StateCenterClient("http://state-center:8000/", "dev-agent-token", opener=http)
|
|
|
|
result = client.start_node("JOB-1", "CONTRACT_CREATE", attempt_no=2, operator="agent")
|
|
|
|
assert result == {"ok": True}
|
|
assert http.requests[0]["url"] == "http://state-center:8000/api/jobs/JOB-1/nodes/CONTRACT_CREATE/start"
|
|
assert http.requests[0]["headers"]["X-agent-token"] == "dev-agent-token"
|
|
assert http.requests[0]["body"] == {
|
|
"attemptNo": 2,
|
|
"executorPlatform": "iS-RPA",
|
|
"operator": "agent",
|
|
}
|
|
|
|
|
|
def test_state_center_client_escapes_non_ascii_path_parts():
|
|
http = FakeHttp([{"ok": True}])
|
|
client = StateCenterClient("http://state-center:8000", "dev-agent-token", opener=http)
|
|
|
|
client.start_node("YYC-合同节点联调-001", "CONTRACT_CREATE")
|
|
|
|
assert http.requests[0]["url"] == (
|
|
"http://state-center:8000/api/jobs/"
|
|
"YYC-%E5%90%88%E5%90%8C%E8%8A%82%E7%82%B9%E8%81%94%E8%B0%83-001"
|
|
"/nodes/CONTRACT_CREATE/start"
|
|
)
|
|
|
|
|
|
def test_contract_create_calls_start_then_complete_with_contract_number():
|
|
http = FakeHttp()
|
|
client = StateCenterClient("http://state-center:8000", "dev-agent-token", opener=http)
|
|
spec = ContractCreateInput(
|
|
job_id="JOB-1",
|
|
supplier_name="重庆亿昊药业",
|
|
order_date="2026-08-11",
|
|
source_type="YYC",
|
|
contract_system_no="HT-20260811-001",
|
|
)
|
|
|
|
result = execute_contract_create(spec, client)
|
|
|
|
assert result["next_node"] == "CONTRACT_APPROVE_WAIT"
|
|
assert [request["url"].split("/")[-1] for request in http.requests] == ["start", "complete"]
|
|
assert http.requests[1]["body"]["businessRefs"] == {"contractSystemNo": "HT-20260811-001"}
|
|
assert http.requests[1]["body"]["summary"]["supplierName"] == "重庆亿昊药业"
|
|
assert http.requests[1]["body"]["summary"]["contractDate"] == "2026-08-11"
|
|
|
|
|
|
def test_contract_create_reports_login_failure_to_state_center():
|
|
http = FakeHttp([{"ok": True}, {"ok": True, "job_status": "FAILED_RETRYABLE"}])
|
|
client = StateCenterClient("http://state-center:8000", "dev-agent-token", opener=http)
|
|
spec = ContractCreateInput(
|
|
job_id="JOB-1",
|
|
supplier_name="重庆亿昊药业",
|
|
order_date="2026-08-11",
|
|
source_type="YYC",
|
|
contract_system_no="HT-20260811-001",
|
|
)
|
|
|
|
def failing_runner(_spec):
|
|
raise LoginFailed("合同系统登录失败")
|
|
|
|
result = execute_contract_create(spec, client, contract_runner=failing_runner)
|
|
|
|
assert result["job_status"] == "FAILED_RETRYABLE"
|
|
assert http.requests[1]["url"].endswith("/api/jobs/JOB-1/nodes/CONTRACT_CREATE/fail")
|
|
assert http.requests[1]["body"]["errorCode"] == "SYS_LOGIN_FAIL"
|
|
assert http.requests[1]["body"]["retryable"] is True
|
|
assert http.requests[1]["body"]["routeRole"] == "OPS"
|