v0-json-schema

This commit is contained in:
gongwenxin
2025-05-16 15:18:02 +08:00
parent 32676a314f
commit 6d0b70fe11
260 changed files with 280278 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
@@ -0,0 +1,52 @@
"""Pydantic models for application configuration."""
from pydantic import BaseModel
from typing import Optional, Dict, Literal
# These models were previously in config/manager.py, moved here for better organization.
class APICallerConfig(BaseModel):
default_timeout: int = 30
default_headers: Optional[Dict[str, str]] = None
# Add other API caller specific configs: e.g., retry_attempts, backoff_factor
class JSONSchemaValidatorConfig(BaseModel):
default_draft_version: Optional[str] = None # e.g., "draft7", "draft2020-12"
# Add other schema validator specific configs
class RuleStorageConfig(BaseModel):
type: Literal["filesystem", "database", "in_memory"] = "filesystem"
path: Optional[str] = "./rules" # For filesystem adapter: path to rules directory
connection_string: Optional[str] = None # For database adapter
# Add other storage specific configs, e.g., for filesystem: file_pattern = "*.json"
class RuleRepositoryConfig(BaseModel):
storage: RuleStorageConfig = RuleStorageConfig()
default_version_strategy: Literal["latest_enabled", "latest_stable", "exact"] = "latest_enabled"
preload_rules: bool = False
# Add other rule repository specific configs
class LoggingConfig(BaseModel):
level: Literal["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"] = "INFO"
format: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
# file_path: Optional[str] = None # Optional: if logging to a file
class TestExecutorConfig(BaseModel):
# Add configurations specific to the Test Executor
# For example, default behavior for failing a test step, etc.
stop_on_first_failure: bool = False
class ReportGeneratorConfig(BaseModel):
# Add configurations specific to the Report Generator
output_format: Literal["json", "html", "xml"] = "json"
output_path: str = "./reports"
class AppConfig(BaseModel):
app_name: str = "DDMS Compliance Suite"
logging: LoggingConfig = LoggingConfig()
api_caller: APICallerConfig = APICallerConfig()
json_schema_validator: JSONSchemaValidatorConfig = JSONSchemaValidatorConfig()
rule_repository: RuleRepositoryConfig = RuleRepositoryConfig()
test_executor: TestExecutorConfig = TestExecutorConfig()
report_generator: ReportGeneratorConfig = ReportGeneratorConfig()
# input_parser: ... # Config for input parser if needed
# assertion_engine: ... # Config for assertion engine if needed
+190
View File
@@ -0,0 +1,190 @@
"""Base Pydantic models for the application."""
from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Any, Union, Literal
from enum import Enum
class SeverityLevel(str, Enum):
ERROR = "error"
WARNING = "warning"
INFO = "info"
class RuleCategory(str, Enum):
JSON_SCHEMA = "JSONSchema"
API_LINTING = "APILinting"
BUSINESS_LOGIC = "BusinessLogic"
DATA_QUALITY = "DataQuality"
SECURITY = "Security"
PERFORMANCE = "Performance"
MAPPING = "Mapping"
PYTHON_CODE = "PythonCode" # Python代码规则类别
API_DESIGN = "APIDesign" # API设计规则类别
ERROR_HANDLING = "ErrorHandling" # 错误处理规则类别
COMPATIBILITY = "Compatibility" # 兼容性规则类别
GENERIC = "Generic"
class TargetType(str, Enum):
API_REQUEST = "APIRequest"
API_RESPONSE = "APIResponse"
DATA_OBJECT = "DataObject"
OPENAPI_SPECIFICATION = "OpenAPISpecification"
GENERIC_TARGET = "GenericTarget"
class RuleLifecycle(str, Enum):
"""规则生命周期枚举,定义规则在测试流程中的适用阶段"""
REQUEST_PREPARATION = "请求准备阶段"
RESPONSE_VALIDATION = "响应验证阶段"
POST_VALIDATION = "后处理阶段"
API_SPECIFICATION_VALIDATION = "API规范验证阶段" # 新增的生命周期
ANY_STAGE = "任意阶段"
class RuleScope(str, Enum):
"""规则作用域枚举,定义规则针对的具体对象"""
REQUEST_URL = "请求URL"
REQUEST_HEADERS = "请求头"
REQUEST_PARAMS = "请求参数"
REQUEST_BODY = "请求体"
RESPONSE_STATUS = "响应状态码"
RESPONSE_HEADERS = "响应头"
RESPONSE_BODY = "响应体"
RESPONSE_TIME = "响应时间"
SECURITY = "安全性"
PERFORMANCE = "性能"
ANY_SCOPE = "任意作用域"
class BaseRule(BaseModel):
"""通用规则属性 (Pydantic基类 BaseRule)"""
id: str # 规则唯一ID
name: str # 规则名称
description: Optional[str] = None # 规则详细描述
category: RuleCategory # 规则类别
version: str = "1.0.0" # 版本号
severity: SeverityLevel = SeverityLevel.INFO # 严重性
source: Optional[str] = None # 规则来源 (例如 "PlatformStandard-XYZ", "OWASP-ASVS")
is_enabled: bool = True # 是否启用
tags: Optional[List[str]] = None # 规则标签 (如 "critical", "wellbore")
target_type: Optional[TargetType] = None # 规则适用目标类型 (描述性元数据)
target_identifier: Optional[str] = None # 规则适用目标的具体标识 (描述性元数据)
author: Optional[str] = None # 规则作者
# 新增字段
lifecycle: Optional[RuleLifecycle] = Field(
default=RuleLifecycle.ANY_STAGE,
description="规则的推荐适用阶段或类型。主要用于识别 API_SPECIFICATION_VALIDATION (静态分析) 规则。"
"对于其他动态规则,此字段为元数据提示,实际执行阶段由 TestStep 定义。"
)
scope: Optional[RuleScope] = Field(
default=RuleScope.ANY_SCOPE,
description="描述规则逻辑主要关注的API交互部分 (例如,请求头、响应体)。"
"此字段为描述性元数据,用于规则分类和理解,不作为执行时的强制约束。"
)
code: Optional[str] = None # 规则验证代码
class JSONSchemaDefinition(BaseRule):
"""JSON Schema 定义 (用于API请求/响应体结构验证)"""
category: Literal[RuleCategory.JSON_SCHEMA] = RuleCategory.JSON_SCHEMA
schema_content: Dict[str, Any] # 实际的JSON Schema
class APILintingRuleset(BaseRule):
"""API 设计规范/Linting规则 (例如,基于Spectral的OpenAPI规范校验规则集)"""
category: Literal[RuleCategory.API_LINTING] = RuleCategory.API_LINTING
ruleset_format: str = "spectral" # 例如 "spectral", "custom_json_rules"
ruleset_content: Union[str, Dict[str, Any]] # 规则集内容或其引用(例如,文件路径或URL,或直接嵌入的规则字典)
class BusinessAssertionTemplate(BaseRule):
"""业务逻辑断言模板或具体规则"""
category: Literal[RuleCategory.BUSINESS_LOGIC] = RuleCategory.BUSINESS_LOGIC
template_language: str = "python_expression" # 如 "python_expression", "jsonpath_assert"
template_expression: str
expected_parameters: Optional[List[str]] = None # 执行断言模板时需要输入的参数列表
class DataQualityRule(BaseRule):
"""数据质量校验规则"""
category: Literal[RuleCategory.DATA_QUALITY] = RuleCategory.DATA_QUALITY
# Specific fields for data quality rules, e.g.:
field_name: Optional[str] = None
validation_type: str # e.g., "regex", "range", "custom_function"
validation_expression: str # regex pattern, range boundaries, function name/path
class PythonCodeRule(BaseRule):
"""使用 Python 代码定义的规则
此类规则允许以 Python 代码片段形式定义复杂的验证逻辑,提供了最大的灵活性。
代码将在受控环境中执行,以确保安全性。
"""
category: Literal[RuleCategory.PYTHON_CODE] = RuleCategory.PYTHON_CODE
# Python 代码内容或文件路径
code_file: Optional[str] = None
# 脚本入口函数名,默认为 validate
entry_function: str = "validate"
# 预期的入口函数参数
expected_parameters: Optional[List[str]] = None
# 是否允许导入外部模块 (出于安全考虑,默认为 False)
allow_imports: bool = False
# 允许导入的模块列表 (如果 allow_imports 为 True)
allowed_modules: Optional[List[str]] = None
# 超时设置(秒),防止无限循环等恶意代码
timeout: int = 5
# 代码依赖的其他规则ID
depends_on: Optional[List[str]] = None
# 新增规则类型
class PerformanceRule(BaseRule):
"""性能相关规则,如响应时间、吞吐量等"""
category: Literal[RuleCategory.PERFORMANCE] = RuleCategory.PERFORMANCE
lifecycle: Literal[RuleLifecycle.RESPONSE_VALIDATION] = RuleLifecycle.RESPONSE_VALIDATION
scope: Literal[RuleScope.RESPONSE_TIME] = RuleScope.RESPONSE_TIME
threshold: Union[float, int] # 性能阈值
metric: str # 性能指标名称
unit: str = "ms" # 默认单位:毫秒
class SecurityRule(BaseRule):
"""安全相关规则,如身份验证、授权、加密等"""
category: Literal[RuleCategory.SECURITY] = RuleCategory.SECURITY
check_type: str # 安全检查类型(如认证、授权、加密等)
expected_value: Optional[str] = None # 预期值
class RESTfulDesignRule(BaseRule):
"""RESTful API设计规则,如HTTP方法使用、URL设计等"""
category: Literal[RuleCategory.API_DESIGN] = RuleCategory.API_DESIGN
design_aspect: str # 设计方面(如URL、HTTP方法、参数等)
pattern: Optional[str] = None # 匹配模式(如正则表达式)
class ErrorHandlingRule(BaseRule):
"""错误处理规则,如错误码、错误消息等"""
category: Literal[RuleCategory.ERROR_HANDLING] = RuleCategory.ERROR_HANDLING
error_code: str # 错误码
expected_status: int # 预期HTTP状态码
expected_message: Optional[str] = None # 预期错误消息
# 更新联合类型以包含新规则类型
AnyRule = Union[
JSONSchemaDefinition,
APILintingRuleset,
BusinessAssertionTemplate,
DataQualityRule,
PythonCodeRule,
PerformanceRule,
SecurityRule,
RESTfulDesignRule,
ErrorHandlingRule,
BaseRule # 通用或未明确分类的规则
]
class RuleQuery(BaseModel):
"""规则查询条件对象 (Pydantic模型)"""
rule_id: Optional[str] = None
category: Optional[RuleCategory] = None
target_type: Optional[TargetType] = None
target_identifier: Optional[str] = None
version: Optional[str] = "latest" # 或特殊标识 ("latest", "stable", or specific version)
tags: Optional[List[str]] = None
is_enabled: Optional[bool] = True # 默认查询已启用的规则
# 新增字段
lifecycle: Optional[RuleLifecycle] = None
scope: Optional[RuleScope] = None
+144
View File
@@ -0,0 +1,144 @@
"""
Pydantic models for Test Cases, Test Steps, and Test Suites.
"""
from typing import Optional, List, Dict, Any, Union, Literal
from pydantic import BaseModel, Field, HttpUrl
from enum import Enum
from .rule_models import SeverityLevel # Assuming rule_models.py is in the same directory
from ..api_caller.caller import APIRequest # Adjust path as necessary
class TestDataGenerationStrategy(str, Enum):
"""Defines how test data for an API request should be generated."""
STATIC = "static" # Data is explicitly provided
FROM_SCHEMA = "from_schema" # Data is generated based on OpenAPI/JSON schema
FROM_PREVIOUS_STEP = "from_previous_step" # Data is extracted from a previous test step's output
AI_GENERATED = "ai_generated" # Data is generated by an AI model
class TestDataGenerationConfig(BaseModel):
"""Configuration for generating test data for an API request."""
strategy: TestDataGenerationStrategy = TestDataGenerationStrategy.STATIC
# For STATIC strategy:
static_data: Optional[Dict[str, Any]] = Field(default=None, description="Explicit data for the request (e.g., body, params).")
# For FROM_SCHEMA strategy:
schema_source: Optional[str] = Field(default=None, description="Identifier for the schema to be used (e.g., operationId, or path to schema file).")
# For FROM_PREVIOUS_STEP strategy:
source_step_id: Optional[str] = Field(default=None, description="The ID of the previous TestStep whose output will be used.")
extraction_rules: Optional[Dict[str, str]] = Field(default_None, description="Rules to extract data (e.g., JSONPath expressions like {'user_id': '$.body.id'}).")
# For AI_GENERATED strategy:
ai_prompt: Optional[str] = Field(default=None, description="Prompt to be used by an AI model to generate data.")
ai_model_config: Optional[Dict[str, Any]] = Field(default_None, description="Configuration for the AI model (e.g., temperature, max_tokens).")
class APIRequestContext(BaseModel):
"""
Defines how to construct the APIRequest for a TestStep, potentially using
data from previous steps or other dynamic sources.
"""
method: str = Field(description="HTTP method (GET, POST, PUT, DELETE, etc.).")
url_template: str = Field(description="URL template, can contain placeholders like {base_url} or {resource_id}.")
path_params_source: Optional[Dict[str, TestDataGenerationConfig]] = Field(default_None, description="How to generate/get path parameters.")
query_params_source: Optional[Dict[str, TestDataGenerationConfig]] = Field(default_None, description="How to generate/get query parameters.")
headers_source: Optional[Dict[str, TestDataGenerationConfig]] = Field(default_None, description="How to generate/get request headers. Default headers can be added by the orchestrator.")
body_source: Optional[TestDataGenerationConfig] = Field(default_None, description="How to generate/get the request body.")
# Stores the actual APIRequest object after context resolution
# This field will be populated by the TestOrchestrator before execution.
resolved_request: Optional[APIRequest] = Field(default=None, exclude=True)
class TestStep(BaseModel):
"""
Represents a single step within a TestCase, typically involving one API call
and a set of rules to be validated against its request/response.
"""
step_id: str = Field(description="Unique identifier for this test step within the TestCase.")
description: Optional[str] = Field(default=None, description="Description of what this test step does.")
api_request_context: APIRequestContext = Field(description="Context to build the API request for this step.")
# Rules to be applied at different phases of this step
# Applied after the request is prepared but before it's sent.
# Useful for validating the constructed request itself.
request_preparation_rule_ids: List[str] = Field(default_factory=list, description="Rules to apply to the APIRequest before sending.")
# Applied after the API response is received. This is the most common place for validation rules.
response_validation_rule_ids: List[str] = Field(default_factory=list, description="Rules to apply to the APIResponse.")
# Applied after response validation, يمكن استخدامه لتنظيف البيانات أو إجراءات ما بعد الاختبار
post_validation_rule_ids: List[str] = Field(default_factory=list, description="Rules to apply after response validation (e.g., cleanup).")
# Configuration for expected outcomes, more specific than just rule pass/fail
expected_status_code: Optional[int] = Field(default=None, description="Expected HTTP status code.")
# Allows defining assertions on the response body using something like JSONPath
# e.g., {"$.data.status": "completed", "$.errors": null}
response_body_assertions: Optional[Dict[str, Any]] = Field(default_None, description="Assertions to make on the response body (e.g., using JSONPath).")
# Execution control
skip: bool = Field(default=False, description="If True, this test step will be skipped.")
# Allows storing output from this step to be used by subsequent steps
# e.g., {"created_user_id": "$.response.body.id"}
outputs_to_extract: Optional[Dict[str, str]] = Field(default_None, description="JSONPath expressions to extract data from response to be used in later steps.")
class TestCaseExecutionMode(str, Enum):
SEQUENTIAL = "sequential" # Steps are executed one after another
PARALLEL = "parallel" # Steps (if independent) can be executed in parallel
class TestCase(BaseModel):
"""
Defines a test case, which consists of one or more test steps,
metadata, and configurations for execution.
"""
id: str = Field(description="Unique identifier for the test case.")
name: str = Field(description="Name of the test case.")
description: Optional[str] = Field(default=None, description="Detailed description of the test case.")
tags: List[str] = Field(default_factory=list, description="Tags for categorizing and filtering test cases.")
severity: SeverityLevel = Field(default=SeverityLevel.INFO, description="Severity of the test case if it fails.")
author: Optional[str] = Field(default=None, description="Author of the test case.")
creation_date: Optional[str] = Field(default=None, description="Date when the test case was created (ISO format).") # Consider using datetime
version: str = Field(default="1.0.0", description="Version of the test case.")
# Test Steps
steps: List[TestStep] = Field(description="A list of test steps to be executed for this test case.")
execution_mode: TestCaseExecutionMode = Field(default=TestCaseExecutionMode.SEQUENTIAL, description="How the steps in this test case should be executed.")
# Data that can be shared across steps within this test case.
# Steps can read from and write to this context.
shared_context: Dict[str, Any] = Field(default_factory=dict, description="Data context televisão across steps.")
# Overall expected outcome for the test case (can be high-level)
expected_overall_result: Optional[str] = Field(default=None, description="A high-level description of the expected outcome for the entire test case.")
# For iterative/load testing
execution_count: int = Field(default=1, ge=1, description="Number of times this test case should be executed.")
# If > 1, defines delay between iterations in seconds.
delay_between_iterations_sec: float = Field(default=0, ge=0)
class TestSuite(BaseModel):
"""
A collection of TestCases, possibly with a shared configuration or setup/teardown logic.
"""
id: str = Field(description="Unique identifier for the test suite.")
name: str = Field(description="Name of the test suite.")
description: Optional[str] = Field(default=None, description="Description of the test suite.")
tags: List[str] = Field(default_factory=list, description="Tags for categorizing and filtering test suites.")
# List of TestCase IDs or full TestCase objects. Using IDs allows for referencing.
# For simplicity in this initial design, let's assume full TestCase objects.
# Later, we could support referencing TestCase definitions stored elsewhere.
test_cases: List[TestCase] = Field(default_factory=list, description="List of test cases included in this suite.")
# Global parameters or configurations that can apply to all TestCases in the suite
# These could override individual TestCase settings or provide defaults.
global_parameters: Optional[Dict[str, Any]] = Field(default_None, description="Parameters applicable to all test cases in the suite.")
# Setup: API calls or actions to perform before running any TestCase in the suite.
# Similar structure to TestStep but without specific rule validations, more for setup.
setup_steps: Optional[List[TestStep]] = Field(default_None, description="Steps to execute before running test cases in the suite.")
# Teardown: API calls or actions to perform after all TestCases in the suite have run.
teardown_steps: Optional[List[TestStep]] = Field(default_None, description="Steps to execute after running test cases in the suite.")
# Execution control for the suite
# e.g., run all, run tagged, run failed from previous
execution_strategy: Optional[str] = Field(default=None, description="Strategy for executing test cases within the suite.")