Files
7000pctAUTO 45f26a18ac
Some checks failed
CI / test (push) Has been cancelled
CI / build (push) Has been cancelled
Add generators and mock server modules
2026-02-06 04:49:20 +00:00

279 lines
8.2 KiB
Python

"""Mock server generator for Prism/OpenAPI mock support."""
import json
from pathlib import Path
from typing import Any, Dict, List, Optional
from ..core import SpecParser
class MockServerGenerator:
"""Generate Prism/OpenAPI mock server configurations."""
DEFAULT_PORT = 4010
DEFAULT_HOST = "0.0.0.0"
def __init__(
self,
spec_parser: SpecParser,
output_dir: str = ".",
):
"""Initialize the mock server generator.
Args:
spec_parser: The OpenAPI specification parser.
output_dir: Directory for generated configuration files.
"""
self.spec_parser = spec_parser
self.output_dir = Path(output_dir)
def generate(
self,
prism_config: bool = True,
docker_compose: bool = True,
dockerfile: bool = True,
) -> List[Path]:
"""Generate mock server configuration files.
Args:
prism_config: Whether to generate prism-config.json.
docker_compose: Whether to generate docker-compose.yml.
dockerfile: Whether to generate Dockerfile.
Returns:
List of generated file paths.
"""
self.output_dir.mkdir(parents=True, exist_ok=True)
generated_files = []
if prism_config:
generated_files.append(self.generate_prism_config())
if docker_compose:
generated_files.append(self.generate_docker_compose())
if dockerfile:
generated_files.append(self.generate_dockerfile())
return generated_files
def generate_prism_config(self, output_file: Optional[str] = None) -> Path:
"""Generate Prism mock server configuration.
Args:
output_file: Optional output file path.
Returns:
Path to the generated file.
"""
if output_file:
output_path = Path(output_file)
else:
output_path = self.output_dir / "prism-config.json"
config = {
"mock": {
"host": self.DEFAULT_HOST,
"port": self.DEFAULT_PORT,
"cors": {
"enabled": True,
"allowOrigin": "*",
"allowMethods": ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"],
"allowHeaders": ["Content-Type", "Authorization", "X-API-Key"],
},
"Validation": {
"request": True,
"response": True,
},
},
"logging": {
"level": "info",
"format": "json",
},
}
output_path.write_text(json.dumps(config, indent=2))
return output_path
def generate_docker_compose(self, output_file: Optional[str] = None) -> Path:
"""Generate Docker Compose configuration for mock server.
Args:
output_file: Optional output file path.
Returns:
Path to the generated file.
"""
if output_file:
output_path = Path(output_file)
else:
output_path = self.output_dir / "docker-compose.yml"
spec_info = self.spec_parser.get_info()
compose_content = f'''version: '3.8'
services:
mock-server:
image: stoplight/prism:latest
container_name: "{spec_info['title']}-mock-server"
command: >
mock
--spec /app/openapi.yaml
--port {self.DEFAULT_PORT}
--host {self.DEFAULT_HOST}
ports:
- "{self.DEFAULT_PORT}:{self.DEFAULT_PORT}"
volumes:
- ./:/app
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-q", "--spider", f"http://localhost:{self.DEFAULT_PORT}/health"]
interval: 30s
timeout: 10s
retries: 3
mock-server-https:
image: stoplight/prism:latest
container_name: "{spec_info['title']}-mock-server-https"
command: >
mock
--spec /app/openapi.yaml
--port {self.DEFAULT_PORT + 1}
--host {self.DEFAULT_HOST}
ports:
- "{self.DEFAULT_PORT + 1}:{self.DEFAULT_PORT + 1}"
volumes:
- ./:/app
restart: unless-stopped
'''
output_path.write_text(compose_content)
return output_path
def generate_dockerfile(self, output_file: Optional[str] = None) -> Path:
"""Generate Dockerfile for mock server.
Args:
output_file: Optional output file path.
Returns:
Path to the generated file.
"""
if output_file:
output_path = Path(output_file)
else:
output_path = self.output_dir / "Dockerfile"
spec_info = self.spec_parser.get_info()
dockerfile_content = f'''FROM stoplight/prism:latest
LABEL maintainer="developer@example.com"
LABEL description="Mock server for {spec_info['title']} API"
WORKDIR /app
COPY openapi.yaml .
EXPOSE {self.DEFAULT_PORT}
CMD ["mock", "--spec", "openapi.yaml", "--port", "{self.DEFAULT_PORT}", "--host", "0.0.0.0"]
'''
output_path.write_text(dockerfile_content)
return output_path
def generate_start_script(self, output_file: Optional[str] = None) -> Path:
"""Generate shell script to start mock server.
Args:
output_file: Optional output file path.
Returns:
Path to the generated file.
"""
if output_file:
output_path = Path(output_file)
else:
output_path = self.output_dir / "start-mock-server.sh"
script_content = f'''#!/bin/bash
set -e
SCRIPT_DIR="$(cd "$(dirname "${{BASH_SOURCE[0]}}")" && pwd)"
cd "$SCRIPT_DIR"
PORT={self.DEFAULT_PORT}
HOST="0.0.0.0"
echo "Starting mock server for API..."
echo "Mock server will be available at: http://localhost:$PORT"
docker compose up -d mock-server
echo "Mock server started successfully!"
echo "To stop: docker compose down"
'''
output_path.write_text(script_content)
output_path.chmod(0o755)
return output_path
def generate_health_check(self) -> Path:
"""Generate health check endpoint configuration.
Returns:
Path to the generated file.
"""
output_path = self.output_dir / "health-check.json"
spec_info = self.spec_parser.get_info()
health_check = {
"openapi": self.spec_parser.version,
"info": {
"title": f"{spec_info['title']} - Health Check",
"version": spec_info["version"],
"description": "Health check endpoint for the mock server",
},
"paths": {
"/health": {
"get": {
"summary": "Health check endpoint",
"description": "Returns the health status of the mock server",
"operationId": "healthCheck",
"responses": {
"200": {
"description": "Mock server is healthy",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["healthy"],
},
"api": {
"type": "string",
},
"version": {
"type": "string",
},
},
},
}
},
}
},
}
}
},
}
output_path.write_text(json.dumps(health_check, indent=2))
return output_path