"""规则执行引擎 该模块负责执行不同类型的规则,包括Python代码规则、断言规则等, 支持在API测试的不同生命周期阶段(请求准备、执行、响应验证等)执行规则。 """ import logging import importlib import inspect import time import threading from typing import Dict, List, Any, Optional, Union, Callable from ..models.rule_models import ( AnyRule, BaseRule, RuleCategory, TargetType, RuleLifecycle, RuleScope, PythonCodeRule, BusinessAssertionTemplate, PerformanceRule, SecurityRule, RESTfulDesignRule, ErrorHandlingRule ) from ..api_caller.caller import APIRequest, APIResponse from ..rule_repository.repository import RuleRepository class RuleExecutionError(Exception): """规则执行过程中发生的错误""" pass class RuleExecutionResult: """规则执行结果""" def __init__(self, rule: BaseRule, is_valid: bool, message: str = "", details: Optional[Dict[str, Any]] = None, error: Optional[Exception] = None): """ 初始化规则执行结果 Args: rule: 执行的规则 is_valid: 验证是否通过 message: 执行结果消息 details: 详细信息 error: 执行过程中发生的异常(如果有) """ self.rule = rule self.rule_id = rule.id self.rule_name = rule.name self.rule_category = rule.category self.is_valid = is_valid self.message = message self.details = details or {} self.error = error def __bool__(self): """允许直接使用结果对象作为布尔值,表示验证是否通过""" return self.is_valid def to_dict(self) -> Dict[str, Any]: """将结果转换为字典""" return { 'rule_id': self.rule_id, 'rule_name': self.rule_name, 'rule_category': self.rule_category.value, 'is_valid': self.is_valid, 'message': self.message, 'details': self.details, 'error': str(self.error) if self.error else None } class RuleExecutor: """规则执行引擎""" def __init__(self, rule_repository: RuleRepository): """ 初始化规则执行引擎 Args: rule_repository: 规则库实例 """ self.rule_repository = rule_repository self.logger = logging.getLogger(__name__) def execute_rule(self, rule: BaseRule, context: Dict[str, Any]) -> RuleExecutionResult: """ 执行单个规则 Args: rule: 要执行的规则 context: 执行上下文,包含API请求、响应等信息 Returns: 执行结果 """ if not rule.is_enabled: return RuleExecutionResult( rule=rule, is_valid=True, message=f"规则 {rule.id} 已禁用,跳过执行" ) try: # 根据规则类型选择适当的执行方法 if rule.category == RuleCategory.PYTHON_CODE or hasattr(rule, 'code') and rule.code: return self._execute_python_code_rule(rule, context) elif rule.category == RuleCategory.BUSINESS_LOGIC: return self._execute_business_assertion_rule(rule, context) elif rule.category == RuleCategory.PERFORMANCE: return self._execute_performance_rule(rule, context) elif rule.category == RuleCategory.SECURITY: return self._execute_security_rule(rule, context) elif rule.category == RuleCategory.API_DESIGN: return self._execute_api_design_rule(rule, context) elif rule.category == RuleCategory.ERROR_HANDLING: return self._execute_error_handling_rule(rule, context) else: return RuleExecutionResult( rule=rule, is_valid=False, message=f"不支持的规则类型: {rule.category}" ) except Exception as e: self.logger.error(f"执行规则 {rule.id} 失败: {e}", exc_info=True) return RuleExecutionResult( rule=rule, is_valid=False, message=f"规则执行失败: {e}", error=e ) def _execute_python_code_rule(self, rule: BaseRule, context: Dict[str, Any]) -> RuleExecutionResult: """执行Python代码规则""" # 获取规则中的Python代码 code = getattr(rule, 'code', None) if not code: return RuleExecutionResult( rule=rule, is_valid=False, message="规则未提供Python代码" ) # 准备执行环境 namespace = {'__builtins__': __builtins__} namespace.update(context) try: # 编译并执行代码 compiled_code = compile(code, f"", 'exec') exec(compiled_code, namespace) # 查找并执行验证函数 entry_function = 'validate' if hasattr(rule, 'entry_function') and rule.entry_function: entry_function = rule.entry_function if entry_function not in namespace: return RuleExecutionResult( rule=rule, is_valid=False, message=f"找不到入口函数 '{entry_function}'" ) validate_func = namespace[entry_function] if not callable(validate_func): return RuleExecutionResult( rule=rule, is_valid=False, message=f"'{entry_function}' 不是可调用的函数" ) # 调用验证函数 timeout = getattr(rule, 'timeout', 5) # 默认5秒超时 result = self._execute_with_timeout(validate_func, (context,), {}, timeout) # 处理执行结果 if isinstance(result, dict): return RuleExecutionResult( rule=rule, is_valid=bool(result.get('is_valid', False)), message=result.get('message', ''), details=result.get('details', {}) ) else: return RuleExecutionResult( rule=rule, is_valid=bool(result), message=str(result) if result is not True else "验证通过" ) except Exception as e: self.logger.error(f"执行Python代码规则 {rule.id} 失败: {e}", exc_info=True) return RuleExecutionResult( rule=rule, is_valid=False, message=f"执行代码失败: {e}", error=e ) def _execute_with_timeout(self, func: Callable, args: tuple, kwargs: Dict[str, Any], timeout: int) -> Any: """使用超时执行函数""" result = [None] exception = [None] def target(): try: result[0] = func(*args, **kwargs) except Exception as e: exception[0] = e thread = threading.Thread(target=target) thread.daemon = True thread.start() thread.join(timeout) if thread.is_alive(): raise RuleExecutionError(f"规则执行超时(超过{timeout}秒)") if exception[0]: raise exception[0] return result[0] def _execute_business_assertion_rule(self, rule: BusinessAssertionTemplate, context: Dict[str, Any]) -> RuleExecutionResult: """执行业务断言规则""" # 验证是否提供了所有必需的参数 if rule.expected_parameters: missing_params = [p for p in rule.expected_parameters if p not in context] if missing_params: return RuleExecutionResult( rule=rule, is_valid=False, message=f"缺少必需的参数: {', '.join(missing_params)}" ) if rule.template_language == "python_expression": try: # 使用eval执行Python表达式 result = eval(rule.template_expression, {'__builtins__': __builtins__}, context) return RuleExecutionResult( rule=rule, is_valid=bool(result), message="断言通过" if result else "断言失败" ) except Exception as e: self.logger.error(f"执行Python表达式断言失败: {e}", exc_info=True) return RuleExecutionResult( rule=rule, is_valid=False, message=f"表达式执行失败: {e}", error=e ) else: return RuleExecutionResult( rule=rule, is_valid=False, message=f"不支持的模板语言: {rule.template_language}" ) def _execute_performance_rule(self, rule: PerformanceRule, context: Dict[str, Any]) -> RuleExecutionResult: """执行性能规则""" response = context.get('api_response') if not response or not isinstance(response, APIResponse): return RuleExecutionResult( rule=rule, is_valid=False, message="缺少有效的API响应对象" ) # 获取响应时间(毫秒) elapsed_time = response.elapsed_time * 1000 # 转换为毫秒 # 检查是否超过阈值 if elapsed_time > rule.threshold: return RuleExecutionResult( rule=rule, is_valid=False, message=f"响应时间({elapsed_time:.2f}ms)超过阈值({rule.threshold}{rule.unit})", details={ 'actual_time': elapsed_time, 'threshold': rule.threshold, 'unit': rule.unit } ) return RuleExecutionResult( rule=rule, is_valid=True, message=f"响应时间({elapsed_time:.2f}ms)在阈值范围内", details={ 'actual_time': elapsed_time, 'threshold': rule.threshold, 'unit': rule.unit } ) def _execute_security_rule(self, rule: SecurityRule, context: Dict[str, Any]) -> RuleExecutionResult: """执行安全规则""" if rule.check_type == "transport_security": request = context.get('api_request') if not request or not isinstance(request, APIRequest): return RuleExecutionResult( rule=rule, is_valid=False, message="缺少有效的API请求对象" ) url = str(request.url) # 检查URL是否使用HTTPS if not url.startswith('https://'): return RuleExecutionResult( rule=rule, is_valid=False, message="API请求必须使用HTTPS协议", details={ 'current_url': url, 'expected_protocol': 'https' } ) return RuleExecutionResult( rule=rule, is_valid=True, message="API请求使用了HTTPS协议", details={ 'url': url } ) else: return RuleExecutionResult( rule=rule, is_valid=False, message=f"不支持的安全检查类型: {rule.check_type}" ) def _execute_api_design_rule(self, rule: RESTfulDesignRule, context: Dict[str, Any]) -> RuleExecutionResult: """执行API设计规则""" import re request = context.get('api_request') if not request or not isinstance(request, APIRequest): return RuleExecutionResult( rule=rule, is_valid=False, message="缺少有效的API请求对象" ) url = str(request.url) # 解析URL,获取路径部分 from urllib.parse import urlparse parsed_url = urlparse(url) path = parsed_url.path # 使用正则表达式验证路径 if rule.pattern and not re.match(rule.pattern, path): return RuleExecutionResult( rule=rule, is_valid=False, message=f"API路径不符合{rule.design_aspect}规范", details={ 'current_path': path, 'expected_pattern': rule.pattern } ) return RuleExecutionResult( rule=rule, is_valid=True, message=f"API路径符合{rule.design_aspect}规范", details={ 'path': path } ) def _execute_error_handling_rule(self, rule: ErrorHandlingRule, context: Dict[str, Any]) -> RuleExecutionResult: """执行错误处理规则""" response = context.get('api_response') if not response or not isinstance(response, APIResponse): return RuleExecutionResult( rule=rule, is_valid=False, message="缺少有效的API响应对象" ) # 只验证4xx和5xx状态码 if response.status_code < 400: return RuleExecutionResult( rule=rule, is_valid=True, message="非错误响应,跳过验证", details={ 'status_code': response.status_code } ) # 验证状态码是否匹配 if rule.expected_status != -1 and response.status_code != rule.expected_status: return RuleExecutionResult( rule=rule, is_valid=False, message=f"响应状态码({response.status_code})与预期({rule.expected_status})不符", details={ 'actual_status': response.status_code, 'expected_status': rule.expected_status } ) # 验证JSON响应 if not response.json_content: return RuleExecutionResult( rule=rule, is_valid=False, message="错误响应不是有效的JSON格式", details={ 'status_code': response.status_code, 'content_type': response.headers.get('Content-Type', '未知') } ) # 检查错误码 if rule.error_code != "*" and str(response.json_content.get('code', '')) != rule.error_code: return RuleExecutionResult( rule=rule, is_valid=False, message=f"错误码({response.json_content.get('code')})与预期({rule.error_code})不符", details={ 'actual_code': response.json_content.get('code'), 'expected_code': rule.error_code } ) # 验证错误消息 if rule.expected_message and rule.expected_message not in str(response.json_content.get('message', '')): return RuleExecutionResult( rule=rule, is_valid=False, message="错误消息与预期不符", details={ 'actual_message': response.json_content.get('message'), 'expected_message': rule.expected_message } ) return RuleExecutionResult( rule=rule, is_valid=True, message="错误响应符合预期", details={ 'status_code': response.status_code, 'error_code': response.json_content.get('code'), 'error_message': response.json_content.get('message') } ) def execute_rules_for_lifecycle(self, lifecycle: RuleLifecycle, context: Dict[str, Any]) -> List[RuleExecutionResult]: """ 执行特定生命周期阶段的所有规则 Args: lifecycle: 生命周期阶段 context: 执行上下文 Returns: 执行结果列表 """ # 获取适用于该生命周期阶段的所有规则 rules = self.rule_repository.get_rules_by_lifecycle(lifecycle) # 执行规则 results = [] for rule in rules: result = self.execute_rule(rule, context) results.append(result) return results def execute_rules_for_target(self, target_type: TargetType, target_id: str, context: Dict[str, Any]) -> List[RuleExecutionResult]: """ 执行特定目标的所有规则 Args: target_type: 目标类型 target_id: 目标ID context: 执行上下文 Returns: 执行结果列表 """ # 获取适用于该目标的所有规则 rules = self.rule_repository.get_rules_for_target(target_type, target_id) # 执行规则 results = [] for rule in rules: result = self.execute_rule(rule, context) results.append(result) return results def execute_specific_rules(self, rules: List[AnyRule], context: Dict[str, Any], lifecycle_phase: Optional[RuleLifecycle] = None) -> List[RuleExecutionResult]: """ 执行一个明确指定的规则列表。 Args: rules: 要执行的规则对象的列表。 context: 执行上下文,包含API请求、响应等信息。 lifecycle_phase: 可选的,名义上的生命周期阶段,可能用于上下文或某些规则的内部逻辑。 注意:此参数目前主要用于信息传递,核心执行逻辑在 execute_rule 中 并不直接依赖它来选择执行路径。 Returns: 一个包含每个规则执行结果的列表。 """ results = [] if not rules: self.logger.info("execute_specific_rules_called_with_no_rules") return results # 如果需要,可以将 lifecycle_phase 添加到 context 中传递给每个规则 # updated_context = context.copy() # if lifecycle_phase: # updated_context['current_lifecycle_phase'] = lifecycle_phase for rule in rules: # 使用现有的 execute_rule 方法执行单个规则 # result = self.execute_rule(rule, updated_context if lifecycle_phase else context) result = self.execute_rule(rule, context) # 简化:暂时不修改context传递 results.append(result) return results