Files
cleveragents-core/features/steps/server_endpoints_steps.py
T
freemo a6f3bd3841 feat(discovery): Add comprehensive data contracts documentation and validation framework
This commit adds JSON/YAML schemas, Python stubs, fixture examples, and comprehensive test coverage for data contracts across all modules (auth, AI models, contexts, plans, orgs, etc.). Implements automated validation through Behave and
2025-11-01 23:33:12 -04:00

249 lines
9.2 KiB
Python

"""Step definitions for server endpoint extraction features."""
import json
from pathlib import Path
import yaml
from behave import given, then, when
@given("the server endpoint extractor is initialized")
def step_initialize_server_extractor(context):
"""Initialize the server endpoint extractor."""
from cleveragents.discovery.server_endpoints import ServerEndpointExtractor
context.server_extractor = ServerEndpointExtractor()
@when("I run the server endpoint extraction")
def step_run_server_extraction(context):
"""Run the server endpoint extraction."""
context.server_inventory = context.server_extractor.extract_endpoints()
context.extraction_succeeded = context.server_inventory is not None
@then("at least {count:d} endpoints should be extracted")
def step_check_endpoint_count(context, count):
"""Check minimum number of endpoints extracted."""
actual = context.server_inventory["statistics"]["total_endpoints"]
assert actual >= count, f"Expected at least {count} endpoints, got {actual}"
@then("the inventory should include endpoint metadata")
def step_check_endpoint_metadata(context):
"""Check that endpoint metadata is included."""
assert "metadata" in context.server_inventory
assert "statistics" in context.server_inventory
assert "endpoints_by_category" in context.server_inventory
assert "all_endpoints" in context.server_inventory
@then("the server inventory can be saved")
def step_server_inventory_can_be_saved(context):
"""Verify server inventory can be saved."""
# For server endpoints, we just verify that we could save if we wanted to
# The actual save is done separately
assert hasattr(context, "server_extractor")
assert hasattr(context, "server_inventory")
@given("the server endpoints have been extracted")
def step_extract_server_endpoints(context):
"""Extract server endpoints if not already done."""
if not hasattr(context, "server_inventory"):
from cleveragents.discovery.server_endpoints import ServerEndpointExtractor
context.server_extractor = ServerEndpointExtractor()
context.server_inventory = context.server_extractor.extract_endpoints()
# Always ensure endpoints attribute is populated
context.endpoints = context.server_inventory["all_endpoints"]
@when("I check the endpoint structure")
def step_check_endpoint_structure(context):
"""Check endpoint structure."""
context.endpoints = context.server_inventory["all_endpoints"]
@then("each endpoint should have a path")
def step_check_endpoint_paths(context):
"""Check all endpoints have paths."""
for endpoint in context.endpoints:
assert "path" in endpoint, f"Endpoint missing path: {endpoint}"
assert endpoint["path"], f"Endpoint has empty path: {endpoint}"
@then("each endpoint should have a method")
def step_check_endpoint_methods(context):
"""Check all endpoints have methods."""
for endpoint in context.endpoints:
assert "method" in endpoint, f"Endpoint missing method: {endpoint}"
assert endpoint["method"], f"Endpoint has empty method: {endpoint}"
@then("each endpoint should have a handler")
def step_check_endpoint_handlers(context):
"""Check all endpoints have handlers."""
for endpoint in context.endpoints:
assert "handler" in endpoint, f"Endpoint missing handler: {endpoint}"
assert endpoint["handler"], f"Endpoint has empty handler: {endpoint}"
@then("streaming endpoints should be identified")
def step_check_streaming_endpoints(context):
"""Check that streaming endpoints are identified."""
streaming_count = context.server_inventory["statistics"]["streaming_endpoints"]
assert streaming_count > 0, "No streaming endpoints identified"
# Check that some endpoints have is_streaming flag
streaming = [e for e in context.endpoints if e.get("is_streaming")]
assert len(streaming) == streaming_count
@when("I save the server endpoint inventory")
def step_save_server_inventory(context):
"""Save the server endpoint inventory."""
if not hasattr(context, "server_extractor"):
from cleveragents.discovery.server_endpoints import ServerEndpointExtractor
context.server_extractor = ServerEndpointExtractor()
context.server_inventory = context.server_extractor.extract_endpoints()
context.yaml_path, context.json_path = context.server_extractor.save_inventory()
@then('an OpenAPI spec should be created at "{path}"')
def step_check_openapi_spec(context, path):
"""Check OpenAPI spec file creation."""
spec_path = Path(path)
assert spec_path.exists(), f"OpenAPI spec not found at {path}"
# Validate it's a valid YAML file with OpenAPI structure
with open(spec_path) as f:
spec = yaml.safe_load(f)
assert "openapi" in spec, "Invalid OpenAPI spec - missing openapi version"
assert "info" in spec, "Invalid OpenAPI spec - missing info section"
assert "paths" in spec, "Invalid OpenAPI spec - missing paths section"
@then("all files should contain consistent data")
def step_check_file_consistency(context):
"""Check that all output files contain consistent data."""
with open(context.yaml_path) as f:
yaml_data = yaml.safe_load(f)
with open(context.json_path) as f:
json_data = json.load(f)
# Check that YAML and JSON have same endpoint count
yaml_count = yaml_data["statistics"]["total_endpoints"]
json_count = json_data["statistics"]["total_endpoints"]
assert yaml_count == json_count, (
f"Inconsistent endpoint count: YAML={yaml_count}, JSON={json_count}"
)
@when("I check endpoint categorization")
def step_check_categorization(context):
"""Check endpoint categorization."""
context.categories = context.server_inventory["endpoints_by_category"]
@then("endpoints should be grouped by category")
def step_check_category_groups(context):
"""Check that endpoints are grouped by category."""
assert len(context.categories) > 0, "No categories found"
# Check each category has endpoints
for category, endpoints in context.categories.items():
assert len(endpoints) > 0, f"Category '{category}' has no endpoints"
@then("categories should include {category}")
def step_check_specific_category(context, category):
"""Check for specific category."""
assert category in context.categories, (
f"Category '{category}' not found. Available: {list(context.categories.keys())}"
)
@when("I check for path parameters")
def step_check_path_params(context):
"""Check for path parameters."""
context.params_endpoints = [
e
for e in context.endpoints
if e.get("path_params") and len(e["path_params"]) > 0
]
@then("endpoints with path parameters should be identified")
def step_check_param_endpoints(context):
"""Check that endpoints with path parameters are identified."""
assert len(context.params_endpoints) > 0, "No endpoints with path parameters found"
@then("path parameter names should be extracted")
def step_check_param_names(context):
"""Check that parameter names are extracted."""
for endpoint in context.params_endpoints:
assert "path_params" in endpoint
assert isinstance(endpoint["path_params"], list)
assert all(isinstance(p, str) for p in endpoint["path_params"])
@then("parameters like {param} and {param2} should be found")
def step_check_specific_params(context, param, param2):
"""Check for specific parameters."""
all_params = set()
for endpoint in context.params_endpoints:
all_params.update(endpoint["path_params"])
assert param in all_params, (
f"Parameter '{param}' not found. Available: {all_params}"
)
assert param2 in all_params, (
f"Parameter '{param2}' not found. Available: {all_params}"
)
@when("I check authentication requirements")
def step_check_auth_requirements(context):
"""Check authentication requirements."""
context.public_endpoints = [
e for e in context.endpoints if not e.get("requires_auth", True)
]
context.protected_endpoints = [
e for e in context.endpoints if e.get("requires_auth", True)
]
@then("public endpoints should be identified")
def step_check_public_endpoints(context):
"""Check that public endpoints are identified."""
assert len(context.public_endpoints) > 0, "No public endpoints found"
@then("protected endpoints should be identified")
def step_check_protected_endpoints(context):
"""Check that protected endpoints are identified."""
assert len(context.protected_endpoints) > 0, "No protected endpoints found"
@then("{endpoint} and {endpoint2} endpoints should be public")
def step_check_specific_public(context, endpoint, endpoint2):
"""Check specific endpoints are public."""
public_paths = [e["path"] for e in context.public_endpoints]
# Check if endpoints contain the keywords
health_found = any(endpoint.lower() in path.lower() for path in public_paths)
version_found = any(endpoint2.lower() in path.lower() for path in public_paths)
assert health_found, (
f"'{endpoint}' endpoint not found in public endpoints: {public_paths}"
)
assert version_found, (
f"'{endpoint2}' endpoint not found in public endpoints: {public_paths}"
)