fix: harden Python workflow client boundary
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
@@ -32,25 +31,6 @@ from wf_transport_rpc_http.client.drafts import RpcDraftClientMixin
|
||||
from wf_transport_rpc_http.client.sources import RpcSourceAdminClientMixin
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _draft_enabled_composition(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Opt draft-focused RPC client tests into the explicit draft surface."""
|
||||
build_local = build_local_static_workflow_server
|
||||
create_app = create_rpc_app
|
||||
|
||||
def draft_local(root, *args, **kwargs):
|
||||
kwargs.setdefault("drafts", True)
|
||||
return build_local(root, *args, **kwargs)
|
||||
|
||||
def draft_app(server, *args, **kwargs):
|
||||
kwargs.setdefault("drafts", True)
|
||||
return create_app(server, *args, **kwargs)
|
||||
|
||||
module = sys.modules[__name__]
|
||||
monkeypatch.setattr(module, "build_local_static_workflow_server", draft_local)
|
||||
monkeypatch.setattr(module, "create_rpc_app", draft_app)
|
||||
|
||||
|
||||
async def test_rpc_client_preserves_structured_jsonrpc_error() -> None:
|
||||
def handler(request: httpx.Request) -> httpx.Response:
|
||||
return httpx.Response(
|
||||
@@ -354,8 +334,8 @@ async def test_rpc_workflow_client_lists_inspects_validates_and_deletes_deployme
|
||||
|
||||
|
||||
async def test_rpc_workflow_client_draft_workspace_lifecycle(tmp_path) -> None:
|
||||
server = build_local_static_workflow_server(tmp_path / "store")
|
||||
app = create_rpc_app(server)
|
||||
server = build_local_static_workflow_server(tmp_path / "store", drafts=True)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(
|
||||
transport=transport, base_url="http://test"
|
||||
@@ -550,8 +530,8 @@ async def test_rpc_client_sends_exact_replace_document_payload() -> None:
|
||||
|
||||
|
||||
async def test_rpc_client_builds_capability_free_draft_lifecycle(tmp_path) -> None:
|
||||
server = build_local_static_workflow_server(tmp_path / "store")
|
||||
app = create_rpc_app(server)
|
||||
server = build_local_static_workflow_server(tmp_path / "store", drafts=True)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(
|
||||
transport=transport,
|
||||
@@ -625,8 +605,8 @@ def test_rpc_client_satisfies_draft_surface_static_shape() -> None:
|
||||
|
||||
|
||||
async def test_rpc_workflow_client_deletes_draft_workspace(tmp_path) -> None:
|
||||
server = build_local_static_workflow_server(tmp_path / "store")
|
||||
app = create_rpc_app(server)
|
||||
server = build_local_static_workflow_server(tmp_path / "store", drafts=True)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(
|
||||
transport=transport, base_url="http://test"
|
||||
@@ -772,8 +752,8 @@ async def test_rpc_client_validates_artifact_plan_without_persisting(tmp_path) -
|
||||
|
||||
|
||||
async def test_rpc_client_set_workflow_output_map(tmp_path) -> None:
|
||||
server = build_local_static_workflow_server(tmp_path / "store")
|
||||
app = create_rpc_app(server)
|
||||
server = build_local_static_workflow_server(tmp_path / "store", drafts=True)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(
|
||||
transport=transport, base_url="http://test"
|
||||
@@ -807,8 +787,8 @@ async def test_rpc_client_set_workflow_output_map(tmp_path) -> None:
|
||||
|
||||
|
||||
async def test_rpc_client_draft_workspace_focused_edit_methods(tmp_path) -> None:
|
||||
server = build_local_static_workflow_server(tmp_path / "store")
|
||||
app = create_rpc_app(server)
|
||||
server = build_local_static_workflow_server(tmp_path / "store", drafts=True)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(
|
||||
transport=transport, base_url="http://test"
|
||||
@@ -1069,8 +1049,8 @@ async def test_rpc_client_draft_remove_methods(tmp_path) -> None:
|
||||
|
||||
|
||||
async def test_rpc_client_draft_workspace_add_step_from_capability(tmp_path) -> None:
|
||||
server = build_local_static_workflow_server(tmp_path / "store")
|
||||
app = create_rpc_app(server)
|
||||
server = build_local_static_workflow_server(tmp_path / "store", drafts=True)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
async with httpx.AsyncClient(
|
||||
transport=transport, base_url="http://test"
|
||||
|
||||
@@ -200,7 +200,7 @@ def _runtime_reuse_server(
|
||||
],
|
||||
)
|
||||
store_roots = config.store_roots
|
||||
workflow_stores = file_workflow_stores(store_roots.workflow_root)
|
||||
workflow_stores = file_workflow_stores(store_roots.workflow_root, drafts=True)
|
||||
auth_store = FileAuthStore(store_roots.auth_root)
|
||||
catalog_store = FileCatalogStore(store_roots.catalog_cache_root)
|
||||
factory = _RecordingSessionFactory()
|
||||
@@ -232,7 +232,7 @@ async def test_mcp_backed_rpc_lists_and_mutates_source_registry(tmp_path) -> Non
|
||||
SourceRegistryFile(sources=[_registry_entry("demo.registry")])
|
||||
)
|
||||
server = build_workflow_server_from_config(config)
|
||||
app = create_rpc_app(server)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
@@ -255,7 +255,7 @@ async def test_mcp_backed_rpc_lists_and_mutates_source_registry(tmp_path) -> Non
|
||||
async def test_mcp_backed_rpc_capability_list_filters_by_source(tmp_path) -> None:
|
||||
config = BrokerConfig(store_root=tmp_path / "store", connections=[])
|
||||
server = build_workflow_server_from_config(config)
|
||||
app = create_rpc_app(server)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
@@ -285,7 +285,7 @@ async def test_mcp_backed_rpc_reports_connections_and_events(tmp_path) -> None:
|
||||
],
|
||||
)
|
||||
server = build_workflow_server_from_config(config)
|
||||
app = create_rpc_app(server)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
@@ -299,7 +299,7 @@ async def test_mcp_backed_rpc_reports_connections_and_events(tmp_path) -> None:
|
||||
async def test_mcp_backed_rpc_applies_source_registry_changes(tmp_path) -> None:
|
||||
config = BrokerConfig(store_root=tmp_path / "store", connections=[])
|
||||
server = build_workflow_server_from_config(config)
|
||||
app = create_rpc_app(server)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=app),
|
||||
@@ -368,7 +368,7 @@ async def test_mcp_backed_rpc_can_be_built_from_neutral_workflow_config(
|
||||
}
|
||||
)
|
||||
server = build_workflow_server_from_workflow_config(workflow_config)
|
||||
app = create_rpc_app(server)
|
||||
app = create_rpc_app(server, drafts=True)
|
||||
transport = httpx.ASGITransport(app=app)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
@@ -408,7 +408,7 @@ async def test_mcp_backed_rpc_resumes_interrupted_run_after_server_rebuild(
|
||||
}
|
||||
)
|
||||
async with httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(first_server)),
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(first_server, drafts=True)),
|
||||
base_url="http://test",
|
||||
) as http_client:
|
||||
first_client = RpcWorkflowApiClient(
|
||||
@@ -433,7 +433,7 @@ async def test_mcp_backed_rpc_resumes_interrupted_run_after_server_rebuild(
|
||||
|
||||
rebuilt_server = build_workflow_server_from_workflow_config(workflow_config)
|
||||
async with httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(rebuilt_server)),
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(rebuilt_server, drafts=True)),
|
||||
base_url="http://test",
|
||||
) as http_client:
|
||||
rebuilt_client = RpcWorkflowApiClient(
|
||||
@@ -463,7 +463,7 @@ async def test_mcp_backed_rpc_workflow_reuses_runtime_session_across_runs(
|
||||
assert factory.created_connections[0].id == "fixture.default"
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(server)),
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(server, drafts=True)),
|
||||
base_url="http://test",
|
||||
) as http_client:
|
||||
client = RpcWorkflowApiClient(url="http://test/rpc", http_client=http_client)
|
||||
@@ -597,7 +597,7 @@ async def test_mcp_backed_rpc_workflow_reuses_runtime_session_direct_setup(
|
||||
)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(server)),
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(server, drafts=True)),
|
||||
base_url="http://test",
|
||||
) as http_client:
|
||||
client = RpcWorkflowApiClient(url="http://test/rpc", http_client=http_client)
|
||||
@@ -696,7 +696,7 @@ async def test_mcp_backed_rpc_deployment_becomes_unrunnable_after_source_removed
|
||||
)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(server)),
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(server, drafts=True)),
|
||||
base_url="http://test",
|
||||
) as http_client:
|
||||
client = RpcWorkflowApiClient(url="http://test/rpc", http_client=http_client)
|
||||
@@ -748,7 +748,7 @@ async def test_mcp_backed_rpc_workflow_reuses_real_stdio_fixture_session(
|
||||
)
|
||||
|
||||
async with httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(server)),
|
||||
transport=httpx.ASGITransport(app=create_rpc_app(server, drafts=True)),
|
||||
base_url="http://test",
|
||||
) as http_client:
|
||||
client = RpcWorkflowApiClient(url="http://test/rpc", http_client=http_client)
|
||||
|
||||
Reference in New Issue
Block a user