feat: normalize workflow OpenRPC manifests
This commit is contained in:
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
def synthetic_openrpc_document() -> dict[str, Any]:
|
||||
return {
|
||||
"openrpc": "1.2.6",
|
||||
"info": {"title": "ignored", "version": "0"},
|
||||
"methods": [
|
||||
{
|
||||
"name": "workflow.zeta.run",
|
||||
"params": [],
|
||||
"result": {
|
||||
"name": "workflow.zeta.run_Result",
|
||||
"schema": {"$ref": "#/components/schemas/ZetaResult"},
|
||||
},
|
||||
"errors": [{"$ref": "#/components/errors/5000"}],
|
||||
},
|
||||
{
|
||||
"name": "workflow.alpha.inspect",
|
||||
"params": [
|
||||
{
|
||||
"name": "optional_nullable",
|
||||
"required": False,
|
||||
"schema": {
|
||||
"title": "Optional Nullable",
|
||||
"anyOf": [{"type": "string"}, {"type": "null"}],
|
||||
"x-future-keyword": {
|
||||
"title": "removed recursively",
|
||||
"value": 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "required_closed",
|
||||
"required": True,
|
||||
"schema": {
|
||||
"title": "Required Closed",
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
},
|
||||
},
|
||||
],
|
||||
"result": {
|
||||
"name": "workflow.alpha.inspect_Result",
|
||||
"schema": {"$ref": "#/components/schemas/AlphaResult"},
|
||||
},
|
||||
"errors": [{"$ref": "#/components/errors/5000"}],
|
||||
},
|
||||
],
|
||||
"components": {
|
||||
"schemas": {
|
||||
"ZetaResult": {
|
||||
"title": "Zeta Result",
|
||||
"type": "object",
|
||||
"properties": {"extension": {"additionalProperties": True}},
|
||||
},
|
||||
"FreeJson": {},
|
||||
"AlphaResult": {
|
||||
"title": "Alpha Result",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"mode": {"title": "Mode", "const": "alpha"},
|
||||
"payload": {},
|
||||
},
|
||||
"required": ["mode", "payload"],
|
||||
"if": {"properties": {"mode": {"const": "alpha"}}},
|
||||
"then": {"required": ["payload"]},
|
||||
"not": {"required": ["forbidden"]},
|
||||
},
|
||||
},
|
||||
"errors": {
|
||||
"5000": {
|
||||
"code": 5000,
|
||||
"message": "Workflow operation failed",
|
||||
"data": {
|
||||
"title": "Error Data",
|
||||
"type": "object",
|
||||
"additionalProperties": False,
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from wf_contract_manifest import manifest_from_openrpc
|
||||
|
||||
from .fixtures import synthetic_openrpc_document
|
||||
|
||||
|
||||
def test_normalizes_operations_and_components_deterministically() -> None:
|
||||
manifest = manifest_from_openrpc(synthetic_openrpc_document())
|
||||
|
||||
assert manifest["manifest_version"] == 1
|
||||
assert manifest["source"] == {
|
||||
"format": "openrpc",
|
||||
"openrpc_version": "1.2.6",
|
||||
}
|
||||
assert [operation["method"] for operation in manifest["operations"]] == [
|
||||
"workflow.alpha.inspect",
|
||||
"workflow.zeta.run",
|
||||
]
|
||||
assert list(manifest["components"]["schemas"]) == [
|
||||
"AlphaResult",
|
||||
"FreeJson",
|
||||
"ZetaResult",
|
||||
]
|
||||
assert list(manifest["components"]["errors"]) == ["5000"]
|
||||
|
||||
|
||||
def test_preserves_parameter_order_optionality_and_nullability() -> None:
|
||||
operation = manifest_from_openrpc(synthetic_openrpc_document())["operations"][0]
|
||||
|
||||
assert [parameter["name"] for parameter in operation["params"]] == [
|
||||
"optional_nullable",
|
||||
"required_closed",
|
||||
]
|
||||
assert operation["params"][0]["required"] is False
|
||||
assert operation["params"][0]["schema"]["anyOf"] == [
|
||||
{"type": "string"},
|
||||
{"type": "null"},
|
||||
]
|
||||
assert operation["params"][1]["required"] is True
|
||||
assert operation["params"][1]["schema"]["additionalProperties"] is False
|
||||
|
||||
|
||||
def test_removes_only_titles_and_preserves_unknown_schema_keywords() -> None:
|
||||
manifest = manifest_from_openrpc(synthetic_openrpc_document())
|
||||
optional_schema = manifest["operations"][0]["params"][0]["schema"]
|
||||
|
||||
assert "title" not in optional_schema
|
||||
assert optional_schema["x-future-keyword"] == {"value": 1}
|
||||
assert manifest["components"]["schemas"]["FreeJson"] == {}
|
||||
assert manifest["components"]["schemas"]["ZetaResult"]["properties"] == {
|
||||
"extension": {"additionalProperties": True}
|
||||
}
|
||||
|
||||
|
||||
def test_preserves_conditional_schema_keywords() -> None:
|
||||
alpha = manifest_from_openrpc(synthetic_openrpc_document())["components"]["schemas"][
|
||||
"AlphaResult"
|
||||
]
|
||||
|
||||
assert alpha["if"] == {"properties": {"mode": {"const": "alpha"}}}
|
||||
assert alpha["then"] == {"required": ["payload"]}
|
||||
assert alpha["not"] == {"required": ["forbidden"]}
|
||||
Reference in New Issue
Block a user