76 lines
2.4 KiB
Python
76 lines
2.4 KiB
Python
import json
|
|
|
|
from rpa_yisaiqi.callback_client import StateCenterClient
|
|
from rpa_yisaiqi.runtime.errors import LoginFailed, NodeError
|
|
from rpa_yisaiqi.runtime.shell import execute_node
|
|
|
|
|
|
class FakeHttp:
|
|
def __init__(self, responses=None):
|
|
self.requests = []
|
|
self.responses = list(responses or [{"ok": True}, {"ok": True, "next_node": "PRODUCT_MATCH"}])
|
|
|
|
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,
|
|
"method": request.get_method(),
|
|
"body": body,
|
|
})
|
|
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_execute_node_starts_then_completes_with_runner_payload():
|
|
http = FakeHttp()
|
|
client = StateCenterClient("http://state-center:8000", "dev-agent-token", opener=http)
|
|
|
|
result = execute_node(
|
|
client,
|
|
"JOB-1",
|
|
"ORDER_FETCH",
|
|
lambda: {"summary": {"orderCount": 1}, "businessRefs": {}},
|
|
attempt_no=1,
|
|
)
|
|
|
|
assert result["next_node"] == "PRODUCT_MATCH"
|
|
assert [req["url"].rsplit("/", 1)[-1] for req in http.requests] == ["start", "complete"]
|
|
assert http.requests[1]["body"]["summary"] == {"orderCount": 1}
|
|
assert http.requests[1]["body"]["attemptNo"] == 1
|
|
|
|
|
|
def test_execute_node_maps_login_failure_to_fail_callback():
|
|
http = FakeHttp([{"ok": True}, {"ok": True, "job_status": "FAILED_RETRYABLE"}])
|
|
client = StateCenterClient("http://state-center:8000", "dev-agent-token", opener=http)
|
|
|
|
def failing():
|
|
raise LoginFailed("登录失败")
|
|
|
|
result = execute_node(client, "JOB-1", "ORDER_FETCH", failing)
|
|
|
|
assert result["job_status"] == "FAILED_RETRYABLE"
|
|
assert http.requests[1]["url"].endswith("/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"
|
|
|
|
|
|
def test_node_error_carries_default_ui_code():
|
|
exc = NodeError("元素找不到")
|
|
assert exc.error_code == "UI_ELEMENT_NOT_FOUND"
|
|
assert exc.retryable is False
|
|
assert exc.route_role == "OPS"
|