test: isolate file stores with tmp_path
This commit is contained in:
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from dataclasses import replace
|
from dataclasses import replace
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from wf_artifacts import (
|
from wf_artifacts import (
|
||||||
@@ -19,7 +20,7 @@ from wf_mcp.storage import FileStore
|
|||||||
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
||||||
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
||||||
|
|
||||||
from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
from tests.wf_mcp.test_support import echo_tool
|
||||||
|
|
||||||
|
|
||||||
def _echo_draft() -> dict[str, Any]:
|
def _echo_draft() -> dict[str, Any]:
|
||||||
@@ -131,8 +132,8 @@ def _artifact_api(
|
|||||||
return WorkflowArtifactApi(context), service
|
return WorkflowArtifactApi(context), service
|
||||||
|
|
||||||
|
|
||||||
def test_save_artifact_stores_and_returns_saved() -> None:
|
def test_save_artifact_stores_and_returns_saved(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "artifacts_save")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "artifacts_save")
|
||||||
api, _service = _artifact_api(artifact_store)
|
api, _service = _artifact_api(artifact_store)
|
||||||
|
|
||||||
result = asyncio.run(api.save_artifact(_echo_artifact().model_dump(mode="json")))
|
result = asyncio.run(api.save_artifact(_echo_artifact().model_dump(mode="json")))
|
||||||
@@ -144,8 +145,8 @@ def test_save_artifact_stores_and_returns_saved() -> None:
|
|||||||
assert saved.id == "echo"
|
assert saved.id == "echo"
|
||||||
|
|
||||||
|
|
||||||
def test_list_artifacts_returns_empty_page_without_artifact_store() -> None:
|
def test_list_artifacts_returns_empty_page_without_artifact_store(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "artifacts_no_store")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "artifacts_no_store")
|
||||||
_api, service = _artifact_api(artifact_store)
|
_api, service = _artifact_api(artifact_store)
|
||||||
context = replace(context_from_service(service), artifact_store=None)
|
context = replace(context_from_service(service), artifact_store=None)
|
||||||
api = WorkflowArtifactApi(context)
|
api = WorkflowArtifactApi(context)
|
||||||
@@ -157,9 +158,9 @@ def test_list_artifacts_returns_empty_page_without_artifact_store() -> None:
|
|||||||
assert result["total"] == 0
|
assert result["total"] == 0
|
||||||
|
|
||||||
|
|
||||||
def test_create_artifact_from_plan_saves_with_observed_node_specs() -> None:
|
def test_create_artifact_from_plan_saves_with_observed_node_specs(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "artifacts_from_plan"
|
tmp_path / "artifacts_from_plan"
|
||||||
)
|
)
|
||||||
api, _service = _artifact_api(artifact_store, register_echo=True)
|
api, _service = _artifact_api(artifact_store, register_echo=True)
|
||||||
|
|
||||||
@@ -179,9 +180,9 @@ def test_create_artifact_from_plan_saves_with_observed_node_specs() -> None:
|
|||||||
assert saved.id == "echo"
|
assert saved.id == "echo"
|
||||||
|
|
||||||
|
|
||||||
def test_create_artifact_from_workspace_returns_saved_false_when_invalid() -> None:
|
def test_create_artifact_from_workspace_returns_saved_false_when_invalid(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "artifacts_workspace_invalid"
|
tmp_path / "artifacts_workspace_invalid"
|
||||||
)
|
)
|
||||||
api, service = _artifact_api(artifact_store, register_echo=True)
|
api, service = _artifact_api(artifact_store, register_echo=True)
|
||||||
draft = _echo_draft()
|
draft = _echo_draft()
|
||||||
@@ -211,9 +212,9 @@ def test_create_artifact_from_workspace_returns_saved_false_when_invalid() -> No
|
|||||||
assert result["status"] == "invalid"
|
assert result["status"] == "invalid"
|
||||||
|
|
||||||
|
|
||||||
def test_create_wrapper_from_workspace_saves_kind_wrapper() -> None:
|
def test_create_wrapper_from_workspace_saves_kind_wrapper(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "artifacts_wrapper_workspace"
|
tmp_path / "artifacts_wrapper_workspace"
|
||||||
)
|
)
|
||||||
api, service = _artifact_api(artifact_store, register_echo=True)
|
api, service = _artifact_api(artifact_store, register_echo=True)
|
||||||
from wf_api.drafts import WorkflowDraftApi
|
from wf_api.drafts import WorkflowDraftApi
|
||||||
@@ -242,8 +243,8 @@ def test_create_wrapper_from_workspace_saves_kind_wrapper() -> None:
|
|||||||
assert saved.kind == "wrapper"
|
assert saved.kind == "wrapper"
|
||||||
|
|
||||||
|
|
||||||
def test_inspect_artifact_returns_stable_fields() -> None:
|
def test_inspect_artifact_returns_stable_fields(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "artifacts_inspect")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "artifacts_inspect")
|
||||||
api, _service = _artifact_api(artifact_store)
|
api, _service = _artifact_api(artifact_store)
|
||||||
artifact_store.save_artifact(_echo_artifact())
|
artifact_store.save_artifact(_echo_artifact())
|
||||||
|
|
||||||
@@ -255,10 +256,10 @@ def test_inspect_artifact_returns_stable_fields() -> None:
|
|||||||
assert "plan" in result
|
assert "plan" in result
|
||||||
|
|
||||||
|
|
||||||
def test_handler_delegation_for_inspect_artifact() -> None:
|
def test_handler_delegation_for_inspect_artifact(tmp_path: Path) -> None:
|
||||||
"""WorkflowSurfaceHandlers.inspect_artifact delegates to WorkflowArtifactApi."""
|
"""WorkflowSurfaceHandlers.inspect_artifact delegates to WorkflowArtifactApi."""
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "artifacts_delegation"
|
tmp_path / "artifacts_delegation"
|
||||||
)
|
)
|
||||||
mcp_root = artifact_store.root / "delegation_mcp"
|
mcp_root = artifact_store.root / "delegation_mcp"
|
||||||
service = WfMcpService(
|
service = WfMcpService(
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from wf_api.artifact_plans import plan_field, plan_nodes, raw_plan_from_artifact
|
from wf_api.artifact_plans import plan_field, plan_nodes, raw_plan_from_artifact
|
||||||
@@ -63,15 +65,15 @@ def test_required_capability_payloads_sorts_by_name() -> None:
|
|||||||
assert "kind" in first
|
assert "kind" in first
|
||||||
|
|
||||||
|
|
||||||
def test_observed_node_specs_projects_enabled_context_specs() -> None:
|
def test_observed_node_specs_projects_enabled_context_specs(tmp_path: Path) -> None:
|
||||||
from wf_artifacts import FileWorkflowArtifactStore
|
from wf_artifacts import FileWorkflowArtifactStore
|
||||||
from wf_mcp.broker import WfMcpService
|
from wf_mcp.broker import WfMcpService
|
||||||
from wf_mcp.models import ConnectionConfig
|
from wf_mcp.models import ConnectionConfig
|
||||||
from wf_mcp.storage import FileStore
|
from wf_mcp.storage import FileStore
|
||||||
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
||||||
from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
from tests.wf_mcp.test_support import echo_tool
|
||||||
|
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "cap_req_helpers")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_req_helpers")
|
||||||
service = WfMcpService(
|
service = WfMcpService(
|
||||||
store=FileStore(artifact_store.root / "mcp"),
|
store=FileStore(artifact_store.root / "mcp"),
|
||||||
artifact_store=artifact_store,
|
artifact_store=artifact_store,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ from wf_mcp.storage import FileStore
|
|||||||
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
||||||
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
||||||
|
|
||||||
from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
from tests.wf_mcp.test_support import echo_tool
|
||||||
from tests.wf_mcp.workflow_surface.conftest import echo_artifact, failing_tool
|
from tests.wf_mcp.workflow_surface.conftest import echo_artifact, failing_tool
|
||||||
|
|
||||||
|
|
||||||
@@ -42,8 +43,8 @@ def _capability_api(
|
|||||||
return WorkflowCapabilityApi(context), service
|
return WorkflowCapabilityApi(context), service
|
||||||
|
|
||||||
|
|
||||||
def test_list_capabilities_returns_planner_visible_sources() -> None:
|
def test_list_capabilities_returns_planner_visible_sources(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "cap_api_list")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_list")
|
||||||
api, _service = _capability_api(artifact_store, register_echo=True)
|
api, _service = _capability_api(artifact_store, register_echo=True)
|
||||||
|
|
||||||
result = asyncio.run(api.list_capabilities())
|
result = asyncio.run(api.list_capabilities())
|
||||||
@@ -62,9 +63,9 @@ def test_list_capabilities_returns_planner_visible_sources() -> None:
|
|||||||
assert "output_fields" in first
|
assert "output_fields" in first
|
||||||
|
|
||||||
|
|
||||||
def test_list_capabilities_filters_by_source() -> None:
|
def test_list_capabilities_filters_by_source(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "cap_api_list_filter"
|
tmp_path / "cap_api_list_filter"
|
||||||
)
|
)
|
||||||
api, _service = _capability_api(artifact_store, register_echo=True)
|
api, _service = _capability_api(artifact_store, register_echo=True)
|
||||||
|
|
||||||
@@ -73,8 +74,8 @@ def test_list_capabilities_filters_by_source() -> None:
|
|||||||
assert [item["name"] for item in result["capabilities"]] == ["wf.std.truthy"]
|
assert [item["name"] for item in result["capabilities"]] == ["wf.std.truthy"]
|
||||||
|
|
||||||
|
|
||||||
def test_inspect_capability_returns_detail_with_wrapper_hints() -> None:
|
def test_inspect_capability_returns_detail_with_wrapper_hints(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "cap_api_inspect")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_inspect")
|
||||||
api, _service = _capability_api(artifact_store, register_echo=True)
|
api, _service = _capability_api(artifact_store, register_echo=True)
|
||||||
|
|
||||||
detail = asyncio.run(
|
detail = asyncio.run(
|
||||||
@@ -89,9 +90,9 @@ def test_inspect_capability_returns_detail_with_wrapper_hints() -> None:
|
|||||||
assert hints["output_map"] == {"echoed": "state.echoed"}
|
assert hints["output_map"] == {"echoed": "state.echoed"}
|
||||||
|
|
||||||
|
|
||||||
def test_inspect_capability_raises_on_unknown() -> None:
|
def test_inspect_capability_raises_on_unknown(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "cap_api_inspect_unknown"
|
tmp_path / "cap_api_inspect_unknown"
|
||||||
)
|
)
|
||||||
api, _service = _capability_api(artifact_store, register_echo=True)
|
api, _service = _capability_api(artifact_store, register_echo=True)
|
||||||
|
|
||||||
@@ -99,8 +100,8 @@ def test_inspect_capability_raises_on_unknown() -> None:
|
|||||||
asyncio.run(api.inspect_capability(qualified_name="no.such.capability"))
|
asyncio.run(api.inspect_capability(qualified_name="no.such.capability"))
|
||||||
|
|
||||||
|
|
||||||
def test_call_capability_node_spec_success() -> None:
|
def test_call_capability_node_spec_success(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "cap_api_call")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_call")
|
||||||
api, _service = _capability_api(artifact_store, register_echo=True)
|
api, _service = _capability_api(artifact_store, register_echo=True)
|
||||||
|
|
||||||
result = asyncio.run(
|
result = asyncio.run(
|
||||||
@@ -117,8 +118,8 @@ def test_call_capability_node_spec_success() -> None:
|
|||||||
assert result["deployment_id"] is None
|
assert result["deployment_id"] is None
|
||||||
|
|
||||||
|
|
||||||
def test_call_capability_node_spec_failure() -> None:
|
def test_call_capability_node_spec_failure(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "cap_api_call_fail")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_call_fail")
|
||||||
api, _service = _capability_api(artifact_store, register_failing=True)
|
api, _service = _capability_api(artifact_store, register_failing=True)
|
||||||
|
|
||||||
result = asyncio.run(
|
result = asyncio.run(
|
||||||
@@ -134,9 +135,9 @@ def test_call_capability_node_spec_failure() -> None:
|
|||||||
assert result["diagnostics"][0]["code"] == "capability_call_failed"
|
assert result["diagnostics"][0]["code"] == "capability_call_failed"
|
||||||
|
|
||||||
|
|
||||||
def test_list_capabilities_includes_saved_wrapper() -> None:
|
def test_list_capabilities_includes_saved_wrapper(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "cap_api_wrapper_list"
|
tmp_path / "cap_api_wrapper_list"
|
||||||
)
|
)
|
||||||
artifact_store.save_artifact(
|
artifact_store.save_artifact(
|
||||||
echo_artifact().model_copy(
|
echo_artifact().model_copy(
|
||||||
@@ -165,9 +166,9 @@ def test_list_capabilities_includes_saved_wrapper() -> None:
|
|||||||
assert row["output_fields"] == ["echoed"]
|
assert row["output_fields"] == ["echoed"]
|
||||||
|
|
||||||
|
|
||||||
def test_inspect_capability_saved_wrapper() -> None:
|
def test_inspect_capability_saved_wrapper(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "cap_api_wrapper_inspect"
|
tmp_path / "cap_api_wrapper_inspect"
|
||||||
)
|
)
|
||||||
artifact_store.save_artifact(
|
artifact_store.save_artifact(
|
||||||
echo_artifact().model_copy(update={"id": "echo_wrapper", "kind": "wrapper"})
|
echo_artifact().model_copy(update={"id": "echo_wrapper", "kind": "wrapper"})
|
||||||
@@ -194,9 +195,9 @@ def test_inspect_capability_saved_wrapper() -> None:
|
|||||||
assert hints["output_map"] == {"echoed": "state.echoed"}
|
assert hints["output_map"] == {"echoed": "state.echoed"}
|
||||||
|
|
||||||
|
|
||||||
def test_call_capability_saved_wrapper() -> None:
|
def test_call_capability_saved_wrapper(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "cap_api_wrapper_call"
|
tmp_path / "cap_api_wrapper_call"
|
||||||
)
|
)
|
||||||
artifact_store.save_artifact(
|
artifact_store.save_artifact(
|
||||||
echo_artifact().model_copy(update={"id": "echo_wrapper", "kind": "wrapper"})
|
echo_artifact().model_copy(update={"id": "echo_wrapper", "kind": "wrapper"})
|
||||||
@@ -215,9 +216,9 @@ def test_call_capability_saved_wrapper() -> None:
|
|||||||
assert result["diagnostics"] == []
|
assert result["diagnostics"] == []
|
||||||
|
|
||||||
|
|
||||||
def test_create_draft_workspace_from_capability() -> None:
|
def test_create_draft_workspace_from_capability(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "cap_api_draft_bootstrap"
|
tmp_path / "cap_api_draft_bootstrap"
|
||||||
)
|
)
|
||||||
api, _service = _capability_api(artifact_store, register_echo=True)
|
api, _service = _capability_api(artifact_store, register_echo=True)
|
||||||
|
|
||||||
@@ -240,9 +241,9 @@ def test_create_draft_workspace_from_capability() -> None:
|
|||||||
assert fetched["draft"]["steps"]["call"]["use"] == "demo.personal.echo_tool"
|
assert fetched["draft"]["steps"]["call"]["use"] == "demo.personal.echo_tool"
|
||||||
|
|
||||||
|
|
||||||
def test_handler_delegates_to_capability_api() -> None:
|
def test_handler_delegates_to_capability_api(tmp_path: Path) -> None:
|
||||||
"""WorkflowSurfaceHandlers methods produce the same result as direct API."""
|
"""WorkflowSurfaceHandlers methods produce the same result as direct API."""
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "cap_api_delegation")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "cap_api_delegation")
|
||||||
mcp_root = artifact_store.root / "delegation_mcp"
|
mcp_root = artifact_store.root / "delegation_mcp"
|
||||||
service = WfMcpService(
|
service = WfMcpService(
|
||||||
store=FileStore(mcp_root),
|
store=FileStore(mcp_root),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from dataclasses import replace
|
from dataclasses import replace
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
from wf_artifacts import (
|
from wf_artifacts import (
|
||||||
@@ -21,7 +22,7 @@ from wf_mcp.storage import FileStore
|
|||||||
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
||||||
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
||||||
|
|
||||||
from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
from tests.wf_mcp.test_support import echo_tool
|
||||||
|
|
||||||
|
|
||||||
def _echo_artifact() -> WorkflowArtifact:
|
def _echo_artifact() -> WorkflowArtifact:
|
||||||
@@ -97,8 +98,8 @@ def _deployment_api(
|
|||||||
return WorkflowDeploymentApi(context), service
|
return WorkflowDeploymentApi(context), service
|
||||||
|
|
||||||
|
|
||||||
def test_save_deployment_stores_and_returns_stable_fields() -> None:
|
def test_save_deployment_stores_and_returns_stable_fields(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "deploy_save")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_save")
|
||||||
api, _service = _deployment_api(artifact_store)
|
api, _service = _deployment_api(artifact_store)
|
||||||
|
|
||||||
result = asyncio.run(
|
result = asyncio.run(
|
||||||
@@ -120,8 +121,8 @@ def test_save_deployment_stores_and_returns_stable_fields() -> None:
|
|||||||
assert result["artifact_version"] == 1
|
assert result["artifact_version"] == 1
|
||||||
|
|
||||||
|
|
||||||
def test_list_deployments_returns_compact_summaries() -> None:
|
def test_list_deployments_returns_compact_summaries(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "deploy_list")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_list")
|
||||||
api, _service = _deployment_api(artifact_store)
|
api, _service = _deployment_api(artifact_store)
|
||||||
artifact_store.save_deployment(
|
artifact_store.save_deployment(
|
||||||
WorkflowDeployment(
|
WorkflowDeployment(
|
||||||
@@ -140,8 +141,8 @@ def test_list_deployments_returns_compact_summaries() -> None:
|
|||||||
assert "bindings" not in result["deployments"][0]
|
assert "bindings" not in result["deployments"][0]
|
||||||
|
|
||||||
|
|
||||||
def test_list_deployments_returns_empty_without_artifact_store() -> None:
|
def test_list_deployments_returns_empty_without_artifact_store(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "deploy_no_store")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_no_store")
|
||||||
_api, service = _deployment_api(artifact_store)
|
_api, service = _deployment_api(artifact_store)
|
||||||
context = replace(context_from_service(service), artifact_store=None)
|
context = replace(context_from_service(service), artifact_store=None)
|
||||||
api = WorkflowDeploymentApi(context)
|
api = WorkflowDeploymentApi(context)
|
||||||
@@ -151,8 +152,8 @@ def test_list_deployments_returns_empty_without_artifact_store() -> None:
|
|||||||
assert result["deployments"] == []
|
assert result["deployments"] == []
|
||||||
|
|
||||||
|
|
||||||
def test_delete_deployment_removes_one() -> None:
|
def test_delete_deployment_removes_one(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "deploy_delete")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_delete")
|
||||||
api, _service = _deployment_api(artifact_store)
|
api, _service = _deployment_api(artifact_store)
|
||||||
artifact_store.save_deployment(
|
artifact_store.save_deployment(
|
||||||
WorkflowDeployment(
|
WorkflowDeployment(
|
||||||
@@ -170,9 +171,9 @@ def test_delete_deployment_removes_one() -> None:
|
|||||||
assert artifact_store.list_deployments() == []
|
assert artifact_store.list_deployments() == []
|
||||||
|
|
||||||
|
|
||||||
def test_validate_deployment_returns_runnable_for_valid_binding() -> None:
|
def test_validate_deployment_returns_runnable_for_valid_binding(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "deploy_validate_runnable"
|
tmp_path / "deploy_validate_runnable"
|
||||||
)
|
)
|
||||||
api, service = _deployment_api(artifact_store, register_echo=True)
|
api, service = _deployment_api(artifact_store, register_echo=True)
|
||||||
artifact_store.save_artifact(_echo_artifact())
|
artifact_store.save_artifact(_echo_artifact())
|
||||||
@@ -202,9 +203,9 @@ class FailingLivenessAdapter:
|
|||||||
raise OSError("stdio process exited")
|
raise OSError("stdio process exited")
|
||||||
|
|
||||||
|
|
||||||
def test_validate_deployment_live_check_calls_live_checker() -> None:
|
def test_validate_deployment_live_check_calls_live_checker(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "deploy_validate_live"
|
tmp_path / "deploy_validate_live"
|
||||||
)
|
)
|
||||||
api, service = _deployment_api(artifact_store, register_echo=True)
|
api, service = _deployment_api(artifact_store, register_echo=True)
|
||||||
artifact_store.save_artifact(_echo_artifact())
|
artifact_store.save_artifact(_echo_artifact())
|
||||||
@@ -229,9 +230,9 @@ def test_validate_deployment_live_check_calls_live_checker() -> None:
|
|||||||
assert result["diagnostics"][0]["code"] == "source_unreachable"
|
assert result["diagnostics"][0]["code"] == "source_unreachable"
|
||||||
|
|
||||||
|
|
||||||
def test_handler_delegation_for_validate_deployment() -> None:
|
def test_handler_delegation_for_validate_deployment(tmp_path: Path) -> None:
|
||||||
"""WorkflowSurfaceHandlers.validate_deployment delegates to WorkflowDeploymentApi."""
|
"""WorkflowSurfaceHandlers.validate_deployment delegates to WorkflowDeploymentApi."""
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "deploy_delegation")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "deploy_delegation")
|
||||||
service = WfMcpService(
|
service = WfMcpService(
|
||||||
store=FileStore(artifact_store.root / "delegation_mcp"),
|
store=FileStore(artifact_store.root / "delegation_mcp"),
|
||||||
artifact_store=artifact_store,
|
artifact_store=artifact_store,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from wf_artifacts import FileWorkflowArtifactStore
|
from wf_artifacts import FileWorkflowArtifactStore
|
||||||
from wf_api import WorkflowApi
|
from wf_api import WorkflowApi
|
||||||
@@ -14,11 +15,10 @@ from wf_mcp.broker.service.workflow_operation_context import context_from_servic
|
|||||||
from wf_mcp.models import ConnectionConfig
|
from wf_mcp.models import ConnectionConfig
|
||||||
from wf_mcp.storage import FileStore
|
from wf_mcp.storage import FileStore
|
||||||
|
|
||||||
from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
from tests.wf_mcp.test_support import echo_tool
|
||||||
|
|
||||||
|
|
||||||
def _api() -> WorkflowApi:
|
def _api(root: Path) -> WorkflowApi:
|
||||||
root = local_temp_root() / "wf_api_direct_composition"
|
|
||||||
service = WfMcpService(
|
service = WfMcpService(
|
||||||
store=FileStore(root / "mcp"),
|
store=FileStore(root / "mcp"),
|
||||||
artifact_store=FileWorkflowArtifactStore(root),
|
artifact_store=FileWorkflowArtifactStore(root),
|
||||||
@@ -30,8 +30,8 @@ def _api() -> WorkflowApi:
|
|||||||
return WorkflowApi(context_from_service(service))
|
return WorkflowApi(context_from_service(service))
|
||||||
|
|
||||||
|
|
||||||
def test_workflow_api_composes_domain_services() -> None:
|
def test_workflow_api_composes_domain_services(tmp_path: Path) -> None:
|
||||||
api = _api()
|
api = _api(tmp_path / "wf_api_direct_composition")
|
||||||
|
|
||||||
assert isinstance(api.capabilities, WorkflowCapabilityApi)
|
assert isinstance(api.capabilities, WorkflowCapabilityApi)
|
||||||
assert isinstance(api.drafts, WorkflowDraftApi)
|
assert isinstance(api.drafts, WorkflowDraftApi)
|
||||||
@@ -41,8 +41,8 @@ def test_workflow_api_composes_domain_services() -> None:
|
|||||||
assert not hasattr(api, "backend")
|
assert not hasattr(api, "backend")
|
||||||
|
|
||||||
|
|
||||||
def test_workflow_api_direct_capability_call() -> None:
|
def test_workflow_api_direct_capability_call(tmp_path: Path) -> None:
|
||||||
api = _api()
|
api = _api(tmp_path / "wf_api_direct_composition")
|
||||||
|
|
||||||
result = asyncio.run(
|
result = asyncio.run(
|
||||||
api.call_capability(
|
api.call_capability(
|
||||||
@@ -56,11 +56,11 @@ def test_workflow_api_direct_capability_call() -> None:
|
|||||||
assert result["output"] == {"echoed": "hello"}
|
assert result["output"] == {"echoed": "hello"}
|
||||||
|
|
||||||
|
|
||||||
def test_workflow_surface_handlers_is_compatibility_shim() -> None:
|
def test_workflow_surface_handlers_is_compatibility_shim(tmp_path: Path) -> None:
|
||||||
from wf_api import WorkflowApi
|
from wf_api import WorkflowApi
|
||||||
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
||||||
|
|
||||||
root = local_temp_root() / "workflow_surface_handler_shim"
|
root = tmp_path / "workflow_surface_handler_shim"
|
||||||
service = WfMcpService(
|
service = WfMcpService(
|
||||||
store=FileStore(root / "mcp"),
|
store=FileStore(root / "mcp"),
|
||||||
artifact_store=FileWorkflowArtifactStore(root),
|
artifact_store=FileWorkflowArtifactStore(root),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from wf_artifacts import FileWorkflowArtifactStore, FileDraftWorkspaceStore
|
from wf_artifacts import FileWorkflowArtifactStore, FileDraftWorkspaceStore
|
||||||
@@ -11,7 +12,7 @@ from wf_mcp.storage import FileStore
|
|||||||
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
||||||
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
||||||
|
|
||||||
from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
from tests.wf_mcp.test_support import echo_tool
|
||||||
|
|
||||||
|
|
||||||
def _echo_draft() -> dict[str, Any]:
|
def _echo_draft() -> dict[str, Any]:
|
||||||
@@ -70,8 +71,8 @@ def _draft_api(
|
|||||||
return WorkflowDraftApi(context), service
|
return WorkflowDraftApi(context), service
|
||||||
|
|
||||||
|
|
||||||
def test_patch_draft_applies_json_patch() -> None:
|
def test_patch_draft_applies_json_patch(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(local_temp_root() / "drafts_patch")
|
artifact_store = FileWorkflowArtifactStore(tmp_path / "drafts_patch")
|
||||||
api, _service = _draft_api(artifact_store)
|
api, _service = _draft_api(artifact_store)
|
||||||
|
|
||||||
result = asyncio.run(
|
result = asyncio.run(
|
||||||
@@ -94,9 +95,9 @@ def test_patch_draft_applies_json_patch() -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_create_draft_workspace_creates_workspace() -> None:
|
def test_create_draft_workspace_creates_workspace(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "drafts_create_workspace"
|
tmp_path / "drafts_create_workspace"
|
||||||
)
|
)
|
||||||
api, _service = _draft_api(artifact_store)
|
api, _service = _draft_api(artifact_store)
|
||||||
|
|
||||||
@@ -118,9 +119,9 @@ def test_create_draft_workspace_creates_workspace() -> None:
|
|||||||
assert fetched["draft"]["steps"]["echo"]["use"] == "demo.personal.echo_tool"
|
assert fetched["draft"]["steps"]["echo"]["use"] == "demo.personal.echo_tool"
|
||||||
|
|
||||||
|
|
||||||
def test_list_draft_workspaces_returns_sorted_summaries_without_drafts() -> None:
|
def test_list_draft_workspaces_returns_sorted_summaries_without_drafts(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "drafts_list_workspaces"
|
tmp_path / "drafts_list_workspaces"
|
||||||
)
|
)
|
||||||
api, _service = _draft_api(artifact_store)
|
api, _service = _draft_api(artifact_store)
|
||||||
asyncio.run(
|
asyncio.run(
|
||||||
@@ -148,9 +149,9 @@ def test_list_draft_workspaces_returns_sorted_summaries_without_drafts() -> None
|
|||||||
assert "draft" not in result["workspaces"][0]
|
assert "draft" not in result["workspaces"][0]
|
||||||
|
|
||||||
|
|
||||||
def test_delete_draft_workspace_is_idempotent() -> None:
|
def test_delete_draft_workspace_is_idempotent(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "drafts_delete_workspace"
|
tmp_path / "drafts_delete_workspace"
|
||||||
)
|
)
|
||||||
api, _service = _draft_api(artifact_store)
|
api, _service = _draft_api(artifact_store)
|
||||||
asyncio.run(
|
asyncio.run(
|
||||||
@@ -173,9 +174,9 @@ def test_delete_draft_workspace_is_idempotent() -> None:
|
|||||||
assert listed["workspaces"] == []
|
assert listed["workspaces"] == []
|
||||||
|
|
||||||
|
|
||||||
def test_patch_draft_workspace_updates_revision() -> None:
|
def test_patch_draft_workspace_updates_revision(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "drafts_patch_workspace"
|
tmp_path / "drafts_patch_workspace"
|
||||||
)
|
)
|
||||||
api, _service = _draft_api(artifact_store)
|
api, _service = _draft_api(artifact_store)
|
||||||
asyncio.run(
|
asyncio.run(
|
||||||
@@ -197,9 +198,9 @@ def test_patch_draft_workspace_updates_revision() -> None:
|
|||||||
assert patched["status"] == "valid"
|
assert patched["status"] == "valid"
|
||||||
|
|
||||||
|
|
||||||
def test_draft_workspace_patch_helpers_update_revision_and_bindings() -> None:
|
def test_draft_workspace_patch_helpers_update_revision_and_bindings(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "drafts_patch_helpers"
|
tmp_path / "drafts_patch_helpers"
|
||||||
)
|
)
|
||||||
api, _service = _draft_api(artifact_store)
|
api, _service = _draft_api(artifact_store)
|
||||||
asyncio.run(
|
asyncio.run(
|
||||||
@@ -265,9 +266,9 @@ def test_draft_workspace_patch_helpers_update_revision_and_bindings() -> None:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_validate_draft_workspace_refreshes_status() -> None:
|
def test_validate_draft_workspace_refreshes_status(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "drafts_validate_workspace"
|
tmp_path / "drafts_validate_workspace"
|
||||||
)
|
)
|
||||||
api, service = _draft_api(artifact_store, register_echo=True)
|
api, service = _draft_api(artifact_store, register_echo=True)
|
||||||
draft = _echo_draft()
|
draft = _echo_draft()
|
||||||
@@ -288,9 +289,9 @@ def test_validate_draft_workspace_refreshes_status() -> None:
|
|||||||
assert fetched["status"] == "invalid"
|
assert fetched["status"] == "invalid"
|
||||||
|
|
||||||
|
|
||||||
def test_create_minimal_draft_workspace_minimal_success_path() -> None:
|
def test_create_minimal_draft_workspace_minimal_success_path(tmp_path: Path) -> None:
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "drafts_minimal_workspace"
|
tmp_path / "drafts_minimal_workspace"
|
||||||
)
|
)
|
||||||
api, _service = _draft_api(artifact_store, register_echo=True)
|
api, _service = _draft_api(artifact_store, register_echo=True)
|
||||||
|
|
||||||
@@ -323,10 +324,10 @@ def test_create_minimal_draft_workspace_minimal_success_path() -> None:
|
|||||||
assert fetched["draft"]["steps"]["call"]["use"] == "demo.personal.echo_tool"
|
assert fetched["draft"]["steps"]["call"]["use"] == "demo.personal.echo_tool"
|
||||||
|
|
||||||
|
|
||||||
def test_delegation_smoke_validate_draft_equivalence() -> None:
|
def test_delegation_smoke_validate_draft_equivalence(tmp_path: Path) -> None:
|
||||||
"""WorkflowSurfaceHandlers.validate_draft delegates to WorkflowDraftApi."""
|
"""WorkflowSurfaceHandlers.validate_draft delegates to WorkflowDraftApi."""
|
||||||
artifact_store = FileWorkflowArtifactStore(
|
artifact_store = FileWorkflowArtifactStore(
|
||||||
local_temp_root() / "drafts_delegation_smoke"
|
tmp_path / "drafts_delegation_smoke"
|
||||||
)
|
)
|
||||||
mcp_root = artifact_store.root / "delegation_mcp"
|
mcp_root = artifact_store.root / "delegation_mcp"
|
||||||
service = WfMcpService(
|
service = WfMcpService(
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ from wf_mcp.models import ConnectionConfig
|
|||||||
from wf_mcp.storage import FileStore
|
from wf_mcp.storage import FileStore
|
||||||
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
from wf_mcp.workflow_surface import WorkflowSurfaceHandlers
|
||||||
|
|
||||||
from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
from tests.wf_mcp.test_support import echo_tool
|
||||||
from tests.wf_mcp.workflow_surface.conftest import (
|
from tests.wf_mcp.workflow_surface.conftest import (
|
||||||
echo_artifact,
|
echo_artifact,
|
||||||
failing_artifact,
|
failing_artifact,
|
||||||
@@ -81,8 +81,8 @@ def _service_with_failing(
|
|||||||
return service, artifact_store
|
return service, artifact_store
|
||||||
|
|
||||||
|
|
||||||
def test_run_api_unrunnable_deployment() -> None:
|
def test_run_api_unrunnable_deployment(tmp_path: Path) -> None:
|
||||||
root = local_temp_root() / "run_api_unrunnable"
|
root = tmp_path / "run_api_unrunnable"
|
||||||
artifact_store = FileWorkflowArtifactStore(root)
|
artifact_store = FileWorkflowArtifactStore(root)
|
||||||
from tests.wf_mcp.workflow_surface.conftest import artifact
|
from tests.wf_mcp.workflow_surface.conftest import artifact
|
||||||
|
|
||||||
@@ -115,8 +115,8 @@ def test_run_api_unrunnable_deployment() -> None:
|
|||||||
assert result["diagnostics"][0]["code"]
|
assert result["diagnostics"][0]["code"]
|
||||||
|
|
||||||
|
|
||||||
def test_run_api_completed_run_persists() -> None:
|
def test_run_api_completed_run_persists(tmp_path: Path) -> None:
|
||||||
root = local_temp_root() / "run_api_completed"
|
root = tmp_path / "run_api_completed"
|
||||||
service, artifact_store = _service_with_echo(root)
|
service, artifact_store = _service_with_echo(root)
|
||||||
context = context_from_service(service)
|
context = context_from_service(service)
|
||||||
api = WorkflowRunApi(context)
|
api = WorkflowRunApi(context)
|
||||||
@@ -138,8 +138,8 @@ def test_run_api_completed_run_persists() -> None:
|
|||||||
assert stored.id == result["run_id"]
|
assert stored.id == result["run_id"]
|
||||||
|
|
||||||
|
|
||||||
def test_run_api_rejects_resume_for_completed_run() -> None:
|
def test_run_api_rejects_resume_for_completed_run(tmp_path: Path) -> None:
|
||||||
root = local_temp_root() / "run_api_resume_completed_rejected"
|
root = tmp_path / "run_api_resume_completed_rejected"
|
||||||
service, _ = _service_with_echo(root)
|
service, _ = _service_with_echo(root)
|
||||||
context = context_from_service(service)
|
context = context_from_service(service)
|
||||||
api = WorkflowRunApi(context)
|
api = WorkflowRunApi(context)
|
||||||
@@ -160,8 +160,8 @@ def test_run_api_rejects_resume_for_completed_run() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_run_api_inspect_uses_pinned_environment_after_deployment_deleted() -> None:
|
def test_run_api_inspect_uses_pinned_environment_after_deployment_deleted(tmp_path: Path) -> None:
|
||||||
root = local_temp_root() / "run_api_inspect_after_deployment_deleted"
|
root = tmp_path / "run_api_inspect_after_deployment_deleted"
|
||||||
service, artifact_store = _service_with_echo(root)
|
service, artifact_store = _service_with_echo(root)
|
||||||
context = context_from_service(service)
|
context = context_from_service(service)
|
||||||
api = WorkflowRunApi(context)
|
api = WorkflowRunApi(context)
|
||||||
@@ -183,8 +183,8 @@ def test_run_api_inspect_uses_pinned_environment_after_deployment_deleted() -> N
|
|||||||
assert summary["output"]["echoed"] == "hello"
|
assert summary["output"]["echoed"] == "hello"
|
||||||
|
|
||||||
|
|
||||||
def test_run_api_inspect_and_bounded_trace() -> None:
|
def test_run_api_inspect_and_bounded_trace(tmp_path: Path) -> None:
|
||||||
root = local_temp_root() / "run_api_inspect_trace"
|
root = tmp_path / "run_api_inspect_trace"
|
||||||
service, _ = _service_with_echo(root)
|
service, _ = _service_with_echo(root)
|
||||||
context = context_from_service(service)
|
context = context_from_service(service)
|
||||||
api = WorkflowRunApi(context)
|
api = WorkflowRunApi(context)
|
||||||
@@ -217,8 +217,8 @@ class ExplodingRunStore(FileRunStore):
|
|||||||
raise AssertionError("run store must not be read before trace_range validation")
|
raise AssertionError("run store must not be read before trace_range validation")
|
||||||
|
|
||||||
|
|
||||||
def test_run_api_rejects_invalid_trace_range_before_store_lookup() -> None:
|
def test_run_api_rejects_invalid_trace_range_before_store_lookup(tmp_path: Path) -> None:
|
||||||
root = local_temp_root() / "run_api_invalid_trace_range"
|
root = tmp_path / "run_api_invalid_trace_range"
|
||||||
service, _ = _service_with_echo(root)
|
service, _ = _service_with_echo(root)
|
||||||
service.run_store = ExplodingRunStore(root / "exploding_runs")
|
service.run_store = ExplodingRunStore(root / "exploding_runs")
|
||||||
context = context_from_service(service)
|
context = context_from_service(service)
|
||||||
@@ -241,8 +241,8 @@ def test_run_api_rejects_invalid_trace_range_before_store_lookup() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_run_api_handler_delegation_matches() -> None:
|
def test_run_api_handler_delegation_matches(tmp_path: Path) -> None:
|
||||||
root = local_temp_root() / "run_api_delegation"
|
root = tmp_path / "run_api_delegation"
|
||||||
service, _ = _service_with_echo(root)
|
service, _ = _service_with_echo(root)
|
||||||
context = context_from_service(service)
|
context = context_from_service(service)
|
||||||
api = WorkflowRunApi(context)
|
api = WorkflowRunApi(context)
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from wf_api.stores import WorkflowStores, file_workflow_stores
|
from wf_api.stores import WorkflowStores, file_workflow_stores
|
||||||
from wf_artifacts import (
|
from wf_artifacts import (
|
||||||
FileDraftWorkspaceStore,
|
FileDraftWorkspaceStore,
|
||||||
@@ -7,11 +9,9 @@ from wf_artifacts import (
|
|||||||
FileWorkflowArtifactStore,
|
FileWorkflowArtifactStore,
|
||||||
)
|
)
|
||||||
|
|
||||||
from tests.wf_mcp.test_support import local_temp_root
|
|
||||||
|
|
||||||
|
def test_file_workflow_stores_constructs_all_three_file_stores(tmp_path: Path) -> None:
|
||||||
def test_file_workflow_stores_constructs_all_three_file_stores() -> None:
|
root = tmp_path / "wf_api_file_workflow_stores"
|
||||||
root = local_temp_root() / "wf_api_file_workflow_stores"
|
|
||||||
|
|
||||||
stores = file_workflow_stores(root)
|
stores = file_workflow_stores(root)
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,9 @@ from wf_mcp.source_registry import (
|
|||||||
)
|
)
|
||||||
from wf_mcp.storage import FileStore
|
from wf_mcp.storage import FileStore
|
||||||
|
|
||||||
from ..test_support import local_temp_root
|
|
||||||
|
|
||||||
|
def _source_catalog(service: ConnectionService, root: Path) -> SourceCatalogService:
|
||||||
def _source_catalog(service: ConnectionService) -> SourceCatalogService:
|
store = FileStore(root / "connection_service_catalog")
|
||||||
store = FileStore(local_temp_root() / "connection_service_catalog")
|
|
||||||
|
|
||||||
def _tool_executor_for(_connection: ConnectionConfig) -> ToolExecutor:
|
def _tool_executor_for(_connection: ConnectionConfig) -> ToolExecutor:
|
||||||
raise AssertionError("tool executor should not be needed in these tests")
|
raise AssertionError("tool executor should not be needed in these tests")
|
||||||
@@ -39,9 +37,9 @@ def _source_catalog(service: ConnectionService) -> SourceCatalogService:
|
|||||||
return catalog
|
return catalog
|
||||||
|
|
||||||
|
|
||||||
def test_connection_service_rejects_reserved_connection_ids() -> None:
|
def test_connection_service_rejects_reserved_connection_ids(tmp_path: Path) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
_source_catalog(service)
|
_source_catalog(service, tmp_path)
|
||||||
|
|
||||||
for connection_id in ("wf.admin", "wf.mcp"):
|
for connection_id in ("wf.admin", "wf.mcp"):
|
||||||
try:
|
try:
|
||||||
@@ -55,9 +53,9 @@ def test_connection_service_rejects_reserved_connection_ids() -> None:
|
|||||||
raise AssertionError(f"expected {connection_id!r} to be rejected")
|
raise AssertionError(f"expected {connection_id!r} to be rejected")
|
||||||
|
|
||||||
|
|
||||||
def test_connection_service_registers_connection_and_empty_source() -> None:
|
def test_connection_service_registers_connection_and_empty_source(tmp_path: Path) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
catalog = _source_catalog(service)
|
catalog = _source_catalog(service, tmp_path)
|
||||||
|
|
||||||
service.register_connection(
|
service.register_connection(
|
||||||
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
||||||
@@ -72,15 +70,15 @@ def test_connection_service_registers_connection_and_empty_source() -> None:
|
|||||||
assert service.events.list_events()[0].connection_id == "demo.personal"
|
assert service.events.list_events()[0].connection_id == "demo.personal"
|
||||||
|
|
||||||
|
|
||||||
def test_connection_service_sync_removes_retired_connections_and_sources() -> None:
|
def test_connection_service_sync_removes_retired_connections_and_sources(tmp_path: Path) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
catalog = _source_catalog(service)
|
catalog = _source_catalog(service, tmp_path)
|
||||||
service.register_connection(
|
service.register_connection(
|
||||||
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
||||||
)
|
)
|
||||||
|
|
||||||
service.sync_connections_from_config(
|
service.sync_connections_from_config(
|
||||||
BrokerConfig(store_root=local_temp_root(), connections=[])
|
BrokerConfig(store_root=tmp_path, connections=[])
|
||||||
)
|
)
|
||||||
|
|
||||||
assert service.list_all() == []
|
assert service.list_all() == []
|
||||||
@@ -92,16 +90,16 @@ def test_connection_service_sync_removes_retired_connections_and_sources() -> No
|
|||||||
assert removed.payload["account"] == "personal"
|
assert removed.payload["account"] == "personal"
|
||||||
|
|
||||||
|
|
||||||
def test_connection_service_sync_updates_existing_source_enabled_flag() -> None:
|
def test_connection_service_sync_updates_existing_source_enabled_flag(tmp_path: Path) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
catalog = _source_catalog(service)
|
catalog = _source_catalog(service, tmp_path)
|
||||||
service.register_connection(
|
service.register_connection(
|
||||||
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
||||||
)
|
)
|
||||||
|
|
||||||
service.sync_connections_from_config(
|
service.sync_connections_from_config(
|
||||||
BrokerConfig(
|
BrokerConfig(
|
||||||
store_root=local_temp_root(),
|
store_root=tmp_path,
|
||||||
connections=[
|
connections=[
|
||||||
ConnectionConfig(
|
ConnectionConfig(
|
||||||
id="demo.personal",
|
id="demo.personal",
|
||||||
@@ -121,13 +119,13 @@ def test_connection_service_sync_updates_existing_source_enabled_flag() -> None:
|
|||||||
assert updated.payload["enabled"] is False
|
assert updated.payload["enabled"] is False
|
||||||
|
|
||||||
|
|
||||||
def test_connection_service_sync_registers_new_connections_with_event() -> None:
|
def test_connection_service_sync_registers_new_connections_with_event(tmp_path: Path) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
catalog = _source_catalog(service)
|
catalog = _source_catalog(service, tmp_path)
|
||||||
|
|
||||||
service.sync_connections_from_config(
|
service.sync_connections_from_config(
|
||||||
BrokerConfig(
|
BrokerConfig(
|
||||||
store_root=local_temp_root(),
|
store_root=tmp_path,
|
||||||
connections=[
|
connections=[
|
||||||
ConnectionConfig(
|
ConnectionConfig(
|
||||||
id="demo.personal",
|
id="demo.personal",
|
||||||
@@ -145,8 +143,8 @@ def test_connection_service_sync_registers_new_connections_with_event() -> None:
|
|||||||
assert registered.connection_id == "demo.personal"
|
assert registered.connection_id == "demo.personal"
|
||||||
|
|
||||||
|
|
||||||
def test_wfmcpservice_exposes_connection_registry_from_connection_service() -> None:
|
def test_wfmcpservice_exposes_connection_registry_from_connection_service(tmp_path: Path) -> None:
|
||||||
service = WfMcpService(store=FileStore(local_temp_root() / "connection_facade"))
|
service = WfMcpService(store=FileStore(tmp_path / "connection_facade"))
|
||||||
|
|
||||||
service.register_connection(
|
service.register_connection(
|
||||||
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
||||||
@@ -157,15 +155,15 @@ def test_wfmcpservice_exposes_connection_registry_from_connection_service() -> N
|
|||||||
assert "demo.personal" in service.capability_sources
|
assert "demo.personal" in service.capability_sources
|
||||||
|
|
||||||
|
|
||||||
def test_wfmcpservice_sync_connections_delegates_to_connection_service() -> None:
|
def test_wfmcpservice_sync_connections_delegates_to_connection_service(tmp_path: Path) -> None:
|
||||||
service = WfMcpService(store=FileStore(local_temp_root() / "connection_sync"))
|
service = WfMcpService(store=FileStore(tmp_path / "connection_sync"))
|
||||||
service.register_connection(
|
service.register_connection(
|
||||||
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
ConnectionConfig(id="demo.personal", server="demo", account="personal")
|
||||||
)
|
)
|
||||||
|
|
||||||
service.sync_connections_from_config(
|
service.sync_connections_from_config(
|
||||||
BrokerConfig(
|
BrokerConfig(
|
||||||
store_root=local_temp_root(),
|
store_root=tmp_path,
|
||||||
connections=[
|
connections=[
|
||||||
ConnectionConfig(
|
ConnectionConfig(
|
||||||
id="demo.work",
|
id="demo.work",
|
||||||
@@ -204,14 +202,14 @@ def _registry_entry(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_connection_service_sync_merges_registry_entries() -> None:
|
def test_connection_service_sync_merges_registry_entries(tmp_path: Path) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
catalog = _source_catalog(service)
|
catalog = _source_catalog(service, tmp_path)
|
||||||
store = FileSourceRegistryStore(local_temp_root() / "registry_merge")
|
store = FileSourceRegistryStore(tmp_path / "registry_merge")
|
||||||
store.save_registry(SourceRegistryFile(sources=[_registry_entry()]))
|
store.save_registry(SourceRegistryFile(sources=[_registry_entry()]))
|
||||||
|
|
||||||
service.sync_connections_from_config(
|
service.sync_connections_from_config(
|
||||||
BrokerConfig(store_root=local_temp_root(), connections=[]),
|
BrokerConfig(store_root=tmp_path, connections=[]),
|
||||||
source_registry_store=store,
|
source_registry_store=store,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -219,15 +217,15 @@ def test_connection_service_sync_merges_registry_entries() -> None:
|
|||||||
assert "demo.registry" in catalog.capability_sources
|
assert "demo.registry" in catalog.capability_sources
|
||||||
|
|
||||||
|
|
||||||
def test_connection_service_sync_config_shadows_registry_entry() -> None:
|
def test_connection_service_sync_config_shadows_registry_entry(tmp_path: Path) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
_source_catalog(service)
|
_source_catalog(service, tmp_path)
|
||||||
store = FileSourceRegistryStore(local_temp_root() / "registry_shadow")
|
store = FileSourceRegistryStore(tmp_path / "registry_shadow")
|
||||||
store.save_registry(SourceRegistryFile(sources=[_registry_entry("demo.same")]))
|
store.save_registry(SourceRegistryFile(sources=[_registry_entry("demo.same")]))
|
||||||
|
|
||||||
service.sync_connections_from_config(
|
service.sync_connections_from_config(
|
||||||
BrokerConfig(
|
BrokerConfig(
|
||||||
store_root=local_temp_root(),
|
store_root=tmp_path,
|
||||||
connections=[
|
connections=[
|
||||||
ConnectionConfig(id="demo.same", server="demo", account="config"),
|
ConnectionConfig(id="demo.same", server="demo", account="config"),
|
||||||
],
|
],
|
||||||
@@ -243,16 +241,16 @@ def test_connection_service_sync_config_shadows_registry_entry() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_connection_service_sync_registry_disabled_entry_hydrates_disabled_source() -> (
|
def test_connection_service_sync_registry_disabled_entry_hydrates_disabled_source(
|
||||||
None
|
tmp_path: Path,
|
||||||
):
|
) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
catalog = _source_catalog(service)
|
catalog = _source_catalog(service, tmp_path)
|
||||||
store = FileSourceRegistryStore(local_temp_root() / "registry_disabled")
|
store = FileSourceRegistryStore(tmp_path / "registry_disabled")
|
||||||
store.save_registry(SourceRegistryFile(sources=[_registry_entry(enabled=False)]))
|
store.save_registry(SourceRegistryFile(sources=[_registry_entry(enabled=False)]))
|
||||||
|
|
||||||
service.sync_connections_from_config(
|
service.sync_connections_from_config(
|
||||||
BrokerConfig(store_root=local_temp_root(), connections=[]),
|
BrokerConfig(store_root=tmp_path, connections=[]),
|
||||||
source_registry_store=store,
|
source_registry_store=store,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -264,7 +262,7 @@ def test_connection_service_sync_locked_config_shadows_registry_entry(
|
|||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
_source_catalog(service)
|
_source_catalog(service, tmp_path)
|
||||||
store = FileSourceRegistryStore(tmp_path / "locked_shadow")
|
store = FileSourceRegistryStore(tmp_path / "locked_shadow")
|
||||||
store.save_registry(
|
store.save_registry(
|
||||||
SourceRegistryFile(
|
SourceRegistryFile(
|
||||||
@@ -279,7 +277,7 @@ def test_connection_service_sync_locked_config_shadows_registry_entry(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
config = BrokerConfig(
|
config = BrokerConfig(
|
||||||
store_root=local_temp_root(),
|
store_root=tmp_path,
|
||||||
connections=[
|
connections=[
|
||||||
ConnectionConfig(
|
ConnectionConfig(
|
||||||
id="demo.default",
|
id="demo.default",
|
||||||
@@ -305,11 +303,11 @@ def test_connection_service_sync_seed_config_materializes_registry_entry(
|
|||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
_source_catalog(service)
|
_source_catalog(service, tmp_path)
|
||||||
store_root = tmp_path / "seed_materialized"
|
store_root = tmp_path / "seed_materialized"
|
||||||
store = FileSourceRegistryStore(store_root)
|
store = FileSourceRegistryStore(store_root)
|
||||||
config = BrokerConfig(
|
config = BrokerConfig(
|
||||||
store_root=local_temp_root(),
|
store_root=tmp_path,
|
||||||
connections=[
|
connections=[
|
||||||
ConnectionConfig(
|
ConnectionConfig(
|
||||||
id="demo.default",
|
id="demo.default",
|
||||||
@@ -339,7 +337,7 @@ def test_connection_service_sync_seed_existing_registry_entry_wins(
|
|||||||
tmp_path: Path,
|
tmp_path: Path,
|
||||||
) -> None:
|
) -> None:
|
||||||
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
service = ConnectionService(events=BrokerEventRecorder(EventBus()))
|
||||||
_source_catalog(service)
|
_source_catalog(service, tmp_path)
|
||||||
store = FileSourceRegistryStore(tmp_path / "seed_existing")
|
store = FileSourceRegistryStore(tmp_path / "seed_existing")
|
||||||
store.save_registry(
|
store.save_registry(
|
||||||
SourceRegistryFile(
|
SourceRegistryFile(
|
||||||
@@ -354,7 +352,7 @@ def test_connection_service_sync_seed_existing_registry_entry_wins(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
config = BrokerConfig(
|
config = BrokerConfig(
|
||||||
store_root=local_temp_root(),
|
store_root=tmp_path,
|
||||||
connections=[
|
connections=[
|
||||||
ConnectionConfig(
|
ConnectionConfig(
|
||||||
id="demo.default",
|
id="demo.default",
|
||||||
@@ -377,13 +375,13 @@ def test_connection_service_sync_seed_existing_registry_entry_wins(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_wfmcpservice_sync_connections_delegates_registry_store() -> None:
|
def test_wfmcpservice_sync_connections_delegates_registry_store(tmp_path: Path) -> None:
|
||||||
service = WfMcpService(store=FileStore(local_temp_root() / "facade_registry"))
|
service = WfMcpService(store=FileStore(tmp_path / "facade_registry"))
|
||||||
store = FileSourceRegistryStore(local_temp_root() / "facade_registry_store")
|
store = FileSourceRegistryStore(tmp_path / "facade_registry_store")
|
||||||
store.save_registry(SourceRegistryFile(sources=[_registry_entry()]))
|
store.save_registry(SourceRegistryFile(sources=[_registry_entry()]))
|
||||||
|
|
||||||
service.sync_connections_from_config(
|
service.sync_connections_from_config(
|
||||||
BrokerConfig(store_root=local_temp_root(), connections=[]),
|
BrokerConfig(store_root=tmp_path, connections=[]),
|
||||||
source_registry_store=store,
|
source_registry_store=store,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user