Fix linting issues in API tests
This commit is contained in:
@@ -1,111 +1,109 @@
|
||||
"""
|
||||
Utilities for working with OpenAPI schemas
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional, Set, Tuple
|
||||
|
||||
|
||||
def extract_required_parameters(
|
||||
spec: Dict[str, Any],
|
||||
path: str,
|
||||
spec: Dict[str, Any],
|
||||
path: str,
|
||||
method: str
|
||||
) -> Tuple[List[Dict[str, Any]], List[Dict[str, Any]]]:
|
||||
"""
|
||||
Extract required parameters for a specific endpoint
|
||||
|
||||
|
||||
Args:
|
||||
spec: Parsed OpenAPI specification
|
||||
path: API path (e.g., '/prompt')
|
||||
method: HTTP method (e.g., 'get', 'post')
|
||||
|
||||
|
||||
Returns:
|
||||
Tuple of (path_params, query_params) containing required parameters
|
||||
"""
|
||||
method = method.lower()
|
||||
path_params = []
|
||||
query_params = []
|
||||
|
||||
|
||||
# Handle path not found
|
||||
if path not in spec['paths']:
|
||||
return path_params, query_params
|
||||
|
||||
|
||||
# Handle method not found
|
||||
if method not in spec['paths'][path]:
|
||||
return path_params, query_params
|
||||
|
||||
|
||||
# Get parameters
|
||||
params = spec['paths'][path][method].get('parameters', [])
|
||||
|
||||
|
||||
for param in params:
|
||||
if param.get('required', False):
|
||||
if param.get('in') == 'path':
|
||||
path_params.append(param)
|
||||
elif param.get('in') == 'query':
|
||||
query_params.append(param)
|
||||
|
||||
|
||||
return path_params, query_params
|
||||
|
||||
|
||||
def get_request_body_schema(
|
||||
spec: Dict[str, Any],
|
||||
path: str,
|
||||
spec: Dict[str, Any],
|
||||
path: str,
|
||||
method: str
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Get request body schema for a specific endpoint
|
||||
|
||||
|
||||
Args:
|
||||
spec: Parsed OpenAPI specification
|
||||
path: API path (e.g., '/prompt')
|
||||
method: HTTP method (e.g., 'get', 'post')
|
||||
|
||||
|
||||
Returns:
|
||||
Request body schema or None if not found
|
||||
"""
|
||||
method = method.lower()
|
||||
|
||||
|
||||
# Handle path not found
|
||||
if path not in spec['paths']:
|
||||
return None
|
||||
|
||||
|
||||
# Handle method not found
|
||||
if method not in spec['paths'][path]:
|
||||
return None
|
||||
|
||||
|
||||
# Handle no request body
|
||||
request_body = spec['paths'][path][method].get('requestBody', {})
|
||||
if not request_body or 'content' not in request_body:
|
||||
return None
|
||||
|
||||
|
||||
# Get schema from first content type
|
||||
content_types = request_body['content']
|
||||
first_content_type = next(iter(content_types))
|
||||
|
||||
|
||||
if 'schema' not in content_types[first_content_type]:
|
||||
return None
|
||||
|
||||
|
||||
return content_types[first_content_type]['schema']
|
||||
|
||||
|
||||
def extract_endpoints_by_tag(spec: Dict[str, Any], tag: str) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Extract all endpoints with a specific tag
|
||||
|
||||
|
||||
Args:
|
||||
spec: Parsed OpenAPI specification
|
||||
tag: Tag to filter by
|
||||
|
||||
|
||||
Returns:
|
||||
List of endpoint details
|
||||
"""
|
||||
endpoints = []
|
||||
|
||||
|
||||
for path, path_item in spec['paths'].items():
|
||||
for method, operation in path_item.items():
|
||||
if method.lower() not in ['get', 'post', 'put', 'delete', 'patch']:
|
||||
continue
|
||||
|
||||
|
||||
if tag in operation.get('tags', []):
|
||||
endpoints.append({
|
||||
'path': path,
|
||||
@@ -113,47 +111,47 @@ def extract_endpoints_by_tag(spec: Dict[str, Any], tag: str) -> List[Dict[str, A
|
||||
'operation_id': operation.get('operationId', ''),
|
||||
'summary': operation.get('summary', '')
|
||||
})
|
||||
|
||||
|
||||
return endpoints
|
||||
|
||||
|
||||
def get_all_tags(spec: Dict[str, Any]) -> Set[str]:
|
||||
"""
|
||||
Get all tags used in the API spec
|
||||
|
||||
|
||||
Args:
|
||||
spec: Parsed OpenAPI specification
|
||||
|
||||
|
||||
Returns:
|
||||
Set of tag names
|
||||
"""
|
||||
tags = set()
|
||||
|
||||
|
||||
for path_item in spec['paths'].values():
|
||||
for operation in path_item.values():
|
||||
if isinstance(operation, dict) and 'tags' in operation:
|
||||
tags.update(operation['tags'])
|
||||
|
||||
|
||||
return tags
|
||||
|
||||
|
||||
def get_schema_examples(spec: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Extract all examples from component schemas
|
||||
|
||||
|
||||
Args:
|
||||
spec: Parsed OpenAPI specification
|
||||
|
||||
|
||||
Returns:
|
||||
Dict mapping schema names to examples
|
||||
"""
|
||||
examples = {}
|
||||
|
||||
|
||||
if 'components' not in spec or 'schemas' not in spec['components']:
|
||||
return examples
|
||||
|
||||
|
||||
for name, schema in spec['components']['schemas'].items():
|
||||
if 'example' in schema:
|
||||
examples[name] = schema['example']
|
||||
|
||||
return examples
|
||||
|
||||
return examples
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
"""
|
||||
Utilities for API response validation against OpenAPI spec
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import yaml
|
||||
import jsonschema
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
@@ -11,10 +9,10 @@ from typing import Any, Dict, List, Optional, Union
|
||||
def load_openapi_spec(spec_path: str) -> Dict[str, Any]:
|
||||
"""
|
||||
Load the OpenAPI specification from a YAML file
|
||||
|
||||
|
||||
Args:
|
||||
spec_path: Path to the OpenAPI specification file
|
||||
|
||||
|
||||
Returns:
|
||||
Dict containing the parsed OpenAPI spec
|
||||
"""
|
||||
@@ -23,68 +21,68 @@ def load_openapi_spec(spec_path: str) -> Dict[str, Any]:
|
||||
|
||||
|
||||
def get_endpoint_schema(
|
||||
spec: Dict[str, Any],
|
||||
path: str,
|
||||
method: str,
|
||||
spec: Dict[str, Any],
|
||||
path: str,
|
||||
method: str,
|
||||
status_code: str = '200'
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
Extract response schema for a specific endpoint from OpenAPI spec
|
||||
|
||||
|
||||
Args:
|
||||
spec: Parsed OpenAPI specification
|
||||
path: API path (e.g., '/prompt')
|
||||
method: HTTP method (e.g., 'get', 'post')
|
||||
status_code: HTTP status code to get schema for
|
||||
|
||||
|
||||
Returns:
|
||||
Schema dict or None if not found
|
||||
"""
|
||||
method = method.lower()
|
||||
|
||||
|
||||
# Handle path not found
|
||||
if path not in spec['paths']:
|
||||
return None
|
||||
|
||||
|
||||
# Handle method not found
|
||||
if method not in spec['paths'][path]:
|
||||
return None
|
||||
|
||||
|
||||
# Handle status code not found
|
||||
responses = spec['paths'][path][method].get('responses', {})
|
||||
if status_code not in responses:
|
||||
return None
|
||||
|
||||
|
||||
# Handle no content defined
|
||||
if 'content' not in responses[status_code]:
|
||||
return None
|
||||
|
||||
|
||||
# Get schema from first content type
|
||||
content_types = responses[status_code]['content']
|
||||
first_content_type = next(iter(content_types))
|
||||
|
||||
|
||||
if 'schema' not in content_types[first_content_type]:
|
||||
return None
|
||||
|
||||
|
||||
return content_types[first_content_type]['schema']
|
||||
|
||||
|
||||
def resolve_schema_refs(schema: Dict[str, Any], spec: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Resolve $ref references in a schema
|
||||
|
||||
|
||||
Args:
|
||||
schema: Schema that may contain references
|
||||
spec: Full OpenAPI spec with component definitions
|
||||
|
||||
|
||||
Returns:
|
||||
Schema with references resolved
|
||||
"""
|
||||
if not isinstance(schema, dict):
|
||||
return schema
|
||||
|
||||
|
||||
result = {}
|
||||
|
||||
|
||||
for key, value in schema.items():
|
||||
if key == '$ref' and isinstance(value, str) and value.startswith('#/'):
|
||||
# Handle reference
|
||||
@@ -92,7 +90,7 @@ def resolve_schema_refs(schema: Dict[str, Any], spec: Dict[str, Any]) -> Dict[st
|
||||
ref_value = spec
|
||||
for path_part in ref_path:
|
||||
ref_value = ref_value.get(path_part, {})
|
||||
|
||||
|
||||
# Recursively resolve any refs in the referenced schema
|
||||
ref_value = resolve_schema_refs(ref_value, spec)
|
||||
result.update(ref_value)
|
||||
@@ -108,7 +106,7 @@ def resolve_schema_refs(schema: Dict[str, Any], spec: Dict[str, Any]) -> Dict[st
|
||||
else:
|
||||
# Pass through other values
|
||||
result[key] = value
|
||||
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -121,30 +119,30 @@ def validate_response(
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Validate a response against the OpenAPI schema
|
||||
|
||||
|
||||
Args:
|
||||
response_data: Response data to validate
|
||||
spec: Parsed OpenAPI specification
|
||||
path: API path (e.g., '/prompt')
|
||||
method: HTTP method (e.g., 'get', 'post')
|
||||
status_code: HTTP status code to validate against
|
||||
|
||||
|
||||
Returns:
|
||||
Dict with validation result containing:
|
||||
- valid: bool indicating if validation passed
|
||||
- errors: List of validation errors if any
|
||||
"""
|
||||
schema = get_endpoint_schema(spec, path, method, status_code)
|
||||
|
||||
|
||||
if schema is None:
|
||||
return {
|
||||
'valid': False,
|
||||
'errors': [f"No schema found for {method.upper()} {path} with status {status_code}"]
|
||||
}
|
||||
|
||||
|
||||
# Resolve any $ref in the schema
|
||||
resolved_schema = resolve_schema_refs(schema, spec)
|
||||
|
||||
|
||||
try:
|
||||
jsonschema.validate(instance=response_data, schema=resolved_schema)
|
||||
return {'valid': True, 'errors': []}
|
||||
@@ -155,20 +153,20 @@ def validate_response(
|
||||
def get_all_endpoints(spec: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
Extract all endpoints from an OpenAPI spec
|
||||
|
||||
|
||||
Args:
|
||||
spec: Parsed OpenAPI specification
|
||||
|
||||
|
||||
Returns:
|
||||
List of dicts with path, method, and tags for each endpoint
|
||||
"""
|
||||
endpoints = []
|
||||
|
||||
|
||||
for path, path_item in spec['paths'].items():
|
||||
for method, operation in path_item.items():
|
||||
if method.lower() not in ['get', 'post', 'put', 'delete', 'patch']:
|
||||
continue
|
||||
|
||||
|
||||
endpoints.append({
|
||||
'path': path,
|
||||
'method': method.lower(),
|
||||
@@ -176,5 +174,5 @@ def get_all_endpoints(spec: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||
'operation_id': operation.get('operationId', ''),
|
||||
'summary': operation.get('summary', '')
|
||||
})
|
||||
|
||||
return endpoints
|
||||
|
||||
return endpoints
|
||||
|
||||
Reference in New Issue
Block a user