fix2:yapi

This commit is contained in:
gongwenxin 2025-05-26 16:38:38 +08:00
parent 6dde4d73e0
commit 01b044b35a
9 changed files with 111784 additions and 1840 deletions

View File

@ -1,247 +1,248 @@
import re
import json # 确保导入json
from typing import Dict, Any, Optional, List
from ddms_compliance_suite.test_framework_core import BaseAPITestCase, TestSeverity, ValidationResult, APIRequestContext
# LLMService的导入路径需要根据您的项目结构确认
# 假设 LLMService 在 ddms_compliance_suite.llm_utils.llm_service
try:
from ddms_compliance_suite.llm_utils.llm_service import LLMService
except ImportError:
LLMService = None
# print("LLMService not found, PathVerbNounCheckCase will be skipped or limited.")
# import re
# import json # 确保导入json
# from typing import Dict, Any, Optional, List
# from ddms_compliance_suite.test_framework_core import BaseAPITestCase, TestSeverity, ValidationResult, APIRequestContext
# # LLMService的导入路径需要根据您的项目结构确认
# # 假设 LLMService 在 ddms_compliance_suite.llm_utils.llm_service
# try:
# from ddms_compliance_suite.llm_utils.llm_service import LLMService
# except ImportError:
# LLMService = None
# # print("LLMService not found, PathVerbNounCheckCase will be skipped or limited.")
class ComprehensiveURLCheckLLMCase(BaseAPITestCase):
id = "TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001"
name = "综合URL规范与RESTful风格检查 (LLM)"
description = (
"使用LLM统一评估API路径是否符合以下规范\n"
"1. 路径参数命名 (例如,全小写蛇形命名法)。\n"
"2. URL路径结构 (例如,/{领域}/{版本号}/资源类型)。\n"
"3. URL版本号嵌入 (例如,包含 /v1/)。\n"
"4. RESTful风格与可读性 (名词表示资源HTTP方法表示动作易理解性)。"
)
severity = TestSeverity.MEDIUM # 综合性检查,可能包含不同严重级别的问题
tags = ["normative-spec", "url", "restful", "llm", "readability", "naming-convention", "structure", "versioning", "static-check"]
execution_order = 60 # 更新执行顺序
# class ComprehensiveURLCheckLLMCase(BaseAPITestCase):
# id = "TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001"
# name = "综合URL规范与RESTful风格检查 (LLM)"
# description = (
# "使用LLM统一评估API路径是否符合以下规范\n"
# "1. 路径参数命名 (例如,全小写蛇形命名法)。\n"
# "2. URL路径结构 (例如,/{领域}/{版本号}/资源类型)。\n"
# "3. URL版本号嵌入 (例如,包含 /v1/)。\n"
# "4. RESTful风格与可读性 (名词表示资源HTTP方法表示动作易理解性)。"
# )
# severity = TestSeverity.MEDIUM # 综合性检查,可能包含不同严重级别的问题
# tags = ["normative-spec", "url", "restful", "llm", "readability", "naming-convention", "structure", "versioning", "static-check"]
# execution_order = 60 # 更新执行顺序
# 此测试用例可以覆盖所有路径但其有效性依赖LLM
# applicable_methods = None
# applicable_paths_regex = None
# # 此测试用例可以覆盖所有路径但其有效性依赖LLM
# # applicable_methods = None
# # applicable_paths_regex = None
# 这个标志可以用来在测试用例级别控制是否实际调用LLM即使全局LLM服务可用
# 如果您希望总是尝试只要LLMService能初始化可以不设置这个或者在逻辑中检查 self.llm_service 是否存在
# use_llm_for_path_analysis: bool = True
# # 这个标志可以用来在测试用例级别控制是否实际调用LLM即使全局LLM服务可用
# # 如果您希望总是尝试只要LLMService能初始化可以不设置这个或者在逻辑中检查 self.llm_service 是否存在
# # use_llm_for_path_analysis: bool = True
def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[LLMService] = None):
super().__init__(endpoint_spec, global_api_spec, json_schema_validator)
self.llm_service = llm_service # 存储注入的 LLMService 实例
if not self.llm_service:
self.logger.warning(f"LLMService 未注入或初始化失败,测试用例 {self.id} 将无法执行LLM路径分析。")
# def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[LLMService] = None):
# super().__init__(endpoint_spec, global_api_spec, json_schema_validator)
# self.llm_service = llm_service # 存储注入的 LLMService 实例
# if not self.llm_service:
# self.logger.warning(f"LLMService 未注入或初始化失败,测试用例 {self.id} 将无法执行LLM路径分析。")
def _get_llm_service_from_orchestrator(self) -> Optional[Any]:
# 在实际框架中测试用例可能无法直接访问编排器来获取LLM服务。
# 这种依赖注入通常在测试用例实例化时或方法调用时处理。
# 此处为一个占位符理想情况下APITestOrchestrator会将llm_service实例传给需要它的测试用例
# 或测试用例通过某种服务定位器获取。
# 暂时我们假设如果全局配置了LLM它就能用。
# 真实的实现需要APITestOrchestrator在执行此测试用例前将llm_service实例注入。
# 为了能运行我们先返回None并在下面逻辑中处理。
# 或者,修改 Orchestrator 将其注入到 self.global_api_spec 或 self.endpoint_spec (不推荐)
# 最好的方式是在 __init__ 中接收一个 llm_service: Optional[LLMService] 参数。
# 但这需要修改 BaseAPITestCase 和 APITestOrchestrator 的 __init__ 和调用逻辑。
# def _get_llm_service_from_orchestrator(self) -> Optional[Any]:
# # 在实际框架中测试用例可能无法直接访问编排器来获取LLM服务。
# # 这种依赖注入通常在测试用例实例化时或方法调用时处理。
# # 此处为一个占位符理想情况下APITestOrchestrator会将llm_service实例传给需要它的测试用例
# # 或测试用例通过某种服务定位器获取。
# # 暂时我们假设如果全局配置了LLM它就能用。
# # 真实的实现需要APITestOrchestrator在执行此测试用例前将llm_service实例注入。
# # 为了能运行我们先返回None并在下面逻辑中处理。
# # 或者,修改 Orchestrator 将其注入到 self.global_api_spec 或 self.endpoint_spec (不推荐)
# # 最好的方式是在 __init__ 中接收一个 llm_service: Optional[LLMService] 参数。
# # 但这需要修改 BaseAPITestCase 和 APITestOrchestrator 的 __init__ 和调用逻辑。
# 临时的解决方法:依赖 APITestOrchestrator 初始化时是否成功创建了 LLMService。
# 这仍然是一个间接的检查。一个更直接的方式是在Orchestrator执行此测试用例时传入。
if hasattr(self, '_orchestrator_llm_service_instance') and self._orchestrator_llm_service_instance:
return self._orchestrator_llm_service_instance
# # 临时的解决方法:依赖 APITestOrchestrator 初始化时是否成功创建了 LLMService。
# # 这仍然是一个间接的检查。一个更直接的方式是在Orchestrator执行此测试用例时传入。
# if hasattr(self, '_orchestrator_llm_service_instance') and self._orchestrator_llm_service_instance:
# return self._orchestrator_llm_service_instance
# 如果没有明确注入我们只能依赖全局LLMService是否被加载
if LLMService is not None:
# 这里不能直接实例化一个新的LLMService因为它需要API Key等配置这些配置在Orchestrator那里。
# 这个测试用例需要依赖Orchestrator来提供一个已经配置好的LLMService实例。
# 此处返回一个指示如果LLM功能应该被使用则需要Orchestrator提供服务。
return "NEEDS_INJECTION"
return None
# # 如果没有明确注入我们只能依赖全局LLMService是否被加载
# if LLMService is not None:
# # 这里不能直接实例化一个新的LLMService因为它需要API Key等配置这些配置在Orchestrator那里。
# # 这个测试用例需要依赖Orchestrator来提供一个已经配置好的LLMService实例。
# # 此处返回一个指示如果LLM功能应该被使用则需要Orchestrator提供服务。
# return "NEEDS_INJECTION"
# return None
def _extract_path_param_names(self, path_template: str) -> List[str]:
"""从路径模板中提取路径参数名称。例如 /users/{user_id}/items/{item_id} -> ['user_id', 'item_id']"""
return re.findall(r'\{([^}]+)\}', path_template)
# def _extract_path_param_names(self, path_template: str) -> List[str]:
# """从路径模板中提取路径参数名称。例如 /users/{user_id}/items/{item_id} -> ['user_id', 'item_id']"""
# return re.findall(r'\{([^}]+)\}', path_template)
def validate_request_url(self, url: str, request_context: APIRequestContext) -> List[ValidationResult]:
results: List[ValidationResult] = []
path_template = self.endpoint_spec.get('path', '')
http_method = request_context.method.upper()
operation_id = self.endpoint_spec.get('operationId', self.endpoint_spec.get('title', '')) # 获取operationId或title
# def validate_request_url(self, url: str, request_context: APIRequestContext) -> List[ValidationResult]:
# results: List[ValidationResult] = []
# path_template = self.endpoint_spec.get('path', '')
# http_method = request_context.method.upper()
# operation_id = self.endpoint_spec.get('operationId', self.endpoint_spec.get('title', '')) # 获取operationId或title
if not self.llm_service:
results.append(ValidationResult(
passed=True, # 标记为通过以避免阻塞,但消息表明跳过
message=f"路径 '{path_template}' 的LLM综合URL检查已跳过LLM服务不可用。",
details={"path_template": path_template, "http_method": http_method, "reason": "LLM Service not available or not injected."}
))
self.logger.warning(f"LLM综合URL检查已跳过对路径 '{path_template}' 的检查LLM服务不可用。")
return results
# if not self.llm_service:
# results.append(ValidationResult(
# passed=True, # 标记为通过以避免阻塞,但消息表明跳过
# message=f"路径 '{path_template}' 的LLM综合URL检查已跳过LLM服务不可用。",
# details={"path_template": path_template, "http_method": http_method, "reason": "LLM Service not available or not injected."}
# ))
# self.logger.warning(f"LLM综合URL检查已跳过对路径 '{path_template}' 的检查LLM服务不可用。")
# return results
path_param_names = self._extract_path_param_names(path_template)
path_params_str = ", ".join(path_param_names) if path_param_names else ""
# path_param_names = self._extract_path_param_names(path_template)
# path_params_str = ", ".join(path_param_names) if path_param_names else "无"
# - 接口名称 (OperationId 或 Title): {operation_id if operation_id else '请你自己从路径模板中提取'}
# # - 接口名称 (OperationId 或 Title): {operation_id if operation_id else '请你自己从路径模板中提取'}
# 构建给LLM的Prompt要求JSON输出
prompt_instruction = f"""
请扮演一位资深的API设计评审员我将提供一个API端点的路径模板HTTP方法以及可能的接口名称
请根据以下石油行业API设计规范评估此API端点并以严格的JSON格式返回您的评估结果
JSON对象应包含一个名为 "assessments" 的键其值为一个对象列表每个对象代表对一个标准的评估包含 "standard_name" (字符串), "is_compliant" (布尔值), "reason" (字符串) 三个键
# # 构建给LLM的Prompt要求JSON输出
# prompt_instruction = f"""
# 请扮演一位资深的API设计评审员。我将提供一个API端点的路径模板、HTTP方法以及可能的接口名称
# 请根据以下石油行业API设计规范评估此API端点并以严格的JSON格式返回您的评估结果。
# JSON对象应包含一个名为 "assessments" 的键,其值为一个对象列表,每个对象代表对一个标准的评估,包含 "standard_name" (字符串), "is_compliant" (布尔值), 和 "reason" (字符串) 三个键
API端点信息:
- HTTP方法: {http_method}
- 路径模板: {path_template}
- 路径中提取的参数名: [{path_params_str}]
# API端点信息:
# - HTTP方法: {http_method}
# - 路径模板: {path_template}
# - 路径中提取的参数名: [{path_params_str}]
评估标准:
# 评估标准:
1. **接口名称规范 (接口名称需要你从路径模板中提取一般是路径中除了参数名以外的最后的一个单词)**:
- 规则: 采用'动词+名词'结构明确业务语义 (例如: GetWellLog, SubmitSeismicJob)
- standard_name: "interface_naming_convention"
# 1. **接口名称规范 (接口名称需要你从路径模板中提取,一般是路径中除了参数名以外的最后的一个单词)**:
# - 规则: 采用'动词+名词'结构,明确业务语义 (例如: GetWellLog, SubmitSeismicJob)。
# - standard_name: "interface_naming_convention"
2. **HTTP方法使用规范**:
- 规则: 遵循RESTful规范GET用于数据检索, POST用于创建资源, PUT用于更新资源, DELETE用于删除资源
- standard_name: "http_method_usage"
# 2. **HTTP方法使用规范**:
# - 规则: 遵循RESTful规范GET用于数据检索, POST用于创建资源, PUT用于更新资源, DELETE用于删除资源。
# - standard_name: "http_method_usage"
3. **URL路径结构规范**:
- 规则: 格式为 `<前缀>/<专业领域>/v<版本号>/<资源类型>` (例如: /logging/v1.2/wells, /seismicprospecting/v1.0/datasets)
- 前缀: 示例: /api/dms
- 专业领域: 专业领域示例: seismicprospecting, welllogging, reservoirevaluation
- 版本号: 语义化版本例如 v1, v1.0, v2.1.3
- 资源类型: 通常为名词复数
- standard_name: "url_path_structure"
# 3. **URL路径结构规范**:
# - 规则: 格式为 `<前缀>/<专业领域>/v<版本号>/<资源类型>` (例如: /logging/v1.2/wells, /seismicprospecting/v1.0/datasets)。
# - 前缀: 示例: /api/dms
# - 专业领域: 专业领域示例: seismicprospecting, welllogging, reservoirevaluation
# - 版本号: 语义化版本,例如 v1, v1.0, v2.1.3。
# - 资源类型: 通常为名词复数。
# - standard_name: "url_path_structure"
# - standard_name: "resource"
# - standard_name: "schema"
# - standard_name: "version"
4. **URL路径参数命名规范**:
- 规则: 路径参数如果存在必须使用全小写字母(可以是一个单词或小写字母加下划线命名这是多个单词的情况并能反映资源的唯一标识 (例如: {{well_id}},{{version}},{{schema}})
- standard_name: "url_path_parameter_naming"
# 4. **URL路径参数命名规范**:
# - 规则: 路径参数(如果存在)必须使用全小写字母(可以是一个单词)或小写字母加下划线命名(这是多个单词的情况),并能反映资源的唯一标识 (例如: {{well_id}},{{version}},{{schema}})。
# - standard_name: "url_path_parameter_naming"
5. **资源命名规范 (在路径中)**:
- 规则: 资源集合应使用名词的复数形式表示 (例如 `/wells`, `/logs`)应优先使用石油行业的标准术语 (例如用 `trajectory` 而非 `path` 来表示井轨迹)
- standard_name: "resource_naming_in_path"
- standard_name: "resource"
- standard_name: "schema"
- standard_name: "version"
# 5. **资源命名规范 (在路径中)**:
# - 规则: 资源集合应使用名词的复数形式表示 (例如 `/wells`, `/logs`);应优先使用石油行业的标准术语 (例如用 `trajectory` 而非 `path` 来表示井轨迹)。
# - standard_name: "resource_naming_in_path"
请确保您的输出是一个可以被 `json.loads()` 直接解析的JSON对象
例如:
{{
"assessments": [
{{
"standard_name": "interface_naming_convention",
"is_compliant": true,
"reason": "接口名称 'GetWellboreTrajectory' 符合动词+名词结构。"
}},
{{
"standard_name": "http_method_usage",
"is_compliant": true,
"reason": "GET方法用于检索资源符合规范。"
}}
// ... 其他标准的评估 ...
]
}}
"""
# 6. **路径可读性与整体RESTful风格**:
# - 规则: 路径整体是否具有良好的可读性、易于理解其功能并且符合RESTful设计原则综合评估可参考前面几点
# - standard_name: "general_readability_and_restfulness"
# 请确保您的输出是一个可以被 `json.loads()` 直接解析的JSON对象。
# 例如:
# {{
# "assessments": [
# {{
# "standard_name": "interface_naming_convention",
# "is_compliant": true,
# "reason": "接口名称 'GetWellboreTrajectory' 符合动词+名词结构。"
# }},
# {{
# "standard_name": "http_method_usage",
# "is_compliant": true,
# "reason": "GET方法用于检索资源符合规范。"
# }}
# // ... 其他标准的评估 ...
# ]
# }}
# """
messages = [
{"role": "system", "content": "你是一位API设计评审专家专注于评估API的URL规范性和RESTful风格。你的输出必须是严格的JSON格式。"},
{"role": "user", "content": prompt_instruction}
]
# # 6. **路径可读性与整体RESTful风格**:
# # - 规则: 路径整体是否具有良好的可读性、易于理解其功能并且符合RESTful设计原则综合评估可参考前面几点
# # - standard_name: "general_readability_and_restfulness"
self.logger.info(f"向LLM发送请求评估路径: {path_template} ({http_method})")
# 假设 _execute_chat_completion_request 支持 response_format={"type": "json_object"} (如果LLM API支持)
# 否则我们需要解析文本输出。为简化这里假设LLM会遵循JSON格式指令。
llm_response_str = self.llm_service._execute_chat_completion_request(
messages=messages,
max_tokens=1024, # 根据评估结果的复杂度调整
temperature=0.2 # 低温以获得更确定的、结构化的输出
)
# messages = [
# {"role": "system", "content": "你是一位API设计评审专家专注于评估API的URL规范性和RESTful风格。你的输出必须是严格的JSON格式。"},
# {"role": "user", "content": prompt_instruction}
# ]
if not llm_response_str:
results.append(ValidationResult(
passed=False, # 执行失败
message=f"未能从LLM获取对路径 '{path_template}' 的评估。",
details={"path_template": path_template, "http_method": http_method, "reason": "LLM did not return a response."}
))
self.logger.error(f"LLM对路径 '{path_template}' 的评估请求未返回任何内容。")
return results
# self.logger.info(f"向LLM发送请求评估路径: {path_template} ({http_method})")
# # 假设 _execute_chat_completion_request 支持 response_format={"type": "json_object"} (如果LLM API支持)
# # 否则我们需要解析文本输出。为简化这里假设LLM会遵循JSON格式指令。
# llm_response_str = self.llm_service._execute_chat_completion_request(
# messages=messages,
# max_tokens=1024, # 根据评估结果的复杂度调整
# temperature=0.2 # 低温以获得更确定的、结构化的输出
# )
self.logger.debug(f"LLM对路径 '{path_template}' 的原始响应: {llm_response_str}")
# if not llm_response_str:
# results.append(ValidationResult(
# passed=False, # 执行失败
# message=f"未能从LLM获取对路径 '{path_template}' 的评估。",
# details={"path_template": path_template, "http_method": http_method, "reason": "LLM did not return a response."}
# ))
# self.logger.error(f"LLM对路径 '{path_template}' 的评估请求未返回任何内容。")
# return results
try:
# 尝试清理并解析LLM响应
# 有时LLM可能在JSON前后添加 "```json" 和 "```"
cleaned_response_str = llm_response_str.strip()
if cleaned_response_str.startswith("```json"):
cleaned_response_str = cleaned_response_str[7:]
if cleaned_response_str.endswith("```"):
cleaned_response_str = cleaned_response_str[:-3]
# self.logger.debug(f"LLM对路径 '{path_template}' 的原始响应: {llm_response_str}")
# try:
# # 尝试清理并解析LLM响应
# # 有时LLM可能在JSON前后添加 "```json" 和 "```"
# cleaned_response_str = llm_response_str.strip()
# if cleaned_response_str.startswith("```json"):
# cleaned_response_str = cleaned_response_str[7:]
# if cleaned_response_str.endswith("```"):
# cleaned_response_str = cleaned_response_str[:-3]
llm_assessment_data = json.loads(cleaned_response_str)
# llm_assessment_data = json.loads(cleaned_response_str)
if "assessments" not in llm_assessment_data or not isinstance(llm_assessment_data["assessments"], list):
raise ValueError("LLM响应JSON中缺少 'assessments' 列表或格式不正确。")
# if "assessments" not in llm_assessment_data or not isinstance(llm_assessment_data["assessments"], list):
# raise ValueError("LLM响应JSON中缺少 'assessments' 列表或格式不正确。")
found_assessments = False
for assessment in llm_assessment_data["assessments"]:
standard_name = assessment.get("standard_name", "未知标准")
is_compliant = assessment.get("is_compliant", False)
reason = assessment.get("reason", "LLM未提供原因。")
found_assessments = True
# found_assessments = False
# for assessment in llm_assessment_data["assessments"]:
# standard_name = assessment.get("standard_name", "未知标准")
# is_compliant = assessment.get("is_compliant", False)
# reason = assessment.get("reason", "LLM未提供原因。")
# found_assessments = True
results.append(ValidationResult(
passed=is_compliant,
message=f"LLM评估 - {standard_name}: {reason}",
details={
"standard_name": standard_name,
"is_compliant_by_llm": is_compliant,
"llm_reason": reason,
"path_template": path_template,
"http_method": http_method
}
))
log_level = self.logger.info if is_compliant else self.logger.warning
log_level(f"LLM评估 - 标准 '{standard_name}' for '{path_template}': {'符合' if is_compliant else '不符合'}。原因: {reason}")
# results.append(ValidationResult(
# passed=is_compliant,
# message=f"LLM评估 - {standard_name}: {reason}",
# details={
# "standard_name": standard_name,
# "is_compliant_by_llm": is_compliant,
# "llm_reason": reason,
# "path_template": path_template,
# "http_method": http_method
# }
# ))
# log_level = self.logger.info if is_compliant else self.logger.warning
# log_level(f"LLM评估 - 标准 '{standard_name}' for '{path_template}': {'符合' if is_compliant else '不符合'}。原因: {reason}")
if not found_assessments:
results.append(ValidationResult(
passed=False,
message=f"LLM返回的评估结果中不包含任何有效的评估项。",
details={"path_template": path_template, "http_method": http_method, "raw_llm_response": llm_response_str}
))
# if not found_assessments:
# results.append(ValidationResult(
# passed=False,
# message=f"LLM返回的评估结果中不包含任何有效的评估项。",
# details={"path_template": path_template, "http_method": http_method, "raw_llm_response": llm_response_str}
# ))
except json.JSONDecodeError as e_json:
results.append(ValidationResult(
passed=False, # 执行失败
message=f"无法将LLM对路径 '{path_template}' 的评估响应解析为JSON: {e_json}",
details={"path_template": path_template, "http_method": http_method, "raw_llm_response": llm_response_str, "error": str(e_json)}
))
self.logger.error(f"LLM对路径 '{path_template}' 的响应JSON解析失败: {e_json}. Raw response: {llm_response_str}")
except ValueError as e_val: # 自定义错误,如缺少 'assessments'
results.append(ValidationResult(
passed=False, # 执行失败
message=f"LLM对路径 '{path_template}' 的评估响应JSON结构不符合预期: {e_val}",
details={"path_template": path_template, "http_method": http_method, "raw_llm_response": llm_response_str, "error": str(e_val)}
))
self.logger.error(f"LLM对路径 '{path_template}' 的响应JSON结构错误: {e_val}. Raw response: {llm_response_str}")
except Exception as e_generic:
results.append(ValidationResult(
passed=False, # 执行失败
message=f"处理LLM对路径 '{path_template}' 的评估响应时发生未知错误: {e_generic}",
details={"path_template": path_template, "http_method": http_method, "raw_llm_response": llm_response_str, "error": str(e_generic)}
))
self.logger.error(f"处理LLM对路径 '{path_template}' 的响应时发生未知错误: {e_generic}", exc_info=True)
# except json.JSONDecodeError as e_json:
# results.append(ValidationResult(
# passed=False, # 执行失败
# message=f"无法将LLM对路径 '{path_template}' 的评估响应解析为JSON: {e_json}",
# details={"path_template": path_template, "http_method": http_method, "raw_llm_response": llm_response_str, "error": str(e_json)}
# ))
# self.logger.error(f"LLM对路径 '{path_template}' 的响应JSON解析失败: {e_json}. Raw response: {llm_response_str}")
# except ValueError as e_val: # 自定义错误,如缺少 'assessments'
# results.append(ValidationResult(
# passed=False, # 执行失败
# message=f"LLM对路径 '{path_template}' 的评估响应JSON结构不符合预期: {e_val}",
# details={"path_template": path_template, "http_method": http_method, "raw_llm_response": llm_response_str, "error": str(e_val)}
# ))
# self.logger.error(f"LLM对路径 '{path_template}' 的响应JSON结构错误: {e_val}. Raw response: {llm_response_str}")
# except Exception as e_generic:
# results.append(ValidationResult(
# passed=False, # 执行失败
# message=f"处理LLM对路径 '{path_template}' 的评估响应时发生未知错误: {e_generic}",
# details={"path_template": path_template, "http_method": http_method, "raw_llm_response": llm_response_str, "error": str(e_generic)}
# ))
# self.logger.error(f"处理LLM对路径 '{path_template}' 的响应时发生未知错误: {e_generic}", exc_info=True)
return results
# return results

View File

@ -803,8 +803,14 @@ class APITestOrchestrator:
# 调用 _prepare_initial_request_data 时传递 test_case_instance
# 并直接解包返回的元组
method, path_params_data, query_params_data, headers_data, body_data = \
self._prepare_initial_request_data(endpoint_spec_dict, test_case_instance=test_case_instance)
request_context_data = self._prepare_initial_request_data(endpoint_spec_dict, test_case_instance=test_case_instance)
# 从 request_context_data 对象中获取各个部分
method = request_context_data.method
path_params_data = request_context_data.path_params
query_params_data = request_context_data.query_params
headers_data = request_context_data.headers
body_data = request_context_data.body
# 让测试用例有机会修改这些生成的数据
# 注意: BaseAPITestCase 中的 generate_* 方法现在需要传入 endpoint_spec_dict
@ -1053,7 +1059,9 @@ class APITestOrchestrator:
# 3.1 设置 Content-Type
# 优先从 requestBody.content 获取 (OpenAPI 3.x)
request_body_spec = endpoint_spec.get('requestBody', {})
request_body_spec_candidate = endpoint_spec.get('requestBody')
request_body_spec = request_body_spec_candidate if isinstance(request_body_spec_candidate, dict) else {}
if 'content' in request_body_spec:
content_types = list(request_body_spec['content'].keys())
if content_types:

80413
log.txt

File diff suppressed because it is too large Load Diff

View File

@ -284,4 +284,8 @@ if __name__ == "__main__":
# python run_api_tests.py --base-url http://127.0.0.1:4523/m1/6389742-6086420-default --swagger assets/doc/井筒API示例swagger.json --custom-test-cases-dir ./custom_testcases \
# --verbose \
# --output test_report.json
# python run_api_tests.py --base-url https://127.0.0.1:4523/m1/6389742-6086420-default --yapi assets/doc/井筒API示例_simple.json --custom-test-cases-dir ./custom_testcases \
# --verbose \
# --output test_report.json

File diff suppressed because it is too large Load Diff