test orgs 2

This commit is contained in:
lda
2026-05-07 06:16:28 +07:00 Verified
parent 06d25582c9
commit 54f3e9a739
10 changed files with 11 additions and 10 deletions
+420
View File
@@ -0,0 +1,420 @@
from __future__ import annotations
import asyncio
import shutil
from wf_core import END, RunStatus
from wf_mcp import (
AuthRecord,
ConnectionConfig,
FileStore,
RawWorkflowPlan,
WfMcpService,
)
from wf_mcp.error_info import error_payload
from .test_support import (
FailingDiscoveryAdapter,
FakeAdapter,
echo_tool,
finalize_tool,
local_temp_root,
)
def test_service_builds_namespaced_catalog() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "catalog_store"))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_specs("demo.personal", echo_tool, finalize_tool)
payload = service.get_catalog().as_payload()
names = [node["qualified_name"] for node in payload["nodes"]]
assert names == [
"demo.personal.echo_tool",
"demo.personal.finalize_tool",
]
def test_service_compiles_and_runs_raw_plan() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "run_store"))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_specs("demo.personal", echo_tool, finalize_tool)
plan = RawWorkflowPlan(
name="demo_plan",
input_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
state_schema={
"fields": {
"echoed": {"type": "string"},
"result": {"type": "string"},
}
},
output_schema={
"type": "object",
"properties": {"result": {"type": "string"}},
"required": ["result"],
},
start="echo",
nodes=[
{
"id": "echo",
"type": "node",
"node": "demo.personal.echo_tool",
"in_map": {"input.text": "text"},
"out_map": {"echoed": "state.echoed"},
},
{
"id": "finalize",
"type": "node",
"node": "demo.personal.finalize_tool",
"in_map": {"state.echoed": "echoed"},
"out_map": {"result": "state.result"},
},
],
edges=[
{"from": "echo", "outcome": "ok", "to": "finalize"},
{"from": "finalize", "outcome": "done", "to": END},
],
)
run = asyncio.run(service.run_workflow_from_plan(plan, {"text": "hello"}))
assert run.status == RunStatus.COMPLETED
assert run.output == {"result": "final:hello"}
event_kinds = [event.kind for event in service.list_events()]
assert "workflow_run_started" in event_kinds
assert "workflow_run_completed" in event_kinds
def test_service_refreshes_catalog_from_adapter() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "adapter_store"))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.save_auth(
AuthRecord(
connection_id="demo.personal",
scheme="token",
payload={"token": "abc"},
)
)
service.register_adapter("demo", FakeAdapter())
asyncio.run(service.refresh_connection_catalog("demo.personal"))
payload = service.get_catalog().as_payload()
assert payload["nodes"] == [
{
"qualified_name": "demo.personal.echo_tool",
"connection_id": "demo.personal",
"local_name": "echo_tool",
"title": "Echo Tool",
"description": "Echo text back",
"outcomes": ["ok"],
"input_schema": {
"additionalProperties": True,
"properties": {"text": {"title": "Text"}},
"required": ["text"],
"title": "demo.personal_echo_tool_Input",
"type": "object",
},
"output_schema": {
"additionalProperties": True,
"properties": {"echoed": {"title": "Echoed"}},
"required": ["echoed"],
"title": "demo.personal_echo_tool_Output",
"type": "object",
},
}
]
assert payload["resources"] == [
{
"qualified_name": "demo.personal.resource.welcome",
"connection_id": "demo.personal",
"local_name": "resource.welcome",
"title": "Welcome Resource",
"uri": "demo://docs/welcome",
"description": "Welcome resource",
"mime_type": "text/plain",
"metadata": {"kind": "static"},
}
]
assert payload["prompts"] == [
{
"qualified_name": "demo.personal.prompt.summarize",
"connection_id": "demo.personal",
"local_name": "prompt.summarize",
"title": "Summarize Prompt",
"description": "Summarize text",
"arguments": [
{
"name": "text",
"required": True,
"description": "Text to summarize",
}
],
"metadata": {"kind": "template"},
}
]
assert payload["connections"] == [
{
"connection_id": "demo.personal",
"fetched_at_epoch_ms": payload["connections"][0]["fetched_at_epoch_ms"],
"max_age_seconds": 300,
"metadata": {
"server": "demo",
"account": "personal",
"auth_scheme": "token",
},
}
]
event_kinds = [event.kind for event in service.list_events()]
assert "catalog_refresh_started" in event_kinds
assert "catalog_refresh_completed" in event_kinds
def test_service_records_tool_call_events() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "event_store"))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_adapter("demo", FakeAdapter())
asyncio.run(service.refresh_connection_catalog("demo.personal"))
plan = RawWorkflowPlan(
name="tool_only_plan",
input_schema={
"type": "object",
"properties": {"text": {"type": "string"}},
"required": ["text"],
},
state_schema={
"fields": {
"echoed": {"type": "string"},
}
},
output_schema={
"type": "object",
"properties": {"echoed": {"type": "string"}},
"required": ["echoed"],
},
start="echo",
nodes=[
{
"id": "echo",
"type": "node",
"node": "demo.personal.echo_tool",
"in_map": {"input.text": "text"},
"out_map": {"echoed": "state.echoed"},
}
],
edges=[
{"from": "echo", "outcome": "ok", "to": END},
],
)
run = asyncio.run(service.run_workflow_from_plan(plan, {"text": "hello"}))
assert run.status == RunStatus.COMPLETED
tool_events = [
event for event in service.list_events() if "tool_call" in event.kind
]
assert [event.kind for event in tool_events] == [
"tool_call_started",
"tool_call_completed",
]
assert tool_events[0].capability_id == "demo.personal.echo_tool"
assert tool_events[1].payload["outcome"] == "ok"
def test_service_can_inspect_resources_and_prompts() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "inspect_store"))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_adapter("demo", FakeAdapter())
asyncio.run(service.refresh_connection_catalog("demo.personal"))
resources = service.list_resources(connection_id="demo.personal")
prompts = service.list_prompts(connection_id="demo.personal")
assert [resource.qualified_name for resource in resources] == [
"demo.personal.resource.welcome"
]
assert [prompt.qualified_name for prompt in prompts] == [
"demo.personal.prompt.summarize"
]
resource = service.get_resource("demo.personal.resource.welcome")
prompt = service.get_prompt("demo.personal.prompt.summarize")
assert resource.uri == "demo://docs/welcome"
assert prompt.arguments[0]["name"] == "text"
def test_service_reports_connection_statuses() -> None:
store = local_temp_root() / "status_store"
# clear store before test
shutil.rmtree(store)
service = WfMcpService(store=FileStore(store))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_adapter("demo", FakeAdapter())
before = service.connection_statuses()
assert before == [
{
"connection_id": "demo.personal",
"server": "demo",
"account": "personal",
"enabled": True,
"has_snapshot": False,
"fetched_at_epoch_ms": None,
"max_age_seconds": None,
"node_count": 0,
"resource_count": 0,
"prompt_count": 0,
}
]
asyncio.run(service.refresh_connection_catalog("demo.personal"))
after = service.connection_statuses()
assert after[0]["has_snapshot"] is True
assert after[0]["node_count"] == 1
assert after[0]["resource_count"] == 1
assert after[0]["prompt_count"] == 1
def test_service_can_proxy_resource_reads_and_prompt_gets() -> None:
store = local_temp_root() / "proxy_store"
# new store
shutil.rmtree(store)
service = WfMcpService(store=FileStore(store))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_adapter("demo", FakeAdapter())
asyncio.run(service.refresh_connection_catalog("demo.personal"))
resource_result = asyncio.run(
service.read_resource("demo.personal.resource.welcome")
)
prompt_result = asyncio.run(
service.render_prompt(
"demo.personal.prompt.summarize",
arguments={"text": "hello world"},
)
)
assert (
resource_result["contents"][0]["text"]
== "Welcome from the fake adapter resource."
)
assert (
prompt_result["messages"][0]["content"]["text"]
== "Summarize this text:\n\nhello world"
)
event_kinds = [event.kind for event in service.list_events()]
assert "resource_read_started" in event_kinds
assert "resource_read_completed" in event_kinds
assert "prompt_get_started" in event_kinds
assert "prompt_get_completed" in event_kinds
def test_service_can_invoke_raw_method_and_notification() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "raw_store"))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_adapter("demo", FakeAdapter())
result = asyncio.run(
service.invoke_method("demo.personal", "demo.echo", params={"text": "hello"})
)
asyncio.run(
service.send_notification(
"demo.personal",
"notifications/progress",
params={"progress": 1},
)
)
assert result == {"echoed": "hello"}
event_kinds = [event.kind for event in service.list_events()]
assert "raw_method_started" in event_kinds
assert "raw_method_completed" in event_kinds
assert "raw_notification_started" in event_kinds
assert "raw_notification_completed" in event_kinds
def test_service_can_call_upstream_tool_directly() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "direct_tool_store"))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_adapter("demo", FakeAdapter())
result = asyncio.run(
service.call_tool(
"demo.personal",
"echo_tool",
arguments={"text": "hello"},
)
)
assert result == {
"outcome": "ok",
"output": {"echoed": "hello"},
"meta": {},
}
event_kinds = [event.kind for event in service.list_events()]
assert "tool_call_started" in event_kinds
assert "tool_call_completed" in event_kinds
def test_service_records_catalog_refresh_failures() -> None:
service = WfMcpService(store=FileStore(local_temp_root() / "refresh_fail_store"))
service.register_connection(
ConnectionConfig(id="demo.personal", server="demo", account="personal")
)
service.register_adapter("demo", FailingDiscoveryAdapter())
try:
asyncio.run(service.refresh_connection_catalog("demo.personal"))
except PermissionError as exc:
assert str(exc) == "Access is denied"
else:
raise AssertionError("expected refresh to fail")
failure_events = [
event
for event in service.list_events()
if event.kind == "catalog_refresh_failed"
]
assert len(failure_events) == 1
assert failure_events[0].payload == {
"error_type": "PermissionError",
"error": "Access is denied",
}
def test_error_payload_unwraps_exception_group() -> None:
exc = ExceptionGroup("outer", [PermissionError("Access is denied")])
assert error_payload(exc) == {
"error_type": "PermissionError",
"error": "Access is denied",
}