Files
ITWorx_MCP_Hub-Public/tests/test_contextforge.py
T

270 lines
11 KiB
Python

from __future__ import annotations
import unittest
from base64 import b64decode
from uuid import UUID
from services.control_api.contextforge.client import ContextForgeClient
from services.control_api.contextforge.errors import ContextForgeError
from services.control_api.contextforge.fake import FakeContextForge
from services.control_api.contextforge.models import (
ContextForgeSettings,
GatewayDesiredState,
VirtualServerDesiredState,
)
class ContextForgeAdapterTests(unittest.TestCase):
def setUp(self) -> None:
self.fake = FakeContextForge()
settings = ContextForgeSettings(
base_url="https://fake.contextforge.test",
auth_token_env="CTX_TOKEN", # noqa: S106
retries=2,
)
self.client = ContextForgeClient(
settings,
transport=self.fake.transport(),
environ={"CTX_TOKEN": "fake-token-never-logged"},
)
self.desired = GatewayDesiredState(
slug="knowledge-dev",
url="https://knowledge.example.test/mcp",
description="Knowledge test gateway",
)
def tearDown(self) -> None:
self.client.close()
def test_health_capabilities_idempotent_crud_test_and_sanitized_inventory(self) -> None:
self.assertEqual(self.client.health()["status"], "healthy")
self.assertEqual(self.client.version(), "1.0.6")
settings_from_env = ContextForgeSettings.from_env(
{
"HUB_CONTEXTFORGE_URL": "https://fake.contextforge.test",
"HUB_CONTEXTFORGE_TOKEN_ENV": "CTX_TOKEN",
}
)
self.assertEqual(settings_from_env.auth_token_env, "CTX_TOKEN")
capabilities = self.client.capabilities()
self.assertTrue(capabilities.health)
first = self.client.ensure_gateway(self.desired)
second = self.client.ensure_gateway(self.desired)
self.assertEqual(first.external_id, second.external_id)
self.assertEqual(len(self.fake.gateways), 1)
self.fake.tools[first.external_id] = [
{
"id": "11111111-1111-4111-8111-111111111111",
"name": "knowledge-dev-knowledge-document-search",
"originalName": "knowledge.document.search",
"customName": "knowledge.document.search",
}
]
gateway_tools = self.client.list_gateway_tools(first)
self.assertEqual(gateway_tools[0].name, "knowledge.document.search")
self.fake.prompts[first.external_id] = [
{
"id": "44444444-4444-4444-8444-444444444444",
"name": "project-context-pack",
}
]
gateway_prompts = self.client.list_gateway_prompts(first)
self.assertEqual(gateway_prompts[0].name, "project-context-pack")
desired_server = VirtualServerDesiredState(
external_id=UUID("22222222-2222-4222-8222-222222222222"),
name="ludarium-prod-readonly",
description="Scoped production server",
associated_tool_ids=(gateway_tools[0].external_id,),
associated_prompt_ids=(gateway_prompts[0].external_id,),
)
server = self.client.ensure_virtual_server(desired_server)
self.assertEqual(server.associated_tool_ids, desired_server.associated_tool_ids)
self.assertEqual(server.associated_prompt_ids, desired_server.associated_prompt_ids)
self.assertEqual(server.visibility, "public")
self.assertEqual(
self.client.ensure_virtual_server(desired_server).external_id, server.external_id
)
self.fake.servers[server.external_id]["visibility"] = "private"
repaired = self.client.ensure_virtual_server(desired_server)
self.assertEqual(repaired.visibility, "public")
self.assertTrue(all(not path.startswith("/v1/") for _, path, _ in self.fake.requests))
self.assertNotIn("external_id", first.snapshot.model_dump())
self.assertNotIn(first.external_id, first.snapshot.model_dump_json())
listed = self.client.list_gateways()
self.assertEqual(listed[0].slug, "knowledge-dev")
result = self.client.test_gateway(first)
self.assertTrue(result.reachable)
by_slug = self.client.test_gateway_by_slug("knowledge-dev")
self.assertTrue(by_slug.reachable)
missing = self.client.test_gateway_by_slug("not-registered")
self.assertFalse(missing.reachable)
self.assertEqual(missing.status, "missing")
updated = self.client.update_gateway(
first,
self.desired.model_copy(update={"description": "Updated safely"}),
)
self.assertEqual(updated.snapshot.description, "Updated safely")
inventory = self.client.inventory()
self.assertEqual(inventory.gateways[0]["slug"], "knowledge-dev")
self.assertIn("external_id_digest", inventory.gateways[0])
self.assertNotIn("external_id", inventory.gateways[0])
self.client.delete_gateway(updated)
self.assertEqual(self.client.list_gateways(), ())
self.assertTrue(
all("fake-token-never-logged" not in str(request) for request in self.fake.requests)
)
def test_refresh_repopulates_stale_gateway_tools_and_prompts(self) -> None:
gateway = self.client.ensure_gateway(
self.desired.model_copy(
update={"slug": "itworx-gitea", "url": "https://gitea.example.test/mcp"}
)
)
self.fake.tools[gateway.external_id] = []
self.fake.prompts[gateway.external_id] = []
self.client.refresh_gateway(gateway)
self.assertIn(
"gitea.pullrequest.list",
{tool.name for tool in self.client.list_gateway_tools(gateway)},
)
self.assertEqual(
{prompt.name for prompt in self.client.list_gateway_prompts(gateway)},
{
"repository-engineer",
"repository-change-review",
"repository-maintenance",
"portfolio-engineer",
"release-readiness",
},
)
def test_ensure_gateway_reactivates_runtime_deactivated_gateway(self) -> None:
first = self.client.ensure_gateway(self.desired)
self.fake.gateways[first.external_id]["status"] = "offline"
recovered = self.client.ensure_gateway(self.desired)
self.assertEqual(recovered.external_id, first.external_id)
self.assertEqual(recovered.snapshot.status, "active")
self.assertTrue(
any(
method == "PUT" and path == f"/gateways/{first.external_id}"
for method, path, _ in self.fake.requests
)
)
def test_uses_original_tool_name_for_catalog_allowlist_matching(self) -> None:
gateway = self.client.ensure_gateway(self.desired)
self.fake.tools[gateway.external_id] = [
{
"id": "33333333-3333-4333-8333-333333333333",
"name": "knowledge-dev-knowledge-document-search",
"originalName": "knowledge.document.search",
"customName": "knowledge.document.search",
}
]
tools = self.client.list_gateway_tools(gateway)
self.assertEqual(len(tools), 1)
self.assertEqual(tools[0].name, "knowledge.document.search")
self.assertEqual(tools[0].published_name, "knowledge.document.search")
self.assertEqual(tools[0].external_id, "33333333-3333-4333-8333-333333333333")
def test_canonicalizes_contextforge_prefixed_tool_name_once(self) -> None:
gateway = self.client.ensure_gateway(self.desired)
external_id = "33333333-3333-4333-8333-333333333333"
self.fake.tools[gateway.external_id] = [
{
"id": external_id,
"name": "knowledge-dev-knowledge-document-search",
"originalName": "knowledge.document.search",
"customName": "knowledge-dev-knowledge-document-search",
}
]
canonical = self.client.ensure_canonical_tool_names(self.client.list_gateway_tools(gateway))
self.assertEqual(canonical[0].published_name, "knowledge.document.search")
self.assertEqual(
self.fake.tools[gateway.external_id][0]["customName"],
"knowledge.document.search",
)
self.client.ensure_canonical_tool_names(canonical)
updates = [
request
for request in self.fake.requests
if request[0] == "PUT" and request[1] == f"/tools/{external_id}"
]
self.assertEqual(len(updates), 1)
def test_reads_gateway_tool_input_schema_in_both_supported_key_styles(self) -> None:
gateway = self.client.ensure_gateway(self.desired)
self.fake.tools[gateway.external_id] = [
{
"id": "33333333-3333-4333-8333-333333333333",
"name": "knowledge.document.search",
"input_schema": {"type": "object", "required": ["query"]},
}
]
tool = self.client.list_gateway_tools(gateway)[0]
self.assertEqual(tool.input_schema, {"type": "object", "required": ["query"]})
def test_basic_compatibility_auth_is_encoded_and_never_logged(self) -> None:
settings = ContextForgeSettings(
base_url="https://fake.contextforge.test",
auth_token_env="CTX_PASSWORD", # noqa: S106
auth_scheme="Basic",
basic_username="bootstrap-admin",
)
client = ContextForgeClient(
settings,
transport=self.fake.transport(),
environ={"CTX_PASSWORD": "password-never-logged"},
)
try:
headers = client._auth_headers()
encoded = headers["Authorization"].removeprefix("Basic ")
self.assertEqual(
b64decode(encoded).decode("utf-8"),
"bootstrap-admin:password-never-logged",
)
client.health()
self.assertNotIn("password-never-logged", str(self.fake.requests))
finally:
client.close()
def test_missing_auth_and_stable_gateway_error_mapping(self) -> None:
settings = ContextForgeSettings(
base_url="https://fake.contextforge.test",
auth_token_env="MISSING_TOKEN", # noqa: S106
)
missing = ContextForgeClient(settings, transport=self.fake.transport(), environ={})
try:
with self.assertRaises(ContextForgeError) as raised:
missing.health()
self.assertEqual(raised.exception.code, "gateway_credentials_missing")
finally:
missing.close()
no_retry_settings = settings.model_copy(update={"retries": 0})
no_retry = ContextForgeClient(
no_retry_settings,
transport=self.fake.transport(),
environ={"MISSING_TOKEN": "token"},
)
try:
self.fake.fail_next = 503
with self.assertRaises(ContextForgeError) as raised:
no_retry.health()
self.assertEqual(raised.exception.code, "gateway_unavailable")
self.assertTrue(raised.exception.retryable)
finally:
no_retry.close()
if __name__ == "__main__":
unittest.main()