279 lines
8.2 KiB
Python
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
|