forked from cleveragents/cleveragents-core
a6f3bd3841
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
249 lines
9.2 KiB
Python
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}"
|
|
)
|