Files
fuzzforge_ai/fuzzforge-mcp/tests/test_resources.py

190 lines
7.4 KiB
Python

"""TODO."""
from datetime import UTC, datetime
from http import HTTPMethod
from json import loads
from typing import TYPE_CHECKING, cast
from fuzzforge_sdk.api.responses.executions import (
GetFuzzForgeModuleExecutionsResponse,
GetFuzzForgeWorkflowExecutionsResponse,
ModuleExecutionSummary,
WorkflowExecutionSummary,
)
from fuzzforge_sdk.api.responses.modules import (
GetFuzzForgeModuleDefinitionResponse,
GetFuzzForgeModuleDefinitionsResponse,
ModuleDefinitionSummary,
)
from fuzzforge_types import FuzzForgeExecutionStatus, FuzzForgeModule
if TYPE_CHECKING:
from collections.abc import Callable
from fastmcp import Client
from fastmcp.client import FastMCPTransport
from fuzzforge_types import (
FuzzForgeExecutionIdentifier,
FuzzForgeModuleIdentifier,
FuzzForgeProjectIdentifier,
FuzzForgeWorkflowIdentifier,
)
from mcp.types import TextResourceContents
from pytest_httpx import HTTPXMock
async def test_get_fuzzforge_module_when_server_returns_valid_data(
httpx_mock: HTTPXMock,
mcp_client: Client[FastMCPTransport],
random_module_description: Callable[[], str],
random_module_identifier: Callable[[], FuzzForgeModuleIdentifier],
random_module_name: Callable[[], str],
) -> None:
"""TODO."""
module = GetFuzzForgeModuleDefinitionResponse(
module_description=random_module_description(),
module_identifier=random_module_identifier(),
module_name=random_module_name(),
created_at=datetime.now(tz=UTC),
updated_at=datetime.now(tz=UTC),
)
httpx_mock.add_response(
json=module.model_dump(mode="json"),
method=HTTPMethod.GET,
url=f"http://127.0.0.1:8000/modules/{module.module_identifier}",
)
response = FuzzForgeModule.model_validate_json(
json_data=cast(
"TextResourceContents",
(await mcp_client.read_resource(f"fuzzforge://modules/{module.module_identifier}"))[0],
).text,
)
assert response.module_description == module.module_description
assert response.module_identifier == module.module_identifier
assert response.module_name == module.module_name
async def test_get_fuzzforge_modules_when_server_returns_valid_data(
httpx_mock: HTTPXMock,
mcp_client: Client[FastMCPTransport],
random_module_description: Callable[[], str],
random_module_identifier: Callable[[], FuzzForgeModuleIdentifier],
random_module_name: Callable[[], str],
) -> None:
"""TODO."""
modules = [
ModuleDefinitionSummary(
module_description=random_module_description(),
module_identifier=random_module_identifier(),
module_name=random_module_name(),
created_at=datetime.now(tz=UTC),
updated_at=datetime.now(tz=UTC),
),
ModuleDefinitionSummary(
module_description=random_module_description(),
module_identifier=random_module_identifier(),
module_name=random_module_name(),
created_at=datetime.now(tz=UTC),
updated_at=datetime.now(tz=UTC),
),
]
httpx_mock.add_response(
json=GetFuzzForgeModuleDefinitionsResponse(
modules=modules,
total=2,
limit=100,
offset=0,
).model_dump(mode="json"),
method=HTTPMethod.GET,
url="http://127.0.0.1:8000/modules",
)
response = [
ModuleDefinitionSummary.model_validate(entry)
for entry in loads(
cast("TextResourceContents", (await mcp_client.read_resource("fuzzforge://modules/"))[0]).text
)
]
assert len(response) == len(modules)
for expected, module in zip(modules, response, strict=True):
assert module.module_description == expected.module_description
assert module.module_identifier == expected.module_identifier
assert module.module_name == expected.module_name
async def test_get_executions_when_server_returns_valid_data(
httpx_mock: HTTPXMock,
mcp_client: Client[FastMCPTransport],
random_module_identifier: Callable[[], FuzzForgeModuleIdentifier],
random_module_execution_identifier: Callable[[], FuzzForgeExecutionIdentifier],
random_workflow_identifier: Callable[[], FuzzForgeWorkflowIdentifier],
random_workflow_execution_identifier: Callable[[], FuzzForgeExecutionIdentifier],
) -> None:
"""TODO."""
project_identifier: FuzzForgeProjectIdentifier = mcp_client.transport.server._lifespan_result.PROJECT_IDENTIFIER # type: ignore[union-attr] # noqa: SLF001
modules = [
ModuleExecutionSummary(
execution_identifier=random_module_execution_identifier(),
module_identifier=random_module_identifier(),
execution_status=FuzzForgeExecutionStatus.PENDING,
error=None,
created_at=datetime.now(tz=UTC),
updated_at=datetime.now(tz=UTC),
),
ModuleExecutionSummary(
execution_identifier=random_module_execution_identifier(),
module_identifier=random_module_identifier(),
execution_status=FuzzForgeExecutionStatus.PENDING,
error=None,
created_at=datetime.now(tz=UTC),
updated_at=datetime.now(tz=UTC),
),
]
workflows = [
WorkflowExecutionSummary(
execution_identifier=random_workflow_execution_identifier(),
workflow_identifier=random_workflow_identifier(),
workflow_status=FuzzForgeExecutionStatus.PENDING,
error=None,
created_at=datetime.now(tz=UTC),
updated_at=datetime.now(tz=UTC),
),
WorkflowExecutionSummary(
execution_identifier=random_workflow_execution_identifier(),
workflow_identifier=random_workflow_identifier(),
workflow_status=FuzzForgeExecutionStatus.PENDING,
error=None,
created_at=datetime.now(tz=UTC),
updated_at=datetime.now(tz=UTC),
),
]
httpx_mock.add_response(
json=GetFuzzForgeModuleExecutionsResponse(
executions=modules,
project_identifier=project_identifier,
total=2,
).model_dump(mode="json"),
method=HTTPMethod.GET,
url=f"http://127.0.0.1:8000/projects/{project_identifier}/modules",
)
httpx_mock.add_response(
json=GetFuzzForgeWorkflowExecutionsResponse(
workflows=workflows,
project_identifier=project_identifier,
total=2,
).model_dump(mode="json"),
method=HTTPMethod.GET,
url=f"http://127.0.0.1:8000/projects/{project_identifier}/workflows",
)
response = loads(cast("TextResourceContents", (await mcp_client.read_resource("fuzzforge://executions/"))[0]).text)
assert len(response) == len(modules) + len(workflows)
for expected_module, module in zip(
modules, [ModuleExecutionSummary.model_validate(entry) for entry in response[: len(modules)]], strict=True
):
assert module.execution_identifier == expected_module.execution_identifier
assert module.module_identifier == expected_module.module_identifier
for expected_workflow, workflow in zip(
workflows, [WorkflowExecutionSummary.model_validate(entry) for entry in response[len(workflows) :]], strict=True
):
assert workflow.execution_identifier == expected_workflow.execution_identifier
assert workflow.workflow_identifier == expected_workflow.workflow_identifier