fix: opt draft storage into real callers
This commit is contained in:
@@ -131,7 +131,7 @@ def _artifact_api(
|
||||
)
|
||||
service.register_specs("demo.personal", echo_tool)
|
||||
context = context_from_service(service)
|
||||
return WorkflowArtifactApi(context), service
|
||||
return WorkflowArtifactApi(context, drafts=True), service
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@@ -454,7 +454,7 @@ def _api(root: Path) -> WorkflowApi:
|
||||
artifact_store=FileWorkflowArtifactStore(root),
|
||||
draft_workspace_store=FileDraftWorkspaceStore(mcp_root),
|
||||
)
|
||||
return WorkflowApi(context_from_service(service))
|
||||
return WorkflowApi(context_from_service(service), drafts=True)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -10,18 +10,30 @@ from wf_artifacts import (
|
||||
)
|
||||
|
||||
|
||||
def test_file_workflow_stores_constructs_all_three_file_stores(tmp_path: Path) -> None:
|
||||
def test_file_workflow_stores_skips_draft_store_by_default(tmp_path: Path) -> None:
|
||||
root = tmp_path / "wf_api_file_workflow_stores"
|
||||
|
||||
stores = file_workflow_stores(root)
|
||||
|
||||
assert isinstance(stores, WorkflowStores)
|
||||
assert isinstance(stores.artifact_store, FileWorkflowArtifactStore)
|
||||
assert isinstance(stores.draft_workspace_store, FileDraftWorkspaceStore)
|
||||
assert stores.draft_workspace_store is None
|
||||
assert isinstance(stores.run_store, FileRunStore)
|
||||
assert stores.artifact_store.root == root
|
||||
assert stores.draft_workspace_store.root == root
|
||||
assert stores.run_store.root == root
|
||||
assert not (root / "draft_workspaces").exists()
|
||||
|
||||
|
||||
def test_file_workflow_stores_constructs_draft_store_when_explicitly_enabled(
|
||||
tmp_path: Path,
|
||||
) -> None:
|
||||
root = tmp_path / "wf_api_file_workflow_stores_drafts"
|
||||
|
||||
stores = file_workflow_stores(root, drafts=True)
|
||||
|
||||
assert isinstance(stores.draft_workspace_store, FileDraftWorkspaceStore)
|
||||
assert stores.draft_workspace_store.root == root
|
||||
assert (root / "draft_workspaces").is_dir()
|
||||
|
||||
|
||||
def test_wf_api_exports_workflow_stores() -> None:
|
||||
|
||||
@@ -16,7 +16,6 @@ from wf_cli.context import (
|
||||
rpc_timeout_from_context,
|
||||
rpc_url_from_context,
|
||||
)
|
||||
from wf_server.config import build_workflow_server_from_workflow_config
|
||||
|
||||
from .conftest import write_python_source_config
|
||||
|
||||
@@ -104,7 +103,6 @@ def test_load_cli_context_builds_service_and_handlers(tmp_path: Path) -> None:
|
||||
|
||||
def test_load_cli_context_local_uses_workflow_store_override(
|
||||
tmp_path: Path,
|
||||
monkeypatch,
|
||||
) -> None:
|
||||
config_path = tmp_path / "wf.json"
|
||||
config_path.write_text(
|
||||
@@ -125,21 +123,15 @@ def test_load_cli_context_local_uses_workflow_store_override(
|
||||
),
|
||||
encoding="utf-8",
|
||||
)
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
def fake_build_workflow_server_from_workflow_config(config):
|
||||
captured["store_root"] = config.server.workflow_store.root
|
||||
return build_workflow_server_from_workflow_config(config)
|
||||
|
||||
monkeypatch.setattr(
|
||||
"wf_cli.context.build_workflow_server_from_workflow_config",
|
||||
fake_build_workflow_server_from_workflow_config,
|
||||
)
|
||||
|
||||
context = load_cli_context(config_path)
|
||||
|
||||
assert context.service is None
|
||||
assert captured["store_root"] == (tmp_path / ".workflow").resolve()
|
||||
assert isinstance(context.handlers, WorkflowApi)
|
||||
assert context.handlers.drafts_enabled is True
|
||||
assert (
|
||||
context.handlers.context.artifact_store.root
|
||||
== (tmp_path / ".workflow").resolve()
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -101,7 +101,7 @@ async def test_registered_output_bindings_tool_delegates_typed_bindings_once(
|
||||
recorder = RecordingWorkflowHandler()
|
||||
monkeypatch.setattr(
|
||||
"wf_mcp.workflow_surface.tools.WorkflowApi",
|
||||
lambda _context: recorder,
|
||||
lambda _context, **_kwargs: recorder,
|
||||
)
|
||||
service = WfMcpService(
|
||||
store=FileStore(tmp_path / "tool_invocation_store"),
|
||||
@@ -167,7 +167,7 @@ async def test_registered_workflow_output_bindings_tool_preserves_union_order(
|
||||
recorder = RecordingWorkflowHandler()
|
||||
monkeypatch.setattr(
|
||||
"wf_mcp.workflow_surface.tools.WorkflowApi",
|
||||
lambda _context: recorder,
|
||||
lambda _context, **_kwargs: recorder,
|
||||
)
|
||||
service = WfMcpService(
|
||||
store=FileStore(tmp_path / "workflow_output_tool_store"),
|
||||
@@ -242,7 +242,7 @@ async def test_registered_capability_tools_delegate_presence_aware_requests(
|
||||
recorder = RecordingWorkflowHandler()
|
||||
monkeypatch.setattr(
|
||||
"wf_mcp.workflow_surface.tools.WorkflowApi",
|
||||
lambda _context: recorder,
|
||||
lambda _context, **_kwargs: recorder,
|
||||
)
|
||||
service = WfMcpService(
|
||||
store=FileStore(tmp_path / "capability_tool_store"),
|
||||
|
||||
@@ -69,6 +69,8 @@ def test_workflow_server_from_service_wires_neutral_surfaces(tmp_path) -> None:
|
||||
assert isinstance(server, WorkflowServer)
|
||||
assert server.config.store_root == config.store_root
|
||||
assert server.api.context is server.context
|
||||
assert server.api.drafts_enabled is True
|
||||
assert server.api.drafts is not None
|
||||
assert server.source_registry_admin is not None
|
||||
assert server.admin.connections is service.connection_service
|
||||
assert server.admin.events is service.events
|
||||
|
||||
@@ -83,13 +83,15 @@ def test_rpc_server_cli_uses_configured_store_and_transport(
|
||||
)
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
def fake_build_server(config):
|
||||
def fake_build_server(config, *, drafts=False):
|
||||
captured["store_root"] = config.server.store.root
|
||||
captured["drafts"] = drafts
|
||||
return object()
|
||||
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc"):
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc", drafts=False):
|
||||
captured["server"] = server
|
||||
captured["rpc_path"] = rpc_path
|
||||
captured["drafts"] = drafts
|
||||
return object()
|
||||
|
||||
def fake_uvicorn_run(app_obj, *, host, port, access_log):
|
||||
@@ -110,6 +112,7 @@ def test_rpc_server_cli_uses_configured_store_and_transport(
|
||||
assert result.exit_code == 0, result.output
|
||||
assert captured["store_root"] == (tmp_path / ".wf_store").resolve()
|
||||
assert captured["rpc_path"] == "/workflow-rpc"
|
||||
assert captured["drafts"] is True
|
||||
assert captured["host"] == "127.0.0.2"
|
||||
assert captured["port"] == 9999
|
||||
assert captured["access_log"] is False
|
||||
@@ -132,9 +135,10 @@ def test_rpc_server_cli_uses_mcp_config_server(monkeypatch, tmp_path) -> None:
|
||||
captured["mcp_config_path"] = path
|
||||
return object()
|
||||
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc"):
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc", drafts=False):
|
||||
captured["server"] = server
|
||||
captured["rpc_path"] = rpc_path
|
||||
captured["drafts"] = drafts
|
||||
return object()
|
||||
|
||||
def fake_uvicorn_run(app_obj, *, host, port, access_log):
|
||||
@@ -207,9 +211,10 @@ def test_rpc_server_cli_mcp_config_builds_registry_capable_server(
|
||||
)
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc"):
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc", drafts=False):
|
||||
captured["source_registry_admin"] = server.source_registry_admin
|
||||
captured["rpc_path"] = rpc_path
|
||||
captured["drafts"] = drafts
|
||||
return object()
|
||||
|
||||
def fake_uvicorn_run(app_obj, *, host, port, access_log):
|
||||
@@ -263,9 +268,10 @@ def test_rpc_server_cli_mcp_config_with_config_uses_transport_settings(
|
||||
)
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc"):
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc", drafts=False):
|
||||
captured["server"] = server
|
||||
captured["rpc_path"] = rpc_path
|
||||
captured["drafts"] = drafts
|
||||
return object()
|
||||
|
||||
def fake_uvicorn_run(app_obj, *, host, port, access_log):
|
||||
@@ -299,13 +305,15 @@ def test_rpc_server_cli_config_with_mcp_source_uses_mcp_builder(
|
||||
) -> None:
|
||||
captured = {}
|
||||
|
||||
def fake_build_from_workflow_config(config):
|
||||
def fake_build_from_workflow_config(config, *, drafts=False):
|
||||
captured["source_kinds"] = [source.kind for source in config.server.sources]
|
||||
captured["build_drafts"] = drafts
|
||||
return object()
|
||||
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc"):
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc", drafts=False):
|
||||
captured["server"] = server
|
||||
captured["rpc_path"] = rpc_path
|
||||
captured["drafts"] = drafts
|
||||
return "app"
|
||||
|
||||
def fake_run(app, *, host, port, access_log):
|
||||
@@ -409,13 +417,15 @@ def test_rpc_server_cli_config_uses_workflow_store_override(
|
||||
)
|
||||
captured: dict[str, object] = {}
|
||||
|
||||
def fake_build_server(config):
|
||||
def fake_build_server(config, *, drafts=False):
|
||||
captured["workflow_store_root"] = config.server.workflow_store.root
|
||||
captured["build_drafts"] = drafts
|
||||
return object()
|
||||
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc"):
|
||||
def fake_create_rpc_app(server, *, rpc_path="/rpc", drafts=False):
|
||||
captured["server"] = server
|
||||
captured["rpc_path"] = rpc_path
|
||||
captured["drafts"] = drafts
|
||||
return object()
|
||||
|
||||
def fake_uvicorn_run(app_obj, *, host, port, access_log):
|
||||
|
||||
@@ -107,9 +107,7 @@ async def test_local_static_server_runs_deployment_and_persists_run(tmp_path) ->
|
||||
assert output["result"] == "hello from server"
|
||||
run_id = run_result["run_id"]
|
||||
assert isinstance(run_id, str)
|
||||
assert (
|
||||
server.stores.run_store.get_run(run_id).id == run_id
|
||||
)
|
||||
assert server.stores.run_store.get_run(run_id).id == run_id
|
||||
|
||||
|
||||
async def test_local_static_server_inspects_and_reads_bounded_trace(tmp_path) -> None:
|
||||
@@ -193,6 +191,28 @@ def test_local_static_server_has_no_source_registry_admin(tmp_path) -> None:
|
||||
assert server.source_registry_admin is None
|
||||
|
||||
|
||||
def test_local_static_server_default_composition_has_no_draft_store(tmp_path) -> None:
|
||||
root = tmp_path / "store"
|
||||
server = build_local_static_workflow_server(root)
|
||||
|
||||
assert server.stores.draft_workspace_store is None
|
||||
assert server.context.draft_workspace_store is None
|
||||
assert server.api.drafts_enabled is False
|
||||
assert not (root / "draft_workspaces").exists()
|
||||
|
||||
|
||||
def test_local_static_server_explicit_draft_composition_has_draft_store(
|
||||
tmp_path,
|
||||
) -> None:
|
||||
root = tmp_path / "store"
|
||||
server = build_local_static_workflow_server(root, drafts=True)
|
||||
|
||||
assert server.stores.draft_workspace_store is not None
|
||||
assert server.context.draft_workspace_store is server.stores.draft_workspace_store
|
||||
assert server.api.drafts_enabled is True
|
||||
assert (root / "draft_workspaces").is_dir()
|
||||
|
||||
|
||||
def test_local_static_builtins_are_platform_sources(tmp_path) -> None:
|
||||
server = build_local_static_workflow_server(tmp_path)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
@@ -21,6 +22,33 @@ from wf_transport_rpc_http.models import (
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _draft_enabled_composition(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Opt draft-focused RPC tests into the otherwise disabled composition."""
|
||||
build_local = build_local_static_workflow_server
|
||||
build_config = build_workflow_server_from_workflow_config
|
||||
create_app = create_rpc_app
|
||||
|
||||
def draft_local(root, *args, **kwargs):
|
||||
kwargs.setdefault("drafts", True)
|
||||
return build_local(root, *args, **kwargs)
|
||||
|
||||
def draft_config(config, *args, **kwargs):
|
||||
kwargs.setdefault("drafts", True)
|
||||
return build_config(config, *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, "build_workflow_server_from_workflow_config", draft_config
|
||||
)
|
||||
monkeypatch.setattr(module, "create_rpc_app", draft_app)
|
||||
|
||||
|
||||
async def _rpc(
|
||||
client: httpx.AsyncClient, method: str, params: dict[str, Any]
|
||||
) -> dict[str, Any]:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import httpx
|
||||
@@ -31,6 +32,25 @@ 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(
|
||||
|
||||
@@ -31,7 +31,12 @@ def _assert_result_component(
|
||||
|
||||
@pytest.fixture
|
||||
def openrpc_document(tmp_path: Path) -> dict[str, Any]:
|
||||
app = create_rpc_app(build_local_static_workflow_server(tmp_path / "store"))
|
||||
# This fixture inventories the complete RPC contract, including the
|
||||
# explicitly opt-in draft methods.
|
||||
app = create_rpc_app(
|
||||
build_local_static_workflow_server(tmp_path / "store", drafts=True),
|
||||
drafts=True,
|
||||
)
|
||||
return app.get_openrpc()
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user