From 6dde4d73e00094e0bdc34e6e2bfc949d3ab710ab Mon Sep 17 00:00:00 2001 From: gongwenxin Date: Mon, 26 May 2025 15:38:37 +0800 Subject: [PATCH] fix:yapi --- Framework_And_TestCase_Guide.md | 189 +-- assets/doc/井筒API示例_simple.json | 430 +++++ assets/images/dms1/.DS_Store | Bin 6148 -> 8196 bytes .../__pycache__/basic_checks.cpython-312.pyc | Bin 5951 -> 3341 bytes custom_testcases/basic_checks.py | 51 +- .../schema_validation_case.cpython-312.pyc | Bin 6155 -> 6229 bytes .../schema_validation_case.py | 4 +- ...g_required_field_body_case.cpython-312.pyc | Bin 0 -> 18237 bytes ..._required_field_query_case.cpython-312.pyc | Bin 0 -> 8522 bytes .../type_mismatch_body_case.cpython-312.pyc | Bin 0 -> 25287 bytes ..._mismatch_query_param_case.cpython-312.pyc | Bin 0 -> 16561 bytes .../missing_required_field_body_case.py | 65 +- .../missing_required_field_query_case.py | 29 +- .../error_handling/type_mismatch_body_case.py | 63 +- .../type_mismatch_query_param_case.py | 117 +- .../url_llm_checks.cpython-312.pyc | Bin 0 -> 11836 bytes .../normative_spec/url_llm_checks.py | 247 +++ .../https_mandatory_case.cpython-312.pyc | Bin 6676 -> 6750 bytes .../security/https_mandatory_case.py | 4 +- .../test_framework_core.cpython-312.pyc | Bin 13271 -> 13574 bytes .../test_orchestrator.cpython-312.pyc | Bin 89058 -> 90031 bytes .../__pycache__/parser.cpython-312.pyc | Bin 14772 -> 26570 bytes ddms_compliance_suite/input_parser/parser.py | 776 +++++---- .../__pycache__/validator.cpython-312.pyc | Bin 6717 -> 6712 bytes .../json_schema_validator/validator.py | 8 +- ddms_compliance_suite/test_framework_core.py | 54 +- ddms_compliance_suite/test_orchestrator.py | 423 ++--- log.txt | 1404 +++++++++++++---- test_report.json | 953 ++++++++++- 29 files changed, 3552 insertions(+), 1265 deletions(-) create mode 100644 assets/doc/井筒API示例_simple.json create mode 100644 custom_testcases/compliance_catalog/error_handling/__pycache__/missing_required_field_body_case.cpython-312.pyc create mode 100644 custom_testcases/compliance_catalog/error_handling/__pycache__/missing_required_field_query_case.cpython-312.pyc create mode 100644 custom_testcases/compliance_catalog/error_handling/__pycache__/type_mismatch_body_case.cpython-312.pyc create mode 100644 custom_testcases/compliance_catalog/error_handling/__pycache__/type_mismatch_query_param_case.cpython-312.pyc create mode 100644 custom_testcases/compliance_catalog/normative_spec/__pycache__/url_llm_checks.cpython-312.pyc create mode 100644 custom_testcases/compliance_catalog/normative_spec/url_llm_checks.py diff --git a/Framework_And_TestCase_Guide.md b/Framework_And_TestCase_Guide.md index 973e1ef..77ae754 100644 --- a/Framework_And_TestCase_Guide.md +++ b/Framework_And_TestCase_Guide.md @@ -2,50 +2,51 @@ 本 API 合规性测试框架主要由以下几个核心组件构成,它们协同工作以完成测试的定义、发现、执行和报告: -1. **命令行接口 (`run_api_tests.py`)**: - * 作为测试执行的入口。 - * 负责解析用户通过命令行传入的参数,例如 API 服务的基础 URL、API 规范文件路径(YAPI 或 Swagger)、测试用例目录、输出报告配置以及 LLM 相关配置。 - * 初始化并驱动 `APITestOrchestrator`。 +1. **命令行接口 (`run_api_tests.py`)**: -2. **测试编排器 (`APITestOrchestrator` 在 `ddms_compliance_suite/test_orchestrator.py`)**: - * **核心控制器**:是整个测试流程的指挥中心。 - * **组件初始化**:负责初始化和管理其他关键组件,如 `InputParser`(API 规范解析器)、`APICaller`(API 请求调用器)、`TestCaseRegistry`(测试用例注册表)以及可选的 `LLMService`(大模型服务)。 - * **测试流程管理**: - * 调用 `InputParser` 解析指定的 API 规范文件,获取所有端点的定义。 - * 根据用户指定的过滤器(如 YAPI 分类或 Swagger 标签)筛选需要测试的 API 端点。 - * 对每一个选定的 API 端点: - * 通过 `TestCaseRegistry` 获取所有适用于该端点的自定义测试用例类。 - * 实例化每个测试用例类。 - * 调用 `_prepare_initial_request_data` 方法准备初始请求数据(路径参数、查询参数、请求头、请求体)。此方法会根据全局配置和测试用例自身的配置决定是否使用 LLM 进行数据生成,并利用 `LLMService` 和动态 Pydantic 模型创建(`_create_pydantic_model_from_schema`)来实现。如果LLM未启用或不适用,则使用传统的基于 Schema 的数据生成逻辑(`_generate_params_from_list`, `_generate_data_from_schema`)。此阶段还实现了端点级别的LLM参数缓存。 - * 依次调用测试用例实例中定义的 `generate_*` 方法,允许测试用例修改生成的请求数据。 - * 调用测试用例实例中定义的 `validate_request_*` 方法,对即将发送的请求进行预校验。 - * 使用 `APICaller` 发送最终构建的 API 请求。 - * 接收到 API 响应后,调用测试用例实例中定义的 `validate_response` 和 `check_performance` 方法,对响应进行详细验证。 - * **结果汇总**:收集每个测试用例的执行结果 (`ExecutedTestCaseResult`),汇总成每个端点的测试结果 (`TestResult`),并最终生成整个测试运行的摘要 (`TestSummary`)。 + * 作为测试执行的入口。 + * 负责解析用户通过命令行传入的参数,例如 API 服务的基础 URL、API 规范文件路径(YAPI 或 Swagger)、测试用例目录、输出报告配置以及 LLM 相关配置。 + * 初始化并驱动 `APITestOrchestrator`。 +2. **测试编排器 (`APITestOrchestrator` 在 `ddms_compliance_suite/test_orchestrator.py`)**: -3. **测试用例注册表 (`TestCaseRegistry` 在 `ddms_compliance_suite/test_case_registry.py`)**: - * **动态发现**:负责在用户指定的目录 (`custom_test_cases_dir`) 下扫描并动态加载所有以 `.py` 结尾的测试用例文件。 - * **类识别与注册**:从加载的模块中,识别出所有继承自 `BaseAPITestCase` 的类,并根据其 `id` 属性进行注册。 - * **执行顺序排序**:在发现所有测试用例类后,会根据每个类的 `execution_order` 属性(主排序键,升序)和类名 `__name__`(次排序键,字母升序)对它们进行排序。 - * **适用性筛选**:提供 `get_applicable_test_cases` 方法,根据 API 端点的 HTTP 方法和路径(通过正则表达式匹配)筛选出适用的、已排序的测试用例类列表给编排器。 + * **核心控制器**:是整个测试流程的指挥中心。 + * **组件初始化**:负责初始化和管理其他关键组件,如 `InputParser`(API 规范解析器)、`APICaller`(API 请求调用器)、`TestCaseRegistry`(测试用例注册表)以及可选的 `LLMService`(大模型服务)。 + * **测试流程管理**: + * 调用 `InputParser` 解析指定的 API 规范文件,获取所有端点的定义。 + * 根据用户指定的过滤器(如 YAPI 分类或 Swagger 标签)筛选需要测试的 API 端点。 + * 对每一个选定的 API 端点: + * 通过 `TestCaseRegistry` 获取所有适用于该端点的自定义测试用例类。 + * 实例化每个测试用例类。 + * 调用 `_prepare_initial_request_data` 方法准备初始请求数据(路径参数、查询参数、请求头、请求体)。此方法会根据全局配置和测试用例自身的配置决定是否使用 LLM 进行数据生成,并利用 `LLMService` 和动态 Pydantic 模型创建(`_create_pydantic_model_from_schema`)来实现。如果LLM未启用或不适用,则使用传统的基于 Schema 的数据生成逻辑(`_generate_params_from_list`, `_generate_data_from_schema`)。此阶段还实现了端点级别的LLM参数缓存。 + * 依次调用测试用例实例中定义的 `generate_*` 方法,允许测试用例修改生成的请求数据。 + * 调用测试用例实例中定义的 `validate_request_*` 方法,对即将发送的请求进行预校验。 + * 使用 `APICaller` 发送最终构建的 API 请求。 + * 接收到 API 响应后,调用测试用例实例中定义的 `validate_response` 和 `check_performance` 方法,对响应进行详细验证。 + * **结果汇总**:收集每个测试用例的执行结果 (`ExecutedTestCaseResult`),汇总成每个端点的测试结果 (`TestResult`),并最终生成整个测试运行的摘要 (`TestSummary`)。 +3. **测试用例注册表 (`TestCaseRegistry` 在 `ddms_compliance_suite/test_case_registry.py`)**: -4. **测试框架核心 (`test_framework_core.py`)**: - * **`BaseAPITestCase`**:所有自定义测试用例的基类。它定义了测试用例应具备的元数据(如 `id`, `name`, `description`, `severity`, `tags`, `execution_order`, `applicable_methods`, `applicable_paths_regex` 以及 LLM 使用标志位)和一系列生命周期钩子方法(如 `generate_*`, `validate_*`)。 - * **`APIRequestContext` / `APIResponseContext`**:数据类,分别用于封装 API 请求和响应的上下文信息,在测试用例的钩子方法间传递。 - * **`ValidationResult`**:数据类,用于表示单个验证点的结果(通过/失败、消息、详细信息)。 - * **`TestSeverity`**:枚举类型,定义测试用例的严重级别。 + * **动态发现**:负责在用户指定的目录 (`custom_test_cases_dir`) 下扫描并动态加载所有以 `.py` 结尾的测试用例文件。 + * **类识别与注册**:从加载的模块中,识别出所有继承自 `BaseAPITestCase` 的类,并根据其 `id` 属性进行注册。 + * **执行顺序排序**:在发现所有测试用例类后,会根据每个类的 `execution_order` 属性(主排序键,升序)和类名 `__name__`(次排序键,字母升序)对它们进行排序。 + * **适用性筛选**:提供 `get_applicable_test_cases` 方法,根据 API 端点的 HTTP 方法和路径(通过正则表达式匹配)筛选出适用的、已排序的测试用例类列表给编排器。 +4. **测试框架核心 (`test_framework_core.py`)**: -5. **API 规范解析器 (`InputParser` 在 `ddms_compliance_suite/input_parser/parser.py`)**: - * 负责读取和解析 YAPI(JSON 格式)或 Swagger/OpenAPI(JSON 或 YAML 格式)的 API 规范文件。 - * 将原始规范数据转换成框架内部易于处理的结构化对象(如 `ParsedYAPISpec`, `YAPIEndpoint`, `ParsedSwaggerSpec`, `SwaggerEndpoint`)。 + * **`BaseAPITestCase`**:所有自定义测试用例的基类。它定义了测试用例应具备的元数据(如 `id`, `name`, `description`, `severity`, `tags`, `execution_order`, `applicable_methods`, `applicable_paths_regex` 以及 LLM 使用标志位)和一系列生命周期钩子方法(如 `generate_*`, `validate_*`)。 + * **`APIRequestContext` / `APIResponseContext`**:数据类,分别用于封装 API 请求和响应的上下文信息,在测试用例的钩子方法间传递。 + * **`ValidationResult`**:数据类,用于表示单个验证点的结果(通过/失败、消息、详细信息)。 + * **`TestSeverity`**:枚举类型,定义测试用例的严重级别。 +5. **API 规范解析器 (`InputParser` 在 `ddms_compliance_suite/input_parser/parser.py`)**: -6. **API 调用器 (`APICaller` 在 `ddms_compliance_suite/api_caller/caller.py`)**: - * 封装了实际的 HTTP 请求发送逻辑。 - * 接收一个 `APIRequest` 对象(包含方法、URL、参数、头部、请求体),使用如 `requests` 库执行请求,并返回一个 `APIResponse` 对象(包含状态码、响应头、响应体内容等)。 + * 负责读取和解析 YAPI(JSON 格式)或 Swagger/OpenAPI(JSON 或 YAML 格式)的 API 规范文件。 + * 将原始规范数据转换成框架内部易于处理的结构化对象(如 `ParsedYAPISpec`, `YAPIEndpoint`, `ParsedSwaggerSpec`, `SwaggerEndpoint`)。 +6. **API 调用器 (`APICaller` 在 `ddms_compliance_suite/api_caller/caller.py`)**: -7. **LLM 服务 (`LLMService` 在 `ddms_compliance_suite/llm_utils/llm_service.py`)** (可选): - * 如果配置了 LLM 服务(如通义千问的兼容 OpenAI 模式的 API),此组件负责与 LLM API 交互。 - * 主要用于根据 Pydantic 模型(从 JSON Schema 动态创建)智能生成复杂的请求参数或请求体。 + * 封装了实际的 HTTP 请求发送逻辑。 + * 接收一个 `APIRequest` 对象(包含方法、URL、参数、头部、请求体),使用如 `requests` 库执行请求,并返回一个 `APIResponse` 对象(包含状态码、响应头、响应体内容等)。 +7. **LLM 服务 (`LLMService` 在 `ddms_compliance_suite/llm_utils/llm_service.py`)** (可选): + + * 如果配置了 LLM 服务(如通义千问的兼容 OpenAI 模式的 API),此组件负责与 LLM API 交互。 + * 主要用于根据 Pydantic 模型(从 JSON Schema 动态创建)智能生成复杂的请求参数或请求体。 这个架构旨在提供一个灵活、可扩展的 API 测试框架,允许用户通过编写自定义的 Python 测试用例来定义复杂的验证逻辑。 @@ -56,67 +57,67 @@ ### 1. 创建自定义测试用例 -1. **创建 Python 文件**:在您的自定义测试用例目录(例如 `custom_testcases/`)下创建一个新的 `.py` 文件。 -2. **继承 `BaseAPITestCase`**:定义一个或多个类,使其继承自 `ddms_compliance_suite.test_framework_core.BaseAPITestCase`。 -3. **定义元数据 (类属性)**: - * `id: str`: 测试用例的全局唯一标识符 (例如 `"TC-MYFEATURE-001"`)。 - * `name: str`: 人类可读的名称。 - * `description: str`: 详细描述。 - * `severity: TestSeverity`: 严重程度 (例如 `TestSeverity.CRITICAL`, `TestSeverity.HIGH`, 等)。 - * `tags: List[str]`: 分类标签 (例如 `["smoke", "regression"]`)。 - * **`execution_order: int` (新增)**: 控制测试用例的执行顺序。**数值较小的会比较大的先执行**。如果多个测试用例此值相同,则它们会再根据类名的字母顺序排序。默认值为 `100`。 - ```python - class MyFirstCheck(BaseAPITestCase): - execution_order = 10 - # ... other metadata - - class MySecondCheck(BaseAPITestCase): - execution_order = 20 - # ... other metadata - ``` - * `applicable_methods: Optional[List[str]]`: 限制适用的 HTTP 方法 (例如 `["POST", "PUT"]`)。`None` 表示所有方法。 - * `applicable_paths_regex: Optional[str]`: 限制适用的 API 路径 (Python 正则表达式)。`None` 表示所有路径。 - * **LLM 使用标志 (可选)**: 这些标志允许测试用例覆盖全局 LLM 配置。 - * `use_llm_for_body: bool = False` - * `use_llm_for_path_params: bool = False` - * `use_llm_for_query_params: bool = False` - * `use_llm_for_headers: bool = False` - (如果测试用例中不设置这些,则遵循 `run_api_tests.py` 传入的全局 LLM 开关。) +1. **创建 Python 文件**:在您的自定义测试用例目录(例如 `custom_testcases/`)下创建一个新的 `.py` 文件。 +2. **继承 `BaseAPITestCase`**:定义一个或多个类,使其继承自 `ddms_compliance_suite.test_framework_core.BaseAPITestCase`。 +3. **定义元数据 (类属性)**: -4. **实现验证逻辑**:重写 `BaseAPITestCase` 中一个或多个 `generate_*` 或 `validate_*` 方法。 + * `id: str`: 测试用例的全局唯一标识符 (例如 `"TC-MYFEATURE-001"`)。 + * `name: str`: 人类可读的名称。 + * `description: str`: 详细描述。 + * `severity: TestSeverity`: 严重程度 (例如 `TestSeverity.CRITICAL`, `TestSeverity.HIGH`, 等)。 + * `tags: List[str]`: 分类标签 (例如 `["smoke", "regression"]`)。 + * **`execution_order: int` (新增)**: 控制测试用例的执行顺序。**数值较小的会比较大的先执行**。如果多个测试用例此值相同,则它们会再根据类名的字母顺序排序。默认值为 `100`。 + ```python + class MyFirstCheck(BaseAPITestCase): + execution_order = 10 + # ... other metadata + + class MySecondCheck(BaseAPITestCase): + execution_order = 20 + # ... other metadata + ``` + * `applicable_methods: Optional[List[str]]`: 限制适用的 HTTP 方法 (例如 `["POST", "PUT"]`)。`None` 表示所有方法。 + * `applicable_paths_regex: Optional[str]`: 限制适用的 API 路径 (Python 正则表达式)。`None` 表示所有路径。 + * **LLM 使用标志 (可选)**: 这些标志允许测试用例覆盖全局 LLM 配置。 + * `use_llm_for_body: bool = False` + * `use_llm_for_path_params: bool = False` + * `use_llm_for_query_params: bool = False` + * `use_llm_for_headers: bool = False` + (如果测试用例中不设置这些,则遵循 `run_api_tests.py` 传入的全局 LLM 开关。) +4. **实现验证逻辑**:重写 `BaseAPITestCase` 中一个或多个 `generate_*` 或 `validate_*` 方法。 ### 2. `BaseAPITestCase` 核心方法 -* **`__init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any])`**: - * 构造函数。`endpoint_spec` 包含当前测试端点的 API 定义,`global_api_spec` 包含完整的 API 规范。 - * 基类会初始化 `self.logger`,可用于记录日志。 +* **`__init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any])`**: -* **请求生成与修改方法**: 在 API 请求发送前调用,用于修改或生成请求数据。 - * `generate_query_params(self, current_query_params: Dict[str, Any]) -> Dict[str, Any]` - * `generate_headers(self, current_headers: Dict[str, str]) -> Dict[str, str]` - * `generate_request_body(self, current_body: Optional[Any]) -> Optional[Any]` - * (如果需要,您也可以尝试定义 `generate_path_params` 方法来自定义路径参数的生成,其模式与上述类似。) + * 构造函数。`endpoint_spec` 包含当前测试端点的 API 定义,`global_api_spec` 包含完整的 API 规范。 + * 基类会初始化 `self.logger`,可用于记录日志。 +* **请求生成与修改方法**: 在 API 请求发送前调用,用于修改或生成请求数据。 -* **请求预校验方法**: 在请求数据完全构建后、发送前调用,用于静态检查。返回 `List[ValidationResult]`。 - * `validate_request_url(self, url: str, request_context: APIRequestContext) -> List[ValidationResult]` - * `validate_request_headers(self, headers: Dict[str, str], request_context: APIRequestContext) -> List[ValidationResult]` - * `validate_request_body(self, body: Optional[Any], request_context: APIRequestContext) -> List[ValidationResult]` + * `generate_query_params(self, current_query_params: Dict[str, Any]) -> Dict[str, Any]` + * `generate_headers(self, current_headers: Dict[str, str]) -> Dict[str, str]` + * `generate_request_body(self, current_body: Optional[Any]) -> Optional[Any]` +* **请求预校验方法**: 在请求数据完全构建后、发送前调用,用于静态检查。返回 `List[ValidationResult]`。 -* **响应验证方法**: 在收到 API 响应后调用,这是最主要的验证阶段。返回 `List[ValidationResult]`。 - * `validate_response(self, response_context: APIResponseContext, request_context: APIRequestContext) -> List[ValidationResult]` - * 检查状态码、响应头、响应体内容是否符合预期。 - * 进行业务逻辑相关的断言。 + * `validate_request_url(self, url: str, request_context: APIRequestContext) -> List[ValidationResult]` + * `validate_request_headers(self, headers: Dict[str, str], request_context: APIRequestContext) -> List[ValidationResult]` + * `validate_request_body(self, body: Optional[Any], request_context: APIRequestContext) -> List[ValidationResult]` +* **响应验证方法**: 在收到 API 响应后调用,这是最主要的验证阶段。返回 `List[ValidationResult]`。 -* **性能检查方法 (可选)**: - * `check_performance(self, response_context: APIResponseContext, request_context: APIRequestContext) -> List[ValidationResult]` - * 通常用于检查响应时间 `response_context.elapsed_time`。 + * `validate_response(self, response_context: APIResponseContext, request_context: APIRequestContext) -> List[ValidationResult]` + * 检查状态码、响应头、响应体内容是否符合预期。 + * 进行业务逻辑相关的断言。 +* **性能检查方法 (可选)**: + + * `check_performance(self, response_context: APIResponseContext, request_context: APIRequestContext) -> List[ValidationResult]` + * 通常用于检查响应时间 `response_context.elapsed_time`。 ### 3. 核心辅助类 -* **`ValidationResult(passed: bool, message: str, details: Optional[Dict[str, Any]] = None)`**: - * 封装单个验证点的结果。所有 `validate_*` 和 `check_*` 方法都应返回此对象的列表。 -* **`APIRequestContext`**: 包含当前请求的详细信息(方法、URL、参数、头、体、端点规范)。 -* **`APIResponseContext`**: 包含 API 响应的详细信息(状态码、头、JSON 内容、文本内容、耗时、原始响应对象、关联的请求上下文)。 +* **`ValidationResult(passed: bool, message: str, details: Optional[Dict[str, Any]] = None)`**: + * 封装单个验证点的结果。所有 `validate_*` 和 `check_*` 方法都应返回此对象的列表。 +* **`APIRequestContext`**: 包含当前请求的详细信息(方法、URL、参数、头、体、端点规范)。 +* **`APIResponseContext`**: 包含 API 响应的详细信息(状态码、头、JSON 内容、文本内容、耗时、原始响应对象、关联的请求上下文)。 ### 4. 示例 (展示 `execution_order`) @@ -161,10 +162,10 @@ class EssentialHeaderCheck(BaseAPITestCase): ### 5. 最佳实践 -* **单一职责**:让每个 `APITestCase` 专注于特定的验证目标。 -* **清晰命名**:为类、ID、名称使用描述性文字。 -* **善用 `endpoint_spec`**:参考 API 定义进行精确测试。 -* **详细的 `ValidationResult`**:失败时提供充足的上下文信息。 -* **日志记录**:使用 `self.logger` 记录测试过程中的重要信息和问题。 +* **单一职责**:让每个 `APITestCase` 专注于特定的验证目标。 +* **清晰命名**:为类、ID、名称使用描述性文字。 +* **善用 `endpoint_spec`**:参考 API 定义进行精确测试。 +* **详细的 `ValidationResult`**:失败时提供充足的上下文信息。 +* **日志记录**:使用 `self.logger` 记录测试过程中的重要信息和问题。 -希望这份更新的架构概览和编写指南对您有所帮助!通过 `execution_order`,您可以更好地控制复杂场景下测试用例的执行流程。 \ No newline at end of file +希望这份更新的架构概览和编写指南对您有所帮助!通过 `execution_order`,您可以更好地控制复杂场景下测试用例的执行流程。 diff --git a/assets/doc/井筒API示例_simple.json b/assets/doc/井筒API示例_simple.json new file mode 100644 index 0000000..c91a099 --- /dev/null +++ b/assets/doc/井筒API示例_simple.json @@ -0,0 +1,430 @@ +[ + { + "index": 0, + "name": "公共分类", + "desc": "公共分类", + "add_time": 1730355210, + "up_time": 1730355210, + "list": [ + { + "query_path": { + "path": "/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}", + "params": [] + }, + "edit_uid": 0, + "status": "undone", + "type": "var", + "req_body_is_json_schema": true, + "res_body_is_json_schema": true, + "api_opened": false, + "index": 0, + "tag": [], + "_id": 135716, + "method": "POST", + "title": "数据推送接口", + "desc": "", + "path": "/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}", + "req_params": [ + { + "_id": "67ff3dc5335acf6754926ab7", + "name": "dms_instance_code", + "desc": "注册实例code\n井筒中心 well_kd_wellbore_ideas01" + }, + { + "_id": "67ff3dc5335acf0829926ab6", + "name": "schema", + "desc": "" + }, + { + "_id": "67ff3dc5335acf485f926ab5", + "name": "version", + "desc": "" + } + ], + "req_body_form": [], + "req_headers": [ + { + "required": "1", + "_id": "67ff3dc5335acf11b4926aba", + "name": "Content-Type", + "value": "application/json" + }, + { + "required": "1", + "_id": "67ff3dc5335acfae3f926ab9", + "name": "tenant-id", + "desc": "tenant-id (Only:undefined)" + }, + { + "required": "1", + "_id": "67ff3dc5335acfad4f926ab8", + "name": "Authorization", + "desc": "Authorization (Only:undefined)" + } + ], + "req_query": [], + "req_body_type": "json", + "res_body_type": "json", + "res_body": "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"number\"},\"message\":{\"type\":\"string\"},\"data\":{\"type\":\"object\",\"properties\":{\"total\":{\"type\":\"number\"},\"list\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"dsid\":{\"type\":\"string\"},\"dataRegion\":{\"type\":\"string\"},\"gasReleaseMon\":{\"type\":\"null\"},\"gasReleaseYear\":{\"type\":\"null\"},\"releaseGasCum\":{\"type\":\"null\"}}}}}}}}", + "req_body_other": "{\"properties\":{\"isSearchCount\":{\"default\":true,\"description\":\"是否统计总条数\",\"type\":\"boolean\"},\"query\":{\"description\":\"查询条件\",\"properties\":{\"dataRegions\":{\"description\":\"数据域,如:JD、DG、TL\",\"items\":{\"description\":\"数据域,如:JD、DG、TL\",\"type\":\"string\"},\"type\":\"array\"},\"fields\":{\"description\":\"查询的字段\",\"items\":{\"description\":\"查询的字段\",\"type\":\"string\"},\"type\":\"array\"},\"filter\":{\"description\":\"筛选器\",\"properties\":{\"key\":{\"description\":\"条件项\",\"type\":\"string\"},\"logic\":{\"description\":\"逻辑操作符,可选值为:AND、OR\",\"type\":\"string\"},\"realValue\":{\"description\":\"条件值\",\"items\":{\"description\":\"条件值\",\"type\":\"object\",\"properties\":{}},\"type\":\"array\"},\"singleValue\":{\"type\":\"object\",\"writeOnly\":true,\"properties\":{}},\"subFilter\":{\"description\":\"子条件\",\"items\":{\"$ref\":\"#/components/schemas/FilterVO\",\"type\":\"string\"},\"type\":\"array\"},\"symbol\":{\"description\":\"运算符,可选值为:>、>=、<、<=、>、<、=、<>、!=、IN、NOTIN、LIKE、IS;当运算符为 IS 时,条件值只能为NULL或NOT NULL\",\"type\":\"string\"}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/FilterVO\"},\"groupFields\":{\"description\":\"分组字段group by\",\"items\":{\"description\":\"分组字段group by\",\"type\":\"string\"},\"type\":\"array\"},\"groupFilter\":{\"description\":\"筛选器\",\"properties\":{\"key\":{\"description\":\"条件项\",\"type\":\"string\"},\"logic\":{\"description\":\"逻辑操作符,可选值为:AND、OR\",\"type\":\"string\"},\"realValue\":{\"description\":\"条件值\",\"items\":{\"description\":\"条件值\",\"type\":\"object\",\"properties\":{}},\"type\":\"array\"},\"singleValue\":{\"type\":\"object\",\"writeOnly\":true,\"properties\":{}},\"subFilter\":{\"description\":\"子条件\",\"items\":{\"$ref\":\"#/components/schemas/FilterVO\",\"type\":\"string\"},\"type\":\"array\"},\"symbol\":{\"description\":\"运算符,可选值为:>、>=、<、<=、>、<、=、<>、!=、IN、NOTIN、LIKE、IS;当运算符为 IS 时,条件值只能为NULL或NOT NULL\",\"type\":\"string\"}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/FilterVO\"},\"sort\":{\"additionalProperties\":{\"description\":\"排序字段,key=字段名,value=排序方式(ASC、DESC)\",\"type\":\"string\"},\"description\":\"排序字段,key=字段名,value=排序方式(ASC、DESC)\",\"type\":\"object\",\"properties\":{}}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/QueryVO\"}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/RdbQueryPageInput\"}", + "project_id": 1193, + "catid": 17672, + "markdown": "", + "uid": 808, + "add_time": 1744780583, + "up_time": 1744780741, + "__v": 0 + } + ] + }, + { + "index": 0, + "name": "地质单元", + "desc": null, + "add_time": 1745736888, + "up_time": 1745736888, + "list": [ + { + "query_path": { + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}", + "params": [] + }, + "edit_uid": 0, + "status": "undone", + "type": "var", + "req_body_is_json_schema": true, + "res_body_is_json_schema": true, + "api_opened": false, + "index": 0, + "tag": [], + "_id": 135751, + "method": "POST", + "title": "地质单元列表查询", + "desc": "", + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}", + "req_params": [ + { + "_id": "680dd55a335acff12e926d18", + "name": "dms_instance_code", + "desc": "注册实例code\n井筒中心 well_kd_wellbore_ideas01" + }, + { + "_id": "680dd55a335acfc43d926d17", + "name": "version", + "example": "1.0.0", + "desc": "交换模型版本" + } + ], + "req_body_form": [], + "req_headers": [ + { + "required": "1", + "_id": "680dd55a335acfb51b926d1d", + "name": "Content-Type", + "value": "application/json" + }, + { + "required": "1", + "_id": "680dd55a335acf6226926d1c", + "name": "tenant-id", + "desc": "tenant-id (Only:undefined)" + }, + { + "required": "1", + "_id": "680dd55a335acf39a0926d1b", + "name": "Authorization", + "desc": "Authorization (Only:undefined)" + } + ], + "req_query": [ + { + "required": "0", + "_id": "680dd55a335acfabfa926d1a", + "name": "pageNo", + "desc": "页码(从1开始)" + }, + { + "required": "0", + "_id": "680dd55a335acf831b926d19", + "name": "pageSize", + "desc": "分页大小(最大值200)" + } + ], + "req_body_type": "json", + "res_body_type": "json", + "res_body": "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"number\"},\"message\":{\"type\":\"string\"},\"data\":{\"type\":\"object\",\"properties\":{\"total\":{\"type\":\"number\"},\"list\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"dsid\":{\"type\":\"string\"},\"dataRegion\":{\"type\":\"string\"},\"gasReleaseMon\":{\"type\":\"null\"},\"gasReleaseYear\":{\"type\":\"null\"},\"releaseGasCum\":{\"type\":\"null\"}}}}}}}}", + "req_body_other": "{\"properties\":{\"isSearchCount\":{\"default\":true,\"description\":\"是否统计总条数\",\"type\":\"boolean\"},\"query\":{\"description\":\"查询条件\",\"properties\":{\"dataRegions\":{\"description\":\"数据域,如:JD、DG、TL\",\"items\":{\"description\":\"数据域,如:JD、DG、TL\",\"type\":\"string\"},\"type\":\"array\"},\"fields\":{\"description\":\"查询的字段\",\"items\":{\"description\":\"查询的字段\",\"type\":\"string\"},\"type\":\"array\"},\"filter\":{\"description\":\"筛选器\",\"properties\":{\"key\":{\"description\":\"条件项\",\"type\":\"string\"},\"logic\":{\"description\":\"逻辑操作符,可选值为:AND、OR\",\"type\":\"string\"},\"realValue\":{\"description\":\"条件值\",\"items\":{\"description\":\"条件值\",\"type\":\"object\",\"properties\":{}},\"type\":\"array\"},\"singleValue\":{\"type\":\"object\",\"writeOnly\":true,\"properties\":{}},\"subFilter\":{\"description\":\"子条件\",\"items\":{\"$ref\":\"#/components/schemas/FilterVO\",\"type\":\"string\"},\"type\":\"array\"},\"symbol\":{\"description\":\"运算符,可选值为:>、>=、<、<=、>、<、=、<>、!=、IN、NOTIN、LIKE、IS;当运算符为 IS 时,条件值只能为NULL或NOT NULL\",\"type\":\"string\"}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/FilterVO\"},\"groupFields\":{\"description\":\"分组字段group by\",\"items\":{\"description\":\"分组字段group by\",\"type\":\"string\"},\"type\":\"array\"},\"groupFilter\":{\"description\":\"筛选器\",\"properties\":{\"key\":{\"description\":\"条件项\",\"type\":\"string\"},\"logic\":{\"description\":\"逻辑操作符,可选值为:AND、OR\",\"type\":\"string\"},\"realValue\":{\"description\":\"条件值\",\"items\":{\"description\":\"条件值\",\"type\":\"object\",\"properties\":{}},\"type\":\"array\"},\"singleValue\":{\"type\":\"object\",\"writeOnly\":true,\"properties\":{}},\"subFilter\":{\"description\":\"子条件\",\"items\":{\"$ref\":\"#/components/schemas/FilterVO\",\"type\":\"string\"},\"type\":\"array\"},\"symbol\":{\"description\":\"运算符,可选值为:>、>=、<、<=、>、<、=、<>、!=、IN、NOTIN、LIKE、IS;当运算符为 IS 时,条件值只能为NULL或NOT NULL\",\"type\":\"string\"}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/FilterVO\"},\"sort\":{\"additionalProperties\":{\"description\":\"排序字段,key=字段名,value=排序方式(ASC、DESC)\",\"type\":\"string\"},\"description\":\"排序字段,key=字段名,value=排序方式(ASC、DESC)\",\"type\":\"object\",\"properties\":{}}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/QueryVO\"}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/RdbQueryPageInput\"}", + "project_id": 1193, + "catid": 18705, + "markdown": "", + "uid": 1103, + "add_time": 1745736910, + "up_time": 1745737050, + "__v": 0 + }, + { + "query_path": { + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "params": [] + }, + "edit_uid": 0, + "status": "undone", + "type": "var", + "req_body_is_json_schema": true, + "res_body_is_json_schema": true, + "api_opened": false, + "index": 0, + "tag": [], + "_id": 135749, + "method": "PUT", + "title": "地质单元数据修改", + "desc": "", + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "req_params": [ + { + "_id": "680dd510335acf19c3926cec", + "name": "dms_instance_code", + "desc": "注册实例code\n井筒中心 well_kd_wellbore_ideas01" + } + ], + "req_body_form": [], + "req_headers": [ + { + "required": "1", + "_id": "680dd510335acf7bb3926cf0", + "name": "Content-Type", + "value": "application/json" + }, + { + "required": "1", + "_id": "680dd510335acf6953926cef", + "name": "tenant-id", + "desc": "tenant-id (Only:undefined)" + }, + { + "required": "1", + "_id": "680dd510335acfd86b926cee", + "name": "Authorization", + "desc": "Authorization (Only:undefined)" + } + ], + "req_query": [ + { + "required": "1", + "_id": "680dd510335acf1ed1926ced", + "name": "id", + "example": "dsid", + "desc": "主键id的key" + } + ], + "req_body_type": "json", + "res_body_type": "json", + "res_body": "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"number\"},\"message\":{\"type\":\"string\"},\"data\":{\"type\":\"boolean\"}}}", + "req_body_other": "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"version\":{\"type\":\"string\"},\"data\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"bsflag\":{\"type\":\"number\"},\"wellCommonName\":{\"type\":\"string\"},\"wellId\":{\"type\":\"string\"},\"dataRegion\":{\"type\":\"string\"}},\"required\":[\"bsflag\",\"wellCommonName\",\"wellId\",\"dataRegion\"]}}}}", + "project_id": 1193, + "catid": 18705, + "markdown": "", + "uid": 1103, + "add_time": 1745736907, + "up_time": 1745736976, + "__v": 0 + }, + { + "query_path": { + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "params": [] + }, + "edit_uid": 0, + "status": "undone", + "type": "var", + "req_body_is_json_schema": true, + "res_body_is_json_schema": true, + "api_opened": false, + "index": 0, + "tag": [], + "_id": 135750, + "method": "DELETE", + "title": "地质单元数据删除", + "desc": "", + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "req_params": [ + { + "_id": "680dd51b335acfe93a926cf1", + "name": "dms_instance_code", + "desc": "注册实例code\n井筒中心 well_kd_wellbore_ideas01" + } + ], + "req_body_form": [], + "req_headers": [ + { + "required": "1", + "_id": "680dd51b335acfb316926cf5", + "name": "Content-Type", + "value": "application/json" + }, + { + "required": "1", + "_id": "680dd51b335acf45f4926cf4", + "name": "tenant-id", + "desc": "tenant-id (Only:undefined)" + }, + { + "required": "1", + "_id": "680dd51b335acf0cfa926cf3", + "name": "Authorization", + "desc": "Authorization (Only:undefined)" + } + ], + "req_query": [ + { + "required": "1", + "_id": "680dd51b335acf7441926cf2", + "name": "id", + "example": "dsid", + "desc": "主键id的key" + } + ], + "req_body_type": "json", + "res_body_type": "json", + "res_body": "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"number\"},\"message\":{\"type\":\"string\"},\"data\":{\"type\":\"boolean\"}}}", + "req_body_other": "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"version\":{\"type\":\"string\",\"title\":\"版本号\"},\"data\":{\"type\":\"array\",\"items\":{\"type\":\"string\"},\"title\":\"主键id数据集\"}}}", + "project_id": 1193, + "catid": 18705, + "markdown": "", + "uid": 1103, + "add_time": 1745736908, + "up_time": 1745736987, + "__v": 0 + }, + { + "query_path": { + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "params": [] + }, + "edit_uid": 0, + "status": "done", + "type": "var", + "req_body_is_json_schema": true, + "res_body_is_json_schema": true, + "api_opened": false, + "index": 0, + "tag": [], + "_id": 135748, + "method": "POST", + "title": "地质单元数据添加", + "desc": "", + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "req_params": [ + { + "_id": "680dd4ff335acf81b3926ce8", + "name": "dms_instance_code", + "desc": "注册实例code\n井筒中心 well_kd_wellbore_ideas01" + } + ], + "req_body_form": [], + "req_headers": [ + { + "required": "1", + "_id": "680dd4ff335acfc5c7926ceb", + "name": "Content-Type", + "value": "application/json" + }, + { + "required": "1", + "_id": "680dd4ff335acff16f926cea", + "name": "tenant-id", + "desc": "tenant-id (Only:undefined)" + }, + { + "required": "1", + "_id": "680dd4ff335acf1a5c926ce9", + "name": "Authorization", + "desc": "Authorization (Only:undefined)" + } + ], + "req_query": [], + "req_body_type": "json", + "res_body_type": "json", + "res_body": "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"number\"},\"message\":{\"type\":\"string\"},\"data\":{\"type\":\"boolean\"}}}", + "req_body_other": "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"version\":{\"type\":\"string\",\"title\":\"交换模型版本号\"},\"data\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"bsflag\":{\"type\":\"number\",\"title\":\"必填字段删除标记\"},\"wellCommonName\":{\"type\":\"string\"},\"wellId\":{\"type\":\"string\"},\"dataRegion\":{\"type\":\"string\"}},\"required\":[\"bsflag\",\"wellCommonName\",\"wellId\",\"dataRegion\"]},\"title\":\"交换模型数据集\"}}}", + "project_id": 1193, + "catid": 18705, + "markdown": "", + "uid": 1103, + "add_time": 1745736907, + "up_time": 1745736959, + "__v": 0 + }, + { + "query_path": { + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}", + "params": [] + }, + "edit_uid": 0, + "status": "done", + "type": "var", + "req_body_is_json_schema": true, + "res_body_is_json_schema": true, + "api_opened": false, + "index": 0, + "tag": [], + "_id": 135752, + "method": "GET", + "title": "地质单元查询详情", + "desc": "", + "path": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}", + "req_params": [ + { + "_id": "680dd53d335acf42db926d05", + "name": "dms_instance_code", + "desc": "注册实例code\n井筒中心 well_kd_wellbore_ideas01" + }, + { + "_id": "680dd53d335acf2105926d04", + "name": "version", + "example": "1.0.0", + "desc": "交换模型版本" + }, + { + "_id": "680dd53d335acf7970926d03", + "name": "id", + "desc": "" + } + ], + "req_body_form": [], + "req_headers": [ + { + "required": "1", + "_id": "680dd53d335acf68e4926d08", + "name": "Content-Type", + "value": "application/json" + }, + { + "required": "1", + "_id": "680dd53d335acf9fb4926d07", + "name": "tenant-id", + "desc": "tenant-id (Only:undefined)" + }, + { + "required": "1", + "_id": "680dd53d335acf7a8d926d06", + "name": "Authorization", + "desc": "Authorization (Only:undefined)" + } + ], + "req_query": [], + "req_body_type": "json", + "res_body_type": "json", + "res_body": "{\"$schema\":\"http://json-schema.org/draft-04/schema#\",\"type\":\"object\",\"properties\":{\"code\":{\"type\":\"number\"},\"message\":{\"type\":\"string\"},\"data\":{\"type\":\"object\",\"properties\":{\"total\":{\"type\":\"number\"},\"list\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"properties\":{\"dsid\":{\"type\":\"string\"},\"dataRegion\":{\"type\":\"string\"},\"gasReleaseMon\":{\"type\":\"null\"},\"gasReleaseYear\":{\"type\":\"null\"},\"releaseGasCum\":{\"type\":\"null\"}}}}}}}}", + "req_body_other": "{\"properties\":{\"isSearchCount\":{\"default\":true,\"description\":\"是否统计总条数\",\"type\":\"boolean\"},\"query\":{\"description\":\"查询条件\",\"properties\":{\"dataRegions\":{\"description\":\"数据域,如:JD、DG、TL\",\"items\":{\"description\":\"数据域,如:JD、DG、TL\",\"type\":\"string\"},\"type\":\"array\"},\"fields\":{\"description\":\"查询的字段\",\"items\":{\"description\":\"查询的字段\",\"type\":\"string\"},\"type\":\"array\"},\"filter\":{\"description\":\"筛选器\",\"properties\":{\"key\":{\"description\":\"条件项\",\"type\":\"string\"},\"logic\":{\"description\":\"逻辑操作符,可选值为:AND、OR\",\"type\":\"string\"},\"realValue\":{\"description\":\"条件值\",\"items\":{\"description\":\"条件值\",\"type\":\"object\",\"properties\":{}},\"type\":\"array\"},\"singleValue\":{\"type\":\"object\",\"writeOnly\":true,\"properties\":{}},\"subFilter\":{\"description\":\"子条件\",\"items\":{\"$ref\":\"#/components/schemas/FilterVO\",\"type\":\"string\"},\"type\":\"array\"},\"symbol\":{\"description\":\"运算符,可选值为:>、>=、<、<=、>、<、=、<>、!=、IN、NOTIN、LIKE、IS;当运算符为 IS 时,条件值只能为NULL或NOT NULL\",\"type\":\"string\"}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/FilterVO\"},\"groupFields\":{\"description\":\"分组字段group by\",\"items\":{\"description\":\"分组字段group by\",\"type\":\"string\"},\"type\":\"array\"},\"groupFilter\":{\"description\":\"筛选器\",\"properties\":{\"key\":{\"description\":\"条件项\",\"type\":\"string\"},\"logic\":{\"description\":\"逻辑操作符,可选值为:AND、OR\",\"type\":\"string\"},\"realValue\":{\"description\":\"条件值\",\"items\":{\"description\":\"条件值\",\"type\":\"object\",\"properties\":{}},\"type\":\"array\"},\"singleValue\":{\"type\":\"object\",\"writeOnly\":true,\"properties\":{}},\"subFilter\":{\"description\":\"子条件\",\"items\":{\"$ref\":\"#/components/schemas/FilterVO\",\"type\":\"string\"},\"type\":\"array\"},\"symbol\":{\"description\":\"运算符,可选值为:>、>=、<、<=、>、<、=、<>、!=、IN、NOTIN、LIKE、IS;当运算符为 IS 时,条件值只能为NULL或NOT NULL\",\"type\":\"string\"}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/FilterVO\"},\"sort\":{\"additionalProperties\":{\"description\":\"排序字段,key=字段名,value=排序方式(ASC、DESC)\",\"type\":\"string\"},\"description\":\"排序字段,key=字段名,value=排序方式(ASC、DESC)\",\"type\":\"object\",\"properties\":{}}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/QueryVO\"}},\"type\":\"object\",\"$$ref\":\"#/components/schemas/RdbQueryPageInput\"}", + "project_id": 1193, + "catid": 18705, + "markdown": "", + "uid": 1103, + "add_time": 1745736911, + "up_time": 1745737021, + "__v": 0 + } + ] + } +] \ No newline at end of file diff --git a/assets/images/dms1/.DS_Store b/assets/images/dms1/.DS_Store index 816c1f80005e2db4db728476b94c7efd2c5c1bf5..2e22604dadeec618895fff4030d3af714f7d6d6a 100644 GIT binary patch literal 8196 zcmeHMU2GLa6rOKe=)P8R9<314feVs%6F+Ipj@am~q-iafVw)%xA3!%oiio)jBE^b%k*CT-}c@!gbq z3a;b1he*P;%h++|vtxJ09-IIB9>d)@eyKxzaVeXZ$%}}68%0c3)Mb1+s zAl>WJKBC85xk^zqzxOZ!SeUAfYh^_<_c-Z{(8Njb7}>0i=+|L3qgH2z(sFV>pG=cmmJhMZAQU@e1C=IlO~+@d+;A zGklIO@C|;%Pxu*^@fZHa6-kk1OG~8tq-9dAv|MVGTBKI-pz=koN zj5W$5eSx|#v4;?C9UadfkxygUrB!h3${b|+-Rk0mHia-R*n8Eb32iFjU9h!@x`ZZC znhADgqCwTlD2bHNwlPtsYLErfthTCJIi-_eH>ev`jqwZ@d>fyMF#7L7dY*mAJ|&P| zB#{2feq(>ID+J7$s3uS@#WK{Q9xDi#EojAhY(OWrq6-faOncFXehgv=Sy%+pVb~}j zKoKQ8f=3Cer|~!e^;tZJ=kWs0;5D4Z>v#ii;XK}(1i@_+A&8I0Avozsny7dixH7S3 zHNXFN-u(OjZFsVH$=Cz22X2)IP`KaJ^AMLlbJa3YUl1 gaiUj$7*gMe#*z^o6_iG(-1-jz@%bO0|MB_%4=iw%iU0rr delta 120 zcmZp1XfcprU|?W$DortDU=RQ@Ie-{MGjUEV6q~50$jGuWU^gQp%Vr*d62{4M1e_-q ziBH|wu%3A_I|qj#Gf*WE2yg=lSCFQSh2NPc^UFAbOl4qXU|<2!Ob}ziVw>Z6<}d>Q D3$+t^ diff --git a/custom_testcases/__pycache__/basic_checks.cpython-312.pyc b/custom_testcases/__pycache__/basic_checks.cpython-312.pyc index 74bf19b36b53146ab6018050f22a1a0bd27c1691..bc10c5ef2a54cfc201c9720365067cf979e387c4 100644 GIT binary patch delta 651 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 diff --git a/custom_testcases/basic_checks.py b/custom_testcases/basic_checks.py index 308f069..6e572ad 100644 --- a/custom_testcases/basic_checks.py +++ b/custom_testcases/basic_checks.py @@ -13,13 +13,13 @@ class StatusCode200Check(BaseAPITestCase): # applicable_methods = None # applicable_paths_regex = None execution_order = 10 # 示例执行顺序 - use_llm_for_body: bool = True - use_llm_for_path_params: bool = True - use_llm_for_query_params: bool = True - use_llm_for_headers: bool = True + # use_llm_for_body: bool = True + # use_llm_for_path_params: bool = True + # use_llm_for_query_params: bool = True + # use_llm_for_headers: bool = True - def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None): - super().__init__(endpoint_spec, global_api_spec, json_schema_validator=json_schema_validator) + def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[Any] = None): + super().__init__(endpoint_spec, global_api_spec, json_schema_validator=json_schema_validator, llm_service=llm_service) self.logger.info(f"测试用例 {self.id} ({self.name}) 已针对端点 '{self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')}' 初始化。") def validate_response(self, response_context: APIResponseContext, request_context: APIRequestContext) -> list[ValidationResult]: @@ -50,42 +50,3 @@ class StatusCode200Check(BaseAPITestCase): ) self.logger.warning(f"状态码验证失败: 期望 {expected_status_code}, 实际 {actual_status_code} for {request_context.url}") return results - -class HeaderExistenceCheck(BaseAPITestCase): - id = "TC-HEADER-001" - name = "检查响应中是否存在 'X-Request-ID' 头" - description = "验证 API 响应是否包含 'X-Request-ID' 头。" - severity = TestSeverity.MEDIUM - tags = ["header", "observability"] - execution_order = 10 # 示例执行顺序 - use_llm_for_body = False - - EXPECTED_HEADER = "X-Request-ID" # 示例,可以根据实际需要修改 - - def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None): - super().__init__(endpoint_spec, global_api_spec, json_schema_validator=json_schema_validator) - self.logger.info(f"测试用例 {self.id} ({self.name}) 已初始化 for endpoint {self.endpoint_spec.get('path')}") - - def validate_response(self, response_context: APIResponseContext, request_context: APIRequestContext) -> list[ValidationResult]: - results = [] - if self.EXPECTED_HEADER in response_context.headers: - results.append( - ValidationResult( - passed=True, - message=f"响应头中找到了期望的 '{self.EXPECTED_HEADER}'。" - ) - ) - self.logger.info(f"请求头 '{self.EXPECTED_HEADER}' 存在于 {request_context.url} 的响应中。") - else: - results.append( - ValidationResult( - passed=False, - message=f"响应头中未找到期望的 '{self.EXPECTED_HEADER}'。", - details={ - "expected_header": self.EXPECTED_HEADER, - "actual_headers": list(response_context.headers.keys()) - } - ) - ) - self.logger.warning(f"请求头 '{self.EXPECTED_HEADER}' 未在 {request_context.url} 的响应中找到。") - return results \ No newline at end of file diff --git a/custom_testcases/compliance_catalog/core_functionality/__pycache__/schema_validation_case.cpython-312.pyc b/custom_testcases/compliance_catalog/core_functionality/__pycache__/schema_validation_case.cpython-312.pyc index 77a7c77d9d9526ccdf71631cf304614f631eccaf..bea638db5ab251f1c83dee5c1a1d96529f48b440 100644 GIT binary patch delta 673 zcmYLGOK1~87@mLjkxl9(o90>jNFr2>2MLx^6fG50P$U*B3afM}nTb`mq|7FwvY>|| zE#g52QBV)!MXBN;2l4JnFR9c^5Il)DsT4s))R~ypf&J%u{NMb{?9I~q5_wBV1j+TN zP?|k?oBWA%m=x9@h%`(*5<8$>9K9ur}K^!F@zE=|lu*3E^l-@yiTbQk2L17l+Md_?M7Q=wWDs z0lI>UR=EhgSK8vW7Jw-Z=&5vvx5KVm@n(GAb$wI%c~RA`nOTXh4vQBsAVNkocSF+e z*U<-yEQMCA?7hJ!vDTh)>+HFfm0h)Fo4brR7No=v@(D(oAEPf}JSh`xqcK0vI3JUk z$CRM?b*uJ zN!3>`H^FnNmuwW3^dE~?X{Ub;VdE5DL+Au{)OH3>XN1nWFd@R4nYNU-`Of6joqfJuB=i&?v)@4-Dt&O*yf>cE2sU Ofn3Link`;3$@3R6mVh<@ diff --git a/custom_testcases/compliance_catalog/core_functionality/schema_validation_case.py b/custom_testcases/compliance_catalog/core_functionality/schema_validation_case.py index b07e6bb..055463c 100644 --- a/custom_testcases/compliance_catalog/core_functionality/schema_validation_case.py +++ b/custom_testcases/compliance_catalog/core_functionality/schema_validation_case.py @@ -13,8 +13,8 @@ class ResponseSchemaValidationCase(BaseAPITestCase): # This test is generally applicable, especially for GET requests or successful POST/PUT. # It might need refinement based on specific endpoint characteristics (e.g., no response body for DELETE) - def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None): - super().__init__(endpoint_spec, global_api_spec, json_schema_validator) + def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[Any] = None): + super().__init__(endpoint_spec, global_api_spec, json_schema_validator, llm_service=llm_service) self.logger.info(f"测试用例 '{self.id}' 已为端点 '{self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')}' 初始化。") def validate_response(self, response_context: APIResponseContext, request_context: APIRequestContext) -> List[ValidationResult]: diff --git a/custom_testcases/compliance_catalog/error_handling/__pycache__/missing_required_field_body_case.cpython-312.pyc b/custom_testcases/compliance_catalog/error_handling/__pycache__/missing_required_field_body_case.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4baf97994789287ee7d1b8f01698c32054950f67 GIT binary patch literal 18237 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 literal 0 HcmV?d00001 diff --git a/custom_testcases/compliance_catalog/error_handling/__pycache__/missing_required_field_query_case.cpython-312.pyc b/custom_testcases/compliance_catalog/error_handling/__pycache__/missing_required_field_query_case.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a757eb1cf279ff423ec899caff1bd477a789db11 GIT binary patch literal 8522 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 P2sU+m+rKavQegiNM_=k= literal 0 HcmV?d00001 diff --git a/custom_testcases/compliance_catalog/error_handling/__pycache__/type_mismatch_query_param_case.cpython-312.pyc b/custom_testcases/compliance_catalog/error_handling/__pycache__/type_mismatch_query_param_case.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b79df5218e8e25055fdef214ead69a3d50cb688b GIT binary patch literal 16561 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 Dict[str, Any]: - ref_value = None - if isinstance(schema_to_resolve, dict): - if "$ref" in schema_to_resolve: - ref_value = schema_to_resolve["$ref"] - elif "$$ref" in schema_to_resolve: - ref_value = schema_to_resolve["$$ref"] - - if ref_value: - self.logger.debug(f"发现引用 '{ref_value}',尝试解析...") - try: - actual_global_spec_dict = None - if hasattr(self.global_api_spec, 'spec') and isinstance(self.global_api_spec.spec, dict): - actual_global_spec_dict = self.global_api_spec.spec - elif isinstance(self.global_api_spec, dict): - actual_global_spec_dict = self.global_api_spec - - if not actual_global_spec_dict: - self.logger.warning(f"无法从 self.global_api_spec (类型: {type(self.global_api_spec)}) 获取用于解析引用的字典。") - return schema_to_resolve - - resolved_schema = None - if ref_value.startswith("#/components/schemas/"): - schema_name = ref_value.split("/")[-1] - components = actual_global_spec_dict.get("components") - if components and isinstance(components.get("schemas"), dict): - resolved_schema = components["schemas"].get(schema_name) - if resolved_schema and isinstance(resolved_schema, dict): - self.logger.info(f"成功从 #/components/schemas/ 解析引用 '{ref_value}'。") - return resolved_schema - else: - self.logger.warning(f"解析引用 '{ref_value}' (路径: #/components/schemas/) 失败:未找到或找到的不是字典: {schema_name}") - else: - self.logger.warning(f"尝试从 #/components/schemas/ 解析引用 '{ref_value}' 失败:无法找到 'components.schemas' 结构。") - - # 如果从 #/components/schemas/ 未成功解析,尝试 #/definitions/ - if not resolved_schema and ref_value.startswith("#/definitions/"): - schema_name = ref_value.split("/")[-1] - definitions = actual_global_spec_dict.get("definitions") - if definitions and isinstance(definitions, dict): - resolved_schema = definitions.get(schema_name) - if resolved_schema and isinstance(resolved_schema, dict): - self.logger.info(f"成功从 #/definitions/ 解析引用 '{ref_value}'。") - return resolved_schema - else: - self.logger.warning(f"解析引用 '{ref_value}' (路径: #/definitions/) 失败:未找到或找到的不是字典: {schema_name}") - else: - self.logger.warning(f"尝试从 #/definitions/ 解析引用 '{ref_value}' 失败:无法找到 'definitions' 结构。") - - if not resolved_schema: - self.logger.warning(f"最终未能通过任一已知路径 (#/components/schemas/ 或 #/definitions/) 解析引用 '{ref_value}'。") - - except Exception as e: - self.logger.error(f"解析引用 '{ref_value}' 时发生错误: {e}", exc_info=True) - return schema_to_resolve # 返回原始 schema 如果不是 ref 或者所有解析尝试都失败 + # 根据用户进一步要求,方法体简化为直接返回,不进行任何 $ref/$ $$ref 的检查。 + # self.logger.debug(f"_resolve_ref_if_present called. Returning schema as-is per new configuration.") + return schema_to_resolve def _find_required_field_in_schema_recursive(self, current_schema: Dict[str, Any], current_path: List[str]) -> Optional[List[str]]: """递归查找第一个可移除的必填字段的路径。 diff --git a/custom_testcases/compliance_catalog/error_handling/missing_required_field_query_case.py b/custom_testcases/compliance_catalog/error_handling/missing_required_field_query_case.py index e9b9a3a..7c4c31a 100644 --- a/custom_testcases/compliance_catalog/error_handling/missing_required_field_query_case.py +++ b/custom_testcases/compliance_catalog/error_handling/missing_required_field_query_case.py @@ -10,10 +10,11 @@ class MissingRequiredFieldQueryCase(BaseAPITestCase): tags = ["error-handling", "appendix-b", "4003", "required-fields", "query-parameters"] execution_order = 211 # After body, before original combined one might have been - def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None): - super().__init__(endpoint_spec, global_api_spec, json_schema_validator) - self.removed_field_name: Optional[str] = None + def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[Any] = None): + super().__init__(endpoint_spec, global_api_spec, json_schema_validator=json_schema_validator, llm_service=llm_service) + self.target_param_name: Optional[str] = None self._try_find_removable_query_param() + self.logger.info(f"测试用例 {self.id} ({self.name}) 已针对端点 '{self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')}' 初始化。Target param to remove: {self.target_param_name}") def _try_find_removable_query_param(self): query_params_spec_list = self.endpoint_spec.get("parameters", []) @@ -23,8 +24,8 @@ class MissingRequiredFieldQueryCase(BaseAPITestCase): if isinstance(param_spec, dict) and param_spec.get("in") == "query" and param_spec.get("required") is True: field_name = param_spec.get("name") if field_name: - self.removed_field_name = field_name - self.logger.info(f"必填字段缺失测试的目标字段 (查询参数): '{self.removed_field_name}'") + self.target_param_name = field_name + self.logger.info(f"必填字段缺失测试的目标字段 (查询参数): '{self.target_param_name}'") return self.logger.info('在此端点规范中未找到可用于测试 "必填查询参数缺失" 的字段。') @@ -34,20 +35,20 @@ class MissingRequiredFieldQueryCase(BaseAPITestCase): return current_body def generate_query_params(self, current_query_params: Dict[str, Any]) -> Dict[str, Any]: - if self.removed_field_name and isinstance(current_query_params, dict): - if self.removed_field_name in current_query_params: + if self.target_param_name and isinstance(current_query_params, dict): + if self.target_param_name in current_query_params: new_params = copy.deepcopy(current_query_params) - original_value = new_params.pop(self.removed_field_name) # 移除参数 - self.logger.info(f"为进行必填查询参数缺失测试,已从查询参数中移除 '{self.removed_field_name}' (原值: '{original_value}')。") + original_value = new_params.pop(self.target_param_name) # 移除参数 + self.logger.info(f"为进行必填查询参数缺失测试,已从查询参数中移除 '{self.target_param_name}' (原值: '{original_value}')。") return new_params else: - self.logger.warning(f"计划移除的查询参数 '{self.removed_field_name}' 在当前查询参数中未找到。") + self.logger.warning(f"计划移除的查询参数 '{self.target_param_name}' 在当前查询参数中未找到。") return current_query_params def validate_response(self, response_context: APIResponseContext, request_context: APIRequestContext) -> List[ValidationResult]: results = [] - if not self.removed_field_name: + if not self.target_param_name: results.append(self.passed("跳过测试:在API规范中未找到合适的必填查询参数用于移除测试。")) self.logger.info("由于未识别到可移除的必填查询参数,跳过此测试用例。") return results @@ -58,7 +59,7 @@ class MissingRequiredFieldQueryCase(BaseAPITestCase): expected_status_codes = [400, 422] specific_error_code_from_appendix_b = "4003" - msg_prefix = f"当移除必填查询参数 '{self.removed_field_name}' 时," + msg_prefix = f"当移除必填查询参数 '{self.target_param_name}' 时," if status_code in expected_status_codes: status_msg = f"{msg_prefix}API响应了预期的错误状态码 {status_code}。" @@ -77,8 +78,8 @@ class MissingRequiredFieldQueryCase(BaseAPITestCase): else: results.append(self.failed( message=f"{msg_prefix}期望API返回状态码 {expected_status_codes} 中的一个,但实际收到 {status_code}。", - details={"status_code": status_code, "response_body": json_content, "removed_field": f"query.{self.removed_field_name}"} + details={"status_code": status_code, "response_body": json_content, "removed_field": f"query.{self.target_param_name}"} )) - self.logger.warning(f"必填查询参数缺失测试失败:期望状态码 {expected_status_codes},实际为 {status_code}。移除的参数:'{self.removed_field_name}'") + self.logger.warning(f"必填查询参数缺失测试失败:期望状态码 {expected_status_codes},实际为 {status_code}。移除的参数:'{self.target_param_name}'") return results \ No newline at end of file diff --git a/custom_testcases/compliance_catalog/error_handling/type_mismatch_body_case.py b/custom_testcases/compliance_catalog/error_handling/type_mismatch_body_case.py index 2a13631..4f76dfc 100644 --- a/custom_testcases/compliance_catalog/error_handling/type_mismatch_body_case.py +++ b/custom_testcases/compliance_catalog/error_handling/type_mismatch_body_case.py @@ -11,15 +11,20 @@ class TypeMismatchBodyCase(BaseAPITestCase): tags = ["error-handling", "appendix-b", "4001", "request-body"] execution_order = 202 # Slightly after query param one - def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None): - super().__init__(endpoint_spec, global_api_spec, json_schema_validator) + def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[Any] = None): + super().__init__(endpoint_spec, global_api_spec, json_schema_validator, llm_service=llm_service) self.logger.setLevel(logging.DEBUG) self.target_field_path: Optional[List[str]] = None self.original_field_type: Optional[str] = None # Location is always 'body' for this class self.target_field_location: str = "body" self.target_field_schema: Optional[Dict[str, Any]] = None + self.json_schema_validator = json_schema_validator + self.original_value_at_path: Any = None + self.mismatched_value: Any = None + self._try_find_mismatch_target_in_body() + def _try_find_mismatch_target_in_body(self): self.logger.critical(f"{self.id} __INIT__ >>> STARTED") self.logger.debug(f"开始为端点 {self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')} 初始化请求体类型不匹配测试的目标字段查找。") @@ -64,58 +69,8 @@ class TypeMismatchBodyCase(BaseAPITestCase): self.logger.info(f"最终,在端点 {self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')} 的请求体中,均未找到可用于测试类型不匹配的字段。") def _resolve_ref_if_present(self, schema_to_resolve: Dict[str, Any]) -> Dict[str, Any]: - ref_value = None - if isinstance(schema_to_resolve, dict): - if "$ref" in schema_to_resolve: - ref_value = schema_to_resolve["$ref"] - elif "$$ref" in schema_to_resolve: - ref_value = schema_to_resolve["$$ref"] - - if ref_value: - self.logger.debug(f"发现引用 '{ref_value}',尝试解析...") - try: - actual_global_spec_dict = None - if hasattr(self.global_api_spec, 'spec') and isinstance(self.global_api_spec.spec, dict): - actual_global_spec_dict = self.global_api_spec.spec - elif isinstance(self.global_api_spec, dict): - actual_global_spec_dict = self.global_api_spec - - if not actual_global_spec_dict: - self.logger.warning(f"无法从 self.global_api_spec (类型: {type(self.global_api_spec)}) 获取用于解析引用的字典。") - return schema_to_resolve - - resolved_schema = None - if ref_value.startswith("#/components/schemas/"): - schema_name = ref_value.split("/")[-1] - components = actual_global_spec_dict.get("components") - if components and isinstance(components.get("schemas"), dict): - resolved_schema = components["schemas"].get(schema_name) - if resolved_schema and isinstance(resolved_schema, dict): - self.logger.info(f"成功从 #/components/schemas/ 解析引用 '{ref_value}'。") - return resolved_schema - else: - self.logger.warning(f"解析引用 '{ref_value}' (路径: #/components/schemas/) 失败:未找到或找到的不是字典: {schema_name}") - else: - self.logger.warning(f"尝试从 #/components/schemas/ 解析引用 '{ref_value}' 失败:无法找到 'components.schemas' 结构。") - - if not resolved_schema and ref_value.startswith("#/definitions/"): - schema_name = ref_value.split("/")[-1] - definitions = actual_global_spec_dict.get("definitions") - if definitions and isinstance(definitions, dict): - resolved_schema = definitions.get(schema_name) - if resolved_schema and isinstance(resolved_schema, dict): - self.logger.info(f"成功从 #/definitions/ 解析引用 '{ref_value}'。") - return resolved_schema - else: - self.logger.warning(f"解析引用 '{ref_value}' (路径: #/definitions/) 失败:未找到或找到的不是字典: {schema_name}") - else: - self.logger.warning(f"尝试从 #/definitions/ 解析引用 '{ref_value}' 失败:无法找到 'definitions' 结构。") - - if not resolved_schema: - self.logger.warning(f"最终未能通过任一已知路径 (#/components/schemas/ 或 #/definitions/) 解析引用 '{ref_value}'。") - - except Exception as e: - self.logger.error(f"解析引用 '{ref_value}' 时发生错误: {e}", exc_info=True) + # 根据用户进一步要求,方法体简化为直接返回,不进行任何 $ref/$ $$ref 的检查。 + # self.logger.debug(f"_resolve_ref_if_present called. Returning schema as-is per new configuration.") return schema_to_resolve def _find_target_field_in_schema(self, schema_to_search: Dict[str, Any], base_path_for_log: str) -> bool: diff --git a/custom_testcases/compliance_catalog/error_handling/type_mismatch_query_param_case.py b/custom_testcases/compliance_catalog/error_handling/type_mismatch_query_param_case.py index c3d1d15..cb40e54 100644 --- a/custom_testcases/compliance_catalog/error_handling/type_mismatch_query_param_case.py +++ b/custom_testcases/compliance_catalog/error_handling/type_mismatch_query_param_case.py @@ -11,14 +11,19 @@ class TypeMismatchQueryParamCase(BaseAPITestCase): tags = ["error-handling", "appendix-b", "4001", "query-parameters"] execution_order = 201 # Slightly after the combined one might have been - def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None): - super().__init__(endpoint_spec, global_api_spec, json_schema_validator) + def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[Any] = None): + super().__init__(endpoint_spec, global_api_spec, json_schema_validator, llm_service=llm_service) self.logger.setLevel(logging.DEBUG) self.target_field_path: Optional[List[str]] = None self.original_field_type: Optional[str] = None # Location is always 'query' for this class self.target_field_location: str = "query" self.target_field_schema: Optional[Dict[str, Any]] = None + self.original_value_at_path: Any = None + self.mismatched_value: Any = None + + # 调用新方法来查找目标字段 + self._try_find_mismatch_target_in_query() self.logger.critical(f"{self.id} __INIT__ >>> STARTED") self.logger.debug(f"开始为端点 {self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')} 初始化查询参数类型不匹配测试的目标字段查找。") @@ -78,59 +83,63 @@ class TypeMismatchQueryParamCase(BaseAPITestCase): if not self.target_field_path: self.logger.info(f"最终,在端点 {self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')} 的查询参数中,均未找到可用于测试类型不匹配的字段。") + def _try_find_mismatch_target_in_query(self): + self.logger.critical(f"{self.id} _try_find_mismatch_target_in_query >>> STARTED") + self.logger.debug(f"开始为端点 {self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')} 初始化查询参数类型不匹配测试的目标字段查找。") + + parameters = self.endpoint_spec.get("parameters", []) + self.logger.critical(f"{self.id} _try_find_mismatch_target_in_query >>> Parameters to be processed: {parameters}") + self.logger.debug(f"传入的参数列表 (在 {self.id}中): {parameters}") + + for param_spec in parameters: + if param_spec.get("in") == "query": + param_name = param_spec.get("name") + if not param_name: + self.logger.warning("发现一个没有名称的查询参数定义,已跳过。") + continue + + self.logger.debug(f"检查查询参数: '{param_name}'") + + param_type = param_spec.get("type") + param_schema = param_spec.get("schema") + + # Scenario 1: Simple type directly in param_spec (e.g., type: string) + if param_type in ["string", "number", "integer", "boolean"]: + self.target_field_path = [param_name] + self.original_field_type = param_type + self.target_field_schema = param_spec + self.logger.info(f"目标字段(查询参数 - 简单类型): {param_name},原始类型: {self.original_field_type}") + break + # Scenario 2: Schema defined for the query parameter (OpenAPI 3.0 style, or complex objects in query) + elif isinstance(param_schema, dict): + self.logger.debug(f"查询参数 '{param_name}' 包含嵌套 schema,尝试在其内部查找简单类型字段。") + resolved_param_schema = self._resolve_ref_if_present(param_schema) + if resolved_param_schema.get("type") == "object": + properties = resolved_param_schema.get("properties", {}) + for prop_name, prop_details_orig in properties.items(): + prop_details = self._resolve_ref_if_present(prop_details_orig) + if prop_details.get("type") in ["string", "number", "integer", "boolean"]: + self.target_field_path = [param_name, prop_name] + self.original_field_type = prop_details.get("type") + self.target_field_schema = prop_details + self.logger.info(f"目标字段(查询参数 - 对象属性): {param_name}.{prop_name},原始类型: {self.original_field_type}") + break + if self.target_field_path: break + elif resolved_param_schema.get("type") in ["string", "number", "integer", "boolean"]: + self.target_field_path = [param_name] + self.original_field_type = resolved_param_schema.get("type") + self.target_field_schema = resolved_param_schema + self.logger.info(f"目标字段(查询参数 - schema为简单类型): {param_name},原始类型: {self.original_field_type}") + break + else: + self.logger.debug(f"查询参数 '{param_name}' (type: {param_type}, schema: {param_schema}) 不是直接的简单类型,也无直接可用的对象型 schema 属性。") + + if not self.target_field_path: + self.logger.info(f"最终,在端点 {self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')} 的查询参数中,均未找到可用于测试类型不匹配的字段。") + def _resolve_ref_if_present(self, schema_to_resolve: Dict[str, Any]) -> Dict[str, Any]: - ref_value = None - if isinstance(schema_to_resolve, dict): - if "$ref" in schema_to_resolve: - ref_value = schema_to_resolve["$ref"] - elif "$$ref" in schema_to_resolve: - ref_value = schema_to_resolve["$$ref"] - - if ref_value: - self.logger.debug(f"发现引用 '{ref_value}',尝试解析...") - try: - actual_global_spec_dict = None - if hasattr(self.global_api_spec, 'spec') and isinstance(self.global_api_spec.spec, dict): - actual_global_spec_dict = self.global_api_spec.spec - elif isinstance(self.global_api_spec, dict): - actual_global_spec_dict = self.global_api_spec - - if not actual_global_spec_dict: - self.logger.warning(f"无法从 self.global_api_spec (类型: {type(self.global_api_spec)}) 获取用于解析引用的字典。") - return schema_to_resolve - - resolved_schema = None - if ref_value.startswith("#/components/schemas/"): - schema_name = ref_value.split("/")[-1] - components = actual_global_spec_dict.get("components") - if components and isinstance(components.get("schemas"), dict): - resolved_schema = components["schemas"].get(schema_name) - if resolved_schema and isinstance(resolved_schema, dict): - self.logger.info(f"成功从 #/components/schemas/ 解析引用 '{ref_value}'。") - return resolved_schema - else: - self.logger.warning(f"解析引用 '{ref_value}' (路径: #/components/schemas/) 失败:未找到或找到的不是字典: {schema_name}") - else: - self.logger.warning(f"尝试从 #/components/schemas/ 解析引用 '{ref_value}' 失败:无法找到 'components.schemas' 结构。") - - if not resolved_schema and ref_value.startswith("#/definitions/"): - schema_name = ref_value.split("/")[-1] - definitions = actual_global_spec_dict.get("definitions") - if definitions and isinstance(definitions, dict): - resolved_schema = definitions.get(schema_name) - if resolved_schema and isinstance(resolved_schema, dict): - self.logger.info(f"成功从 #/definitions/ 解析引用 '{ref_value}'。") - return resolved_schema - else: - self.logger.warning(f"解析引用 '{ref_value}' (路径: #/definitions/) 失败:未找到或找到的不是字典: {schema_name}") - else: - self.logger.warning(f"尝试从 #/definitions/ 解析引用 '{ref_value}' 失败:无法找到 'definitions' 结构。") - - if not resolved_schema: - self.logger.warning(f"最终未能通过任一已知路径 (#/components/schemas/ 或 #/definitions/) 解析引用 '{ref_value}'。") - - except Exception as e: - self.logger.error(f"解析引用 '{ref_value}' 时发生错误: {e}", exc_info=True) + # 根据用户进一步要求,方法体简化为直接返回,不进行任何 $ref/$ $$ref 的检查。 + # self.logger.debug(f"_resolve_ref_if_present called. Returning schema as-is per new configuration.") return schema_to_resolve # No generate_request_body, or it simply returns current_body diff --git a/custom_testcases/compliance_catalog/normative_spec/__pycache__/url_llm_checks.cpython-312.pyc b/custom_testcases/compliance_catalog/normative_spec/__pycache__/url_llm_checks.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..28c75285e34b141533ed740f4dfe50d8b4055f69 GIT binary patch literal 11836 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 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 + + # 如果没有明确注入,我们只能依赖全局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 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 + + 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 '请你自己从路径模板中提取'} + + # 构建给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}] + +评估标准: + +1. **接口名称规范 (接口名称需要你从路径模板中提取,一般是路径中除了参数名以外的最后的一个单词)**: + - 规则: 采用'动词+名词'结构,明确业务语义 (例如: GetWellLog, SubmitSeismicJob)。 + - standard_name: "interface_naming_convention" + +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" + +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" + + + +请确保您的输出是一个可以被 `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" + + messages = [ + {"role": "system", "content": "你是一位API设计评审专家,专注于评估API的URL规范性和RESTful风格。你的输出必须是严格的JSON格式。"}, + {"role": "user", "content": prompt_instruction} + ] + + 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 # 低温以获得更确定的、结构化的输出 + ) + + 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.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) + + 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 + + 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} + )) + + + 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 + + diff --git a/custom_testcases/compliance_catalog/security/__pycache__/https_mandatory_case.cpython-312.pyc b/custom_testcases/compliance_catalog/security/__pycache__/https_mandatory_case.cpython-312.pyc index f888250b9c0bb1d6eaf9b41165215f26a5636955..3829bdacc7a1ca8083a5992da08859261625471d 100644 GIT binary patch delta 830 zcmYjP&r4KM6u$TU9%tUnIAc2FWI9&rq=BJgQxO)mC_*SBX_OwrygMp9M>%h%GzM%T zp^FxEi-c&=CJLp^Ks*0|+8DHmNrPI3gyANNsC%9Y9(dn9-*?V=_i)aA-20{1d~cdH zMA*$__xSol^Iwg}gs{EB>*)Zk<-@e?vh8C*X2yk_Hx@{q+BNfLCS?0rzz(oLUa`%2 zB@?!Ttkw>(h|r>}&db*9u!tO3ATu;mKSWZI$|{Z1OI5$)Oj<63+Y>pKQ?Y?v!|P@7 zZT}GPggzz3-2fqrYMDF`xn)|G%5qs*q00&n%004FCXdVpD)Ujf(^Qt}PQ^1~tEe2+ z_9^;veUDKxOH#&Qib9S;(;6Mk`<4Cpa^fW8ja2|CGjQRM zmz&Q{ILwA_FIOZ^0r=1l6xmGC%1srDtWZqpJFWK;F*NAIxDL!MIYk%Jd@~x0oD!O= z3uxIfNLK3W-pG2ZkW$hhf7j4KoA`Fa$PkVcdJy~w_#OZU?p+I4gjY3pSCM0mV_9N> zEkbp1?E{b$2<9H(%W~iH7qLuYi%9AXX^W6+QU;F^>6Y{pnI-W*v5T~opNr2Xy~$zu bYXaDt_rKr9naL@;rTvp6a~BLLcmhdEfVwnf+OLRdK#KP7l-8 zzdpY9{-tx$6C+RC@dq^kbI_}nVPwv?_n8kozUNd^yhkK?LL_~YC-=;1FLy+mpA#9a zWkp|Jm-;qO=}7-Rdji#gCFZ8vUm*|Eb+gmC3z}-^@A$XIYk0#NU0w5;*eiuFUfbB9jdQY7gtr06Ur3idX z>tf6hvKnFB^XfrOO3#yeEK{FM33)YWmEozHxB87AvBkD$eT>YEQnnRr?FbBG9*XUt zRu`eYDjH1;us{t5DJ8m7!_D>0RoBEzBo3?D*eDd0A3K6l`%e6q1tV%K^#{uBTrU7j zwF~KGfN6!9x0;FUWqXS1Zm7xZgNM^}bO~1pV;Z4B18E(+My_4k-WHo2=gF~}+QGBy ztce;IDDh$^*RQPyg5$V4$`)^R_M4za6$(aC$Y#)xNJGO6ipNbM8=ju#$@-eu5ICa) zGOAJR8W!8P`@R@CC zRnpVWVNnyEQ_#D}1NA*uRSWqAD5>Z9-BRaHDCILl8sDi2V>dUpcry^QxT4C1Ns}V~ E0OJX$IsgCw diff --git a/custom_testcases/compliance_catalog/security/https_mandatory_case.py b/custom_testcases/compliance_catalog/security/https_mandatory_case.py index de1c4c1..4b712cd 100644 --- a/custom_testcases/compliance_catalog/security/https_mandatory_case.py +++ b/custom_testcases/compliance_catalog/security/https_mandatory_case.py @@ -12,8 +12,8 @@ class HTTPSMandatoryCase(BaseAPITestCase): # 此测试会修改URL为HTTP,应适用于大多数端点。 - def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None): - super().__init__(endpoint_spec, global_api_spec, json_schema_validator) + def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[Any] = None): + super().__init__(endpoint_spec, global_api_spec, json_schema_validator, llm_service=llm_service) self.logger.info(f"测试用例 '{self.id}' 已为端点 '{self.endpoint_spec.get('method')} {self.endpoint_spec.get('path')}' 初始化。") def modify_request_url(self, current_url: str) -> str: diff --git a/ddms_compliance_suite/__pycache__/test_framework_core.cpython-312.pyc b/ddms_compliance_suite/__pycache__/test_framework_core.cpython-312.pyc index ce81c559edd7f4ee74f1e7e90f444e5ba0a0accb..d65d9fe656dd5097a264a00e3549ebebb8965f94 100644 GIT binary patch delta 2314 zcmah|UrbY19KPqax4r#C3kVcwX>SV@3KS5iu)&y{=nO*;a4v$vO3y8nm7=#rC$!cX zHd(Sw&54^%jqJ|@1`{{Q7P1GY^TlP!b_;Bf&Ly}f_g3}AnLX^B*0QQBJ4wHD&iDJy z_xs&n&siRPcUbddTAGr=BU@EB^s?b zxmlPy$@JvIJU*9a_&hgFSeT!>b4#IqQre@3hB(VSp?SQ+ngXmbKx5Jwdn9v6p$W$d zAjdP9W!zyYG-JXDEtn|eO_)sMxp+A;ScD^HSo}n)r!`irvA~jKf@eHRal8=P_@ZYb zWjInCUN=;ZLskU^9k7DWgZ9)8z{+^#$s$=;g?m=Qm%>f38b>zbLQ=Z-xPzQq25Tmn zS@L(_(PLZFm;d*H+LQxjhn2Saxnr4s0Buy|^^WxWdEubP#k&|3lV^c;G?8_Lkp`)L zIf`YO(249URG3`@HlRC(4ak#ieZ2ZS+X&|7zRz|7Er&;n5n9UOlx=N0x)Z)gu7f~{ zyt?WdVHd7A%0PZ#Y%nSr8XG@tj#uqF`dh}4lHb)lc~w}3H}slT7Q zCW}e~hxhYIw?XW-100?kHaq}n&XluWG;DkY96?u&*MJipFzo{$pr1`Kz@zIN4^APg z`8VJ}w51=MMgx}Lb!+}Y19rJ2NfbMVG?pCXEp&iS&}W5W`oF41QtTmgtY{m!h<+$K zx`D-n1pgisVf>gHq(V~kwmAn0#Y=r5CddqHaPX-iv<4;TC@8%^hh!cqB*&`srzChQ zXxHb1a>z8{IO?+6!?K`Upo4NBfU?W-Svuh|3lcM+g3@jZvLO~bWhS^(6sn*CDu=UE zxx{*XeG7F$;i3mA7rjqTQ6U9Xg@cN7)CKw!{k}qq>5w9sdK~-UwB$3@K^AKyA?5m} z0bMeE5F}4S8BEKkpyoXNKg}Ue@5!;&otY9lqYTO~Yth4!m(1xwB`G4AAki5Y4dO)~ zqHGy+J4;*W%~7r2HN=lN`wuw8TI`Z%}K8^dhUEh^*VC!*5fQIAisVq=>sapflP zS_l#dVTj5F-aqCI_@n6u6M094{se_f9CNvNzrTM3gL9CNYF%T3!21IIkPqO>{84p0 z3)VaRqrND}=A&x&nAe*;;8)=c9J*KDEBgYk{8v#|MPE23qYT`#-VxC|mi5gMeY5yt zhuAr=sCS8M?y5?^tghpO?tvRxamah7aZx|Ar1r(isC3_Yv(qTLlSxlXEAjdfyy zLv-|tdxykckEkD>YQx`QsaZBRM9dAhZ55*Zg+*KQeBio7w6)x0Bqq&NM~tP?xu;9c zU$5qs+@h7-5;SXX$o%WRnQCwWzYKTmX1#h_niAc$cY{gPR9OLTBTwZUy3;r$Op=b0 zcgS%9x!J;Tv|6bLchKLJ#ta+XjxSVH+Tsj21tX54lB$ow14QN~@FoEtfl>nGb_@Fn z2m}HI>Iu9>fIKk)VTh{z0emrCBYa?J6bku-KTd!=Y$1n0ypk4A#u_oEMMz6N_xOKrLO5!*B}3dg*Bvv3|w)V`Y0OM{)@K2D0K_~-otw601T delta 1972 zcmZuxZA?>F7{2GWw_lXDK(Q?sN(=o2%7;+Kz@aEAi^6mzb3^$koJ)a0nfDeAScWmW zu*`|eNfwMFvc*K4`!UmfnPtxHm&wd>8!#o^mgu%@`?o4T^w+X;S_;MOBz?{~@AJIx z``ouT_pOmwK=VU(wu-{5W63jA>bR-VDnUGAR(>G^OX$A#FHnna>l`zKGH5uI? zM&mL}Ig}KvgXNqFR%A{9dXmo5CKa#}&& zhtpI-ho+77k*|$qAh(N%j$&}rsnl-t#MCYu#}UDX{1!dxDR@}8q2lX^-kYKCM@QK` zKtNa6$Hom=TpF5ugG-kjMAr-3!AVqQGevYoagg1Yk^ee+V%`tJXlL(e(1}wTRN!bsf-%1aFdE86XZ7Q0u zf%R@OShN8lAXN(HT3j2P4D8%A3zN~x~ z%B`rGQ4I^jK_TQ14sfY=?g%!;vjiL%;?j}v;hef6hH)8}>=xG~_ujFT7a`6h?{W3u#OUZo6n|I&g<=&)Wgp>k!Ufde>6v-J7ROj` zl=a5g<|x}N?tDo++`r5YL>0za#YM-%th`lq-dxAq9rJZpnl3eoWxGUoi`dd5I(wJd zz7@4UVWxD3Sxtha%$C`XpS7lW$5q>k*7;LW>BYUP`jVL59o4&+Ui=Jx<^8ttR^xL0 zKGD1XPFU=GE!OFuiFW!$U%yy3a9b*xSO6mxW)0R(Y9LFu;P0~JQ7&; z4T-~J;>eij3r3CO35G&9E4>WA4bKBTt@MF2=wMX^xQ8aI`V8-p!Ji?MA}_wh!W&57 z97%xYV4GlZb+{+7e1~Qc)_6s4+*C u#cNsQ-if}c{T#fCgt~HdT(M(p98QdK&HOz2xb8sC0U8_vkE!IA9NNF|G5AgZ diff --git a/ddms_compliance_suite/__pycache__/test_orchestrator.cpython-312.pyc b/ddms_compliance_suite/__pycache__/test_orchestrator.cpython-312.pyc index 0d61f76d6cd616d270a48acbf8cedc13c282f59d..75af1df56c5c835b8cc2cc0f06aa0d57c8c033e7 100644 GIT binary patch delta 7993 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 diff --git a/ddms_compliance_suite/input_parser/__pycache__/parser.cpython-312.pyc b/ddms_compliance_suite/input_parser/__pycache__/parser.cpython-312.pyc index 90971a8aba8a231044fba2d3ab279f5c261c0be3..125db7937b07bb3512ad777c4c0d19806a7e91bb 100644 GIT binary patch literal 26570 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

dHbY@UygO z-AwKMV*Bk=Z=9OC^yV3`mPv@wM8{%y5Oq0DkIvwUj9bX92GPI2AN z*_PnCwqWMoac$VLCS)lA--l`4T&}EK?h3YD5c-G2(n|{#{z36NNo_rSd4>-b?*JQi zDh%(y{p{k&!FP@>WP=Mq&Mm`DL&#Pk+A4(VF5yDI&;_o-?gbCO2rh15pMOMALy}4w zb()abB1J=zO4I(&&M^!4LP zDyJAOR|4qDz|o6Zs5~Yd?+zXB6_0~&@}S`H1&|i=EI>U6~1e=))_-ng#jZrrg@@7!qAsjm|oCjf^6D~M~ zydL4wuwcv$87~XQ%VBdG_*!GTCte=jz#pZw8mV{EcNeNYNZts^pD;ViA^KU>n%!&F z9~#pk{b8YIcU97dWjai+)wk-CKHS`_ZB-}ze47Tc=F}R4AmT_bbeJY#MUUoc=P+ z)7LZO`bWY8^tonX%B_4+3PfHne^E)m!!n=;MGJ8iKmf#eO|DOZv~)m3dw_>vY?=f zXgTKqTuwtOboWJ)JcNA%lL%hx0{5o!aQTOwCPy;;g%Ud&HFzUKDi2QPw%~Xd&HCYl z7pW<8!7|f(7-#iMoK>#eFvh~h^Su>PM+x}er`z%WhyXYJ5xnmb7*Y0@{}jje83vm% z_#A`pVeownS};J=Nsb1@KjCHkIfTJ)FhH{w(O2?cU}`y^%cD1J#ORfDwhnSN&@wic z96S48*cdn%>4ba4gzHA!bRDp^#H1N9p?fm9SqJkX78$0z2*@x|&t`5{N&KtalJK{A zPxH6&<$r@LZYPs~#f2LiW-bbudlz*3!Zo$P;#Sp+8N(YJ35(0>{mWQf23g!sm$JAT z$b5_!LnLHzg`)cDk?D&<^Po`RUa)wO$IY$^W!H+?wQ$2kK`?tOT>N1z30ccUYx&g1 z=^a7q#<5)wN-J-_@Wu;ojy|M}rafS2FC15o55`#H8C|%lAyl9!E=|dIP{7|QXoDWSZOj}A@%T*t4UIpRL z4f%U&RX?vaVtQ*~Yq4ssSOe*Hdt&PsGC`7*i`pR~(DL9{5q-%)pGNWcg_TTG7EFcY z;7{;fL8U+1zIH!kXwAAstzBcCO2bG6Tb6iIy5qtVb{m4V=KikdDSKl_-1 Z=&?~vXHJ+fo%xmVI89q0QWz3+{BPpi*46+3 literal 14772 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 Dict[str, Any]: + # 基类可以提供一个默认的 to_dict 实现或要求子类实现 + raise NotImplementedError("Subclasses must implement to_dict") -@dataclass -class ParsedYAPISpec: +class YAPIEndpoint(BaseEndpoint): # Inherit from BaseEndpoint + def __init__(self, data: Dict[str, Any], category_name: Optional[str] = None, category_id: Optional[int] = None): + super().__init__(method=data.get("method", "GET").upper(), path=data.get("path", "")) + self._raw_data = data + self.title: str = data.get("title", "") + self.desc: Optional[str] = data.get("desc") + self._id: int = data.get("_id") + self.project_id: int = data.get("project_id") + self.catid: int = data.get("catid") + + self.req_params: List[Dict[str, Any]] = data.get("req_params", []) + self.req_query: List[Dict[str, Any]] = data.get("req_query", []) + self.req_headers: List[Dict[str, Any]] = data.get("req_headers", []) + self.req_body_form: List[Dict[str, Any]] = data.get("req_body_form", []) + + self.req_body_type: Optional[str] = data.get("req_body_type") + self.req_body_is_json_schema: bool = data.get("req_body_is_json_schema", False) + self.req_body_other: Optional[str] = data.get("req_body_other") + + self.res_body_type: Optional[str] = data.get("res_body_type") + self.res_body_is_json_schema: bool = data.get("res_body_is_json_schema", False) + self.res_body: Optional[str] = data.get("res_body") + + self.status: str = data.get("status", "undone") + self.api_opened: bool = data.get("api_opened", False) + self.uid: int = data.get("uid") + + self.category_name = category_name + self.category_id = category_id if category_id is not None else self.catid + + self._parsed_req_body_schema: Optional[Dict[str, Any]] = None + if self.req_body_type == "json" and self.req_body_other and self.req_body_is_json_schema: + try: + self._parsed_req_body_schema = json.loads(self.req_body_other) + except json.JSONDecodeError as e: + logger.error(f"YAPIEndpoint (ID: {self._id}, Title: {self.title}): Failed to parse req_body_other as JSON during init: {e}. Content: {self.req_body_other[:200]}") + + self._parsed_res_body_schema: Optional[Dict[str, Any]] = None + if self.res_body_type == "json" and self.res_body and self.res_body_is_json_schema: + try: + self._parsed_res_body_schema = json.loads(self.res_body) + except json.JSONDecodeError as e: + logger.error(f"YAPIEndpoint (ID: {self._id}, Title: {self.title}): Failed to parse res_body as JSON during init: {e}. Content: {self.res_body[:200]}") + + def to_dict(self) -> Dict[str, Any]: + endpoint_dict = { + "method": self.method, + "path": self.path, + "title": self.title, + "summary": self.title, + "description": self.desc or "", + "operationId": f"{self.method.lower()}_{self.path.replace('/', '_').replace('{', '').replace('}', '')}_{self._id}", + "tags": [self.category_name or str(self.catid)], + "parameters": [], + "requestBody": None, + "responses": {}, + "_source_format": "yapi", + "_yapi_id": self._id, + "_yapi_raw_data": self._raw_data # Keep raw data for debugging or deeper inspection if needed + } + + # Path parameters from req_params + for p_spec in self.req_params: + param_name = p_spec.get("name") + if not param_name: continue + endpoint_dict["parameters"].append({ + "name": param_name, + "in": "path", + "required": True, # Path parameters are always required + "description": p_spec.get("desc", ""), + "schema": {"type": "string", "example": p_spec.get("example", f"example_{param_name}")} + }) + + # Query parameters from req_query + for q_spec in self.req_query: + param_name = q_spec.get("name") + if not param_name: continue + is_required = q_spec.get("required") == "1" # YAPI uses "1" for true + param_schema = {"type": "string"} # Default to string, YAPI doesn't specify types well here + if "example" in q_spec: param_schema["example"] = q_spec["example"] + # Add other fields from YAPI query spec if needed (e.g., desc) + endpoint_dict["parameters"].append({ + "name": param_name, + "in": "query", + "required": is_required, + "description": q_spec.get("desc", ""), + "schema": param_schema + }) + + # Header parameters from req_headers + for h_spec in self.req_headers: + param_name = h_spec.get("name") + if not param_name or param_name.lower() == 'content-type': continue # Content-Type is handled by requestBody + is_required = h_spec.get("required") == "1" + default_value = h_spec.get("value") # YAPI uses 'value' for default/example header value + param_schema = {"type": "string"} + if default_value: + if is_required: # If required, it's more like an example of what's expected + param_schema["example"] = default_value + else: # If not required, it's a default value + param_schema["default"] = default_value + + endpoint_dict["parameters"].append({ + "name": param_name, + "in": "header", + "required": is_required, + "description": h_spec.get("desc", ""), + "schema": param_schema + }) + + # Request body + if self.req_body_type == "json" and self._parsed_req_body_schema: + endpoint_dict["requestBody"] = { + "content": { + "application/json": { + "schema": self._parsed_req_body_schema + } + } + } + elif self.req_body_type == "form" and self.req_body_form: + properties = {} + required_form_params = [] + for form_param in self.req_body_form: + name = form_param.get("name") + if not name: continue + properties[name] = { + "type": "string", # YAPI form params are typically strings, file uploads are different + "description": form_param.get("desc","") + } + if form_param.get("example"): properties[name]["example"] = form_param.get("example") + if form_param.get("required") == "1": required_form_params.append(name) + + endpoint_dict["requestBody"] = { + "content": { + "application/x-www-form-urlencoded": { + "schema": { + "type": "object", + "properties": properties, + "required": required_form_params if required_form_params else None # OpenAPI: omit if empty + } + } + # YAPI also supports req_body_type = 'file', which would map to multipart/form-data + # This example focuses on json and basic form. + } + } + # Add other req_body_types if necessary (e.g., raw, file) + + # Responses + # YAPI has a simpler response structure. We'll map its res_body to a default success response (e.g., 200 or 201). + default_success_status = "200" + if self.method == "POST": default_success_status = "201" # Common practice for POST success + + if self.res_body_type == "json" and self._parsed_res_body_schema: + endpoint_dict["responses"][default_success_status] = { + "description": "Successful Operation (from YAPI res_body)", + "content": { + "application/json": { + "schema": self._parsed_res_body_schema + } + } + } + elif self.res_body_type == "json" and not self._parsed_res_body_schema and self.res_body: # Schema parsing failed but text exists + endpoint_dict["responses"][default_success_status] = { + "description": "Successful Operation (Schema parsing error, raw text might be available)", + "content": {"application/json": {"schema": {"type": "object", "description": "Schema parsing failed for YAPI res_body."}}} # Placeholder + } + else: # No JSON schema, or other res_body_type + endpoint_dict["responses"][default_success_status] = { + "description": "Successful Operation (No specific schema provided in YAPI for this response)" + } + + # Ensure there's always a default response if nothing specific was added + if not endpoint_dict["responses"]: + endpoint_dict["responses"]["default"] = {"description": "Default response from YAPI definition"} + + return endpoint_dict + + def __repr__(self): + return f"" + +class SwaggerEndpoint(BaseEndpoint): # Inherit from BaseEndpoint + def __init__(self, path: str, method: str, data: Dict[str, Any], global_spec: Dict[str, Any]): + super().__init__(method=method.upper(), path=path) + self._raw_data = data + self._global_spec = global_spec # Store for $ref resolution + self.summary: Optional[str] = data.get("summary") + self.description: Optional[str] = data.get("description") + self.operation_id: Optional[str] = data.get("operationId") + self.tags: List[str] = data.get("tags", []) + # Parameters, requestBody, responses are processed by to_dict + + def _resolve_ref(self, ref_path: str) -> Optional[Dict[str, Any]]: + """Resolves a $ref path within the global OpenAPI/Swagger spec.""" + if not ref_path.startswith("#/"): + logger.warning(f"Unsupported $ref path: {ref_path}. Only local refs '#/...' are currently supported.") + return None + + parts = ref_path[2:].split('/') # Remove '#/' and split + current_level = self._global_spec + try: + for part in parts: + # Decode URI component encoding if present (e.g. "~0" for "~", "~1" for "/") + part = part.replace("~1", "/").replace("~0", "~") + current_level = current_level[part] + # It's crucial to return a copy if the resolved ref will be modified, + # or ensure modifications happen on copies later. + # For now, returning as is, assuming downstream processing is careful or uses copies. + if isinstance(current_level, dict): + return current_level # Potentially json.loads(json.dumps(current_level)) for a deep copy + else: # Resolved to a non-dict, which might be valid for some simple refs but unusual for schemas + logger.warning(f"$ref '{ref_path}' resolved to a non-dictionary type: {type(current_level)}. Value: {str(current_level)[:100]}") + return {"type": "string", "description": f"Resolved $ref '{ref_path}' to non-dict: {str(current_level)[:100]}"} # Placeholder + except (KeyError, TypeError, AttributeError) as e: + logger.error(f"Failed to resolve $ref '{ref_path}': {e}", exc_info=True) + return None + + def _process_schema_or_ref(self, schema_like: Any) -> Optional[Dict[str, Any]]: + """ + Processes a schema part, resolving $refs and recursively processing nested structures. + Returns a new dictionary with resolved refs, or None if resolution fails badly. + """ + if not isinstance(schema_like, dict): + if schema_like is None: return None + logger.warning(f"Expected a dictionary for schema processing, got {type(schema_like)}. Value: {str(schema_like)[:100]}") + return {"type": "string", "description": f"Schema was not a dict: {str(schema_like)[:100]}"} # Placeholder for non-dict schema + + # If it's a $ref, resolve it. + if "$ref" in schema_like: + return self._resolve_ref(schema_like["$ref"]) # This will be the new base schema_like + + # Create a copy to avoid modifying the original spec during processing + processed_schema = schema_like.copy() + + # Recursively process 'properties' for object schemas + if "properties" in processed_schema and isinstance(processed_schema["properties"], dict): + new_properties = {} + for prop_name, prop_schema in processed_schema["properties"].items(): + resolved_prop = self._process_schema_or_ref(prop_schema) + if resolved_prop is not None: # Only add if resolution was successful + new_properties[prop_name] = resolved_prop + # else: logger.warning(f"Failed to process property '{prop_name}' in {self.operation_id or self.path}") + processed_schema["properties"] = new_properties + + # Recursively process 'items' for array schemas + if "items" in processed_schema and isinstance(processed_schema["items"], dict): # 'items' should be a schema object + resolved_items = self._process_schema_or_ref(processed_schema["items"]) + if resolved_items is not None: + processed_schema["items"] = resolved_items + # else: logger.warning(f"Failed to process 'items' schema in {self.operation_id or self.path}") + + # Handle allOf, anyOf, oneOf by trying to merge or process them (simplistic merge for allOf) + # This is a complex area of JSON Schema. This is a very basic attempt. + if "allOf" in processed_schema and isinstance(processed_schema["allOf"], list): + merged_all_of_props = {} + merged_all_of_required = set() + temp_schema_for_all_of = {"type": processed_schema.get("type", "object"), "properties": {}, "required": []} + + for sub_schema_data in processed_schema["allOf"]: + resolved_sub_schema = self._process_schema_or_ref(sub_schema_data) + if resolved_sub_schema and isinstance(resolved_sub_schema, dict): + if "properties" in resolved_sub_schema: + temp_schema_for_all_of["properties"].update(resolved_sub_schema["properties"]) + if "required" in resolved_sub_schema and isinstance(resolved_sub_schema["required"], list): + merged_all_of_required.update(resolved_sub_schema["required"]) + # Copy other top-level keywords from the resolved_sub_schema if needed, e.g. description + for key, value in resolved_sub_schema.items(): + if key not in ["properties", "required", "type", "$ref", "allOf", "anyOf", "oneOf"]: + if key not in temp_schema_for_all_of or temp_schema_for_all_of[key] is None: # prioritize existing + temp_schema_for_all_of[key] = value + + if temp_schema_for_all_of["properties"]: + processed_schema["properties"] = {**processed_schema.get("properties",{}), **temp_schema_for_all_of["properties"]} + if merged_all_of_required: + current_required = set(processed_schema.get("required", [])) + current_required.update(merged_all_of_required) + processed_schema["required"] = sorted(list(current_required)) + del processed_schema["allOf"] # Remove allOf after processing + # Copy other merged attributes back to processed_schema + for key, value in temp_schema_for_all_of.items(): + if key not in ["properties", "required", "type", "$ref", "allOf", "anyOf", "oneOf"]: + if key not in processed_schema or processed_schema[key] is None: + processed_schema[key] = value + + + # anyOf, oneOf are harder as they represent choices. For now, we might just list them or pick first. + # For simplicity in to_dict, we might not fully expand them but ensure refs inside are resolved. + for keyword in ["anyOf", "oneOf"]: + if keyword in processed_schema and isinstance(processed_schema[keyword], list): + processed_sub_list = [] + for sub_item in processed_schema[keyword]: + resolved_sub = self._process_schema_or_ref(sub_item) + if resolved_sub: + processed_sub_list.append(resolved_sub) + if processed_sub_list: # only update if some were resolved + processed_schema[keyword] = processed_sub_list + + return processed_schema + + def to_dict(self) -> Dict[str, Any]: + endpoint_data = { + "method": self.method, + "path": self.path, + "summary": self.summary or "", + "title": self.summary or self.operation_id or "", # Fallback for title + "description": self.description or "", + "operationId": self.operation_id or f"{self.method.lower()}_{self.path.replace('/', '_').replace('{', '').replace('}', '')}", + "tags": self.tags, + "parameters": [], + "requestBody": None, + "responses": {}, + "_source_format": "swagger/openapi", + "_swagger_raw_data": self._raw_data, # Keep raw for debugging + "_global_api_spec_for_resolution": self._global_spec # For test cases that might need to resolve further + } + + # Process parameters + if "parameters" in self._raw_data and isinstance(self._raw_data["parameters"], list): + for param_data_raw in self._raw_data["parameters"]: + # Each param_data_raw could itself be a $ref or contain a schema that is a $ref + processed_param_container = self._process_schema_or_ref(param_data_raw) + if processed_param_container and isinstance(processed_param_container, dict): + # If the parameter itself was a $ref, processed_param_container is the resolved object. + # If it contained a schema that was a $ref, that nested schema should be resolved. + # We need to ensure 'schema' key exists if 'in' is path, query, header + if "schema" in processed_param_container and isinstance(processed_param_container["schema"], dict): + # schema was present, process it further (it might have been already by _process_schema_or_ref if it was a complex object) + # but if _process_schema_or_ref was called on param_data_raw which wasn't a ref itself, + # the internal 'schema' ref might not have been re-processed with full context. + # However, the recursive nature of _process_schema_or_ref should handle nested $refs. + pass # Assume it's processed by the main call to _process_schema_or_ref on param_data_raw + elif "content" in processed_param_container: # Parameter described by Content Object (OpenAPI 3.x) + pass # Content object schemas should have been resolved by _process_schema_or_ref + + endpoint_data["parameters"].append(processed_param_container) + + # Process requestBody + if "requestBody" in self._raw_data and isinstance(self._raw_data["requestBody"], dict): + processed_rb = self._process_schema_or_ref(self._raw_data["requestBody"]) + if processed_rb: + endpoint_data["requestBody"] = processed_rb + + # Process responses + if "responses" in self._raw_data and isinstance(self._raw_data["responses"], dict): + for status_code, resp_data_raw in self._raw_data["responses"].items(): + processed_resp = self._process_schema_or_ref(resp_data_raw) + if processed_resp: + endpoint_data["responses"][status_code] = processed_resp + elif resp_data_raw: # If processing failed but raw exists, keep raw (though this is less ideal) + endpoint_data["responses"][status_code] = resp_data_raw + logger.warning(f"Kept raw response data for {status_code} due to processing failure for {self.operation_id or self.path}") + + if not endpoint_data["responses"]: # Ensure default response if none processed + endpoint_data["responses"]["default"] = {"description": "Default response from Swagger/OpenAPI definition"} + + return endpoint_data + + def __repr__(self): + return f"" + +class ParsedAPISpec: + """解析后的API规范的通用基类""" + def __init__(self, spec_type: str, endpoints: List[Union[YAPIEndpoint, SwaggerEndpoint]], spec: Dict[str, Any]): + self.spec_type = spec_type + self.endpoints = endpoints + self.spec = spec # Store the original full spec dictionary, useful for $ref resolution if not pre-resolved + +class ParsedYAPISpec(ParsedAPISpec): """解析后的YAPI规范""" - endpoints: List[YAPIEndpoint] - categories: List[Dict[str, Any]] - total_count: int + def __init__(self, endpoints: List[YAPIEndpoint], categories: List[Dict[str, Any]], spec: Dict[str, Any]): + super().__init__(spec_type="yapi", endpoints=endpoints, spec=spec) + self.categories = categories -@dataclass -class SwaggerEndpoint: - """Swagger API端点信息""" - path: str - method: str - summary: str = "" - description: str = "" - operation_id: str = "" - tags: List[str] = field(default_factory=list) - parameters: List[Dict[str, Any]] = field(default_factory=list) - responses: Dict[str, Any] = field(default_factory=dict) - consumes: List[str] = field(default_factory=list) - produces: List[str] = field(default_factory=list) - request_body: Dict[str, Any] = field(default_factory=dict) - -@dataclass -class ParsedSwaggerSpec: - """解析后的Swagger规范""" - endpoints: List[SwaggerEndpoint] - info: Dict[str, Any] - swagger_version: str - host: str = "" - base_path: str = "" - schemes: List[str] = field(default_factory=list) - tags: List[Dict[str, Any]] = field(default_factory=list) - categories: List[Dict[str, Any]] = field(default_factory=list) - -class ParsedBusinessLogic(BaseModel): - # Placeholder for parsed business logic flow - name: str - steps: list # List of steps, each could be another Pydantic model +class ParsedSwaggerSpec(ParsedAPISpec): + """解析后的Swagger/OpenAPI规范""" + def __init__(self, endpoints: List[SwaggerEndpoint], tags: List[Dict[str, Any]], spec: Dict[str, Any]): + super().__init__(spec_type="swagger", endpoints=endpoints, spec=spec) + self.tags = tags class InputParser: - """ - Responsible for parsing DDMS supplier's input materials like API specs, etc. - """ - + """负责解析输入(如YAPI JSON)并提取API端点信息""" def __init__(self): - pass - - def parse_openapi_spec(self, spec_path: str) -> Optional[ParsedOpenAPISpec]: - """ - Parses an OpenAPI specification from a file path. - - Args: - spec_path: The file path of the OpenAPI specification. - - Returns: - A ParsedOpenAPISpec object containing the parsed specification, - or None if parsing fails. - """ - try: - # Check if file exists - if not os.path.exists(spec_path): - print(f"Error: File not found: {spec_path}") - return None - - # Read and parse JSON file - with open(spec_path, 'r', encoding='utf-8') as f: - swagger_data = json.load(f) - - # Extract basic information - swagger_version = swagger_data.get('swagger', swagger_data.get('openapi', 'Unknown')) - info = swagger_data.get('info', {}) - paths = swagger_data.get('paths', {}) - tags = swagger_data.get('tags', []) - base_path = swagger_data.get('basePath', '') - - # Create and return ParsedOpenAPISpec - return ParsedOpenAPISpec( - spec=swagger_data, - info=info, - paths=paths, - tags=tags, - basePath=base_path, - swagger_version=swagger_version - ) - - except FileNotFoundError: - print(f"File not found: {spec_path}") - return None - except json.JSONDecodeError as e: - print(f"Error parsing JSON from {spec_path}: {e}") - return None - except Exception as e: - print(f"Error parsing OpenAPI spec from {spec_path}: {e}") - return None + self.logger = logging.getLogger(__name__) def parse_yapi_spec(self, file_path: str) -> Optional[ParsedYAPISpec]: - """ - 解析YAPI规范文件 - - Args: - file_path: YAPI JSON文件路径 - - Returns: - Optional[ParsedYAPISpec]: 解析后的YAPI规范,如果解析失败则返回None - """ - if not os.path.isfile(file_path): - logger.error(f"文件不存在: {file_path}") - return None - + self.logger.info(f"Parsing YAPI spec from: {file_path}") + all_endpoints: List[YAPIEndpoint] = [] + yapi_categories: List[Dict[str, Any]] = [] + raw_spec_data_list: Optional[List[Dict[str, Any]]] = None # YAPI export is a list of categories try: with open(file_path, 'r', encoding='utf-8') as f: - yapi_data = json.load(f) - - if not isinstance(yapi_data, list): - logger.error(f"无效的YAPI文件格式: 顶层元素应该是数组") + raw_spec_data_list = json.load(f) + + if not isinstance(raw_spec_data_list, list): + self.logger.error(f"YAPI spec file {file_path} does not contain a JSON list as expected for categories.") return None - - endpoints = [] - categories = [] - - # 处理分类 - for category_data in yapi_data: + + for category_data in raw_spec_data_list: if not isinstance(category_data, dict): - logger.warning(f"YAPI 分类条目格式不正确,应为字典类型,已跳过: {category_data}") + self.logger.warning(f"Skipping non-dictionary item in YAPI spec list: {str(category_data)[:100]}") continue + cat_name = category_data.get("name") + cat_id = category_data.get("_id", category_data.get("id")) # YAPI uses _id + yapi_categories.append({"name": cat_name, "description": category_data.get("desc"), "id": cat_id}) - category_name = category_data.get('name', '') - category_desc = category_data.get('desc', '') - - # 添加到分类列表 - categories.append({ - 'name': category_name, - 'desc': category_desc - }) - - # 处理API接口 - api_list = category_data.get('list', []) - if not isinstance(api_list, list): - logger.warning(f"分类 '{category_name}' 中的 API列表 (list) 格式不正确,应为数组类型,已跳过。") - continue - - for api_item in api_list: - if not isinstance(api_item, dict): - logger.warning(f"分类 '{category_name}' 中的 API条目格式不正确,应为字典类型,已跳过: {api_item}") + for endpoint_data in category_data.get("list", []): + if not isinstance(endpoint_data, dict): + self.logger.warning(f"Skipping non-dictionary endpoint item in category '{cat_name}': {str(endpoint_data)[:100]}") continue - - # 提取API信息 - path = api_item.get('path', '') - if not path: - logger.info(f"分类 '{category_name}' 中的 API条目缺少 'path',使用空字符串。 API: {api_item.get('title', '未命名')}") - method = api_item.get('method', 'GET') - if api_item.get('method') is None: # 仅当原始数据中完全没有 method 字段时记录 - logger.info(f"分类 '{category_name}' 中的 API条目 '{path}' 缺少 'method',使用默认值 'GET'。") - title = api_item.get('title', '') - if not title: - logger.info(f"分类 '{category_name}' 中的 API条目 '{path}' ({method}) 缺少 'title',使用空字符串。") - description = api_item.get('desc', '') - - # 提取请求参数 - req_params = api_item.get('req_params', []) - req_query = api_item.get('req_query', []) - req_headers = api_item.get('req_headers', []) - - # 提取请求体信息 - req_body_type = api_item.get('req_body_type', '') - req_body_other = api_item.get('req_body_other', '') - - # 提取响应体信息 - res_body_type = api_item.get('res_body_type', '') - res_body = api_item.get('res_body', '') - - # 创建端点对象 - endpoint = YAPIEndpoint( - path=path, - method=method, - title=title, - description=description, - category_name=category_name, - req_params=req_params, - req_query=req_query, - req_headers=req_headers, - req_body_type=req_body_type, - req_body_other=req_body_other, - res_body_type=res_body_type, - res_body=res_body - ) - - endpoints.append(endpoint) - - return ParsedYAPISpec( - endpoints=endpoints, - categories=categories, - total_count=len(endpoints) - ) + try: + yapi_endpoint = YAPIEndpoint(endpoint_data, category_name=cat_name, category_id=cat_id) + all_endpoints.append(yapi_endpoint) + except Exception as e_ep: + self.logger.error(f"Error processing YAPI endpoint data (ID: {endpoint_data.get('_id', 'N/A')}, Title: {endpoint_data.get('title', 'N/A')}). Error: {e_ep}", exc_info=True) + # The 'spec' for ParsedYAPISpec should be a dict representing the whole document. + # Since YAPI export is a list of categories, we wrap it. + yapi_full_spec_dict = {"yapi_categories": raw_spec_data_list} + return ParsedYAPISpec(endpoints=all_endpoints, categories=yapi_categories, spec=yapi_full_spec_dict) + except FileNotFoundError: + self.logger.error(f"YAPI spec file not found: {file_path}") + except json.JSONDecodeError as e: + self.logger.error(f"Error decoding JSON from YAPI spec file {file_path}: {e}") except Exception as e: - logger.error(f"解析YAPI文件时出错: {str(e)}") - return None + self.logger.error(f"An unexpected error occurred while parsing YAPI spec {file_path}: {e}", exc_info=True) + return None def parse_swagger_spec(self, file_path: str) -> Optional[ParsedSwaggerSpec]: - """ - 解析Swagger规范文件 - - Args: - file_path: Swagger JSON文件路径 - - Returns: - Optional[ParsedSwaggerSpec]: 解析后的Swagger规范,如果解析失败则返回None - """ - if not os.path.isfile(file_path): - logger.error(f"文件不存在: {file_path}") - return None - + self.logger.info(f"Parsing Swagger/OpenAPI spec from: {file_path}") + all_endpoints: List[SwaggerEndpoint] = [] + swagger_tags: List[Dict[str, Any]] = [] + raw_spec_data_dict: Optional[Dict[str, Any]] = None # Swagger/OpenAPI is a single root object try: with open(file_path, 'r', encoding='utf-8') as f: - swagger_data = json.load(f) - - if not isinstance(swagger_data, dict): - logger.error(f"无效的Swagger文件格式: 顶层元素应该是对象") + # TODO: Add YAML support if needed, e.g., using PyYAML + raw_spec_data_dict = json.load(f) + + if not isinstance(raw_spec_data_dict, dict): + self.logger.error(f"Swagger spec file {file_path} does not contain a JSON object as expected.") return None - - # 提取基本信息 - swagger_version = swagger_data.get('swagger', swagger_data.get('openapi', '')) - info = swagger_data.get('info', {}) - host = swagger_data.get('host', '') - base_path = swagger_data.get('basePath', '') - schemes = swagger_data.get('schemes', []) - tags = swagger_data.get('tags', []) + + swagger_tags = raw_spec_data_dict.get("tags", []) + paths = raw_spec_data_dict.get("paths", {}) - # 创建分类列表 - categories = [] - for tag in tags: - categories.append({ - 'name': tag.get('name', ''), - 'desc': tag.get('description', '') - }) - - # 处理API路径 - paths = swagger_data.get('paths', {}) - endpoints = [] - - for path, path_item in paths.items(): - if not isinstance(path_item, dict): - continue - - # 处理每个HTTP方法 (GET, POST, PUT, DELETE等) - for method, operation in path_item.items(): - if method in ['get', 'post', 'put', 'delete', 'patch', 'options', 'head', 'trace']: - if not isinstance(operation, dict): - continue - - # 提取操作信息 - summary = operation.get('summary', '') - description = operation.get('description', '') - operation_id = operation.get('operationId', '') - operation_tags = operation.get('tags', []) - - # 提取参数信息 - parameters = operation.get('parameters', []) - - # 提取响应信息 - responses = operation.get('responses', {}) - - # 提取请求和响应的内容类型 - consumes = operation.get('consumes', swagger_data.get('consumes', [])) - produces = operation.get('produces', swagger_data.get('produces', [])) - - # 提取请求体信息 (OpenAPI 3.0 格式) - request_body = operation.get('requestBody', {}) - - # 创建端点对象 - endpoint = SwaggerEndpoint( - path=path, - method=method.upper(), - summary=summary, - description=description, - operation_id=operation_id, - tags=operation_tags, - parameters=parameters, - responses=responses, - consumes=consumes, - produces=produces, - request_body=request_body - ) - - endpoints.append(endpoint) - - # 创建返回对象 - return ParsedSwaggerSpec( - endpoints=endpoints, - info=info, - swagger_version=swagger_version, - host=host, - base_path=base_path, - schemes=schemes, - tags=tags, - categories=categories - ) + for path, path_item_obj in paths.items(): + if not isinstance(path_item_obj, dict): continue + for method, operation_obj in path_item_obj.items(): + # Common methods, can be extended + if method.lower() not in ["get", "post", "put", "delete", "patch", "options", "head", "trace"]: + continue # Skip non-standard HTTP methods or extensions like 'parameters' at path level + if not isinstance(operation_obj, dict): continue + try: + # Pass the full raw_spec_data_dict for $ref resolution within SwaggerEndpoint + swagger_endpoint = SwaggerEndpoint(path, method, operation_obj, global_spec=raw_spec_data_dict) + all_endpoints.append(swagger_endpoint) + except Exception as e_ep: + self.logger.error(f"Error processing Swagger endpoint: {method.upper()} {path}. Error: {e_ep}", exc_info=True) + return ParsedSwaggerSpec(endpoints=all_endpoints, tags=swagger_tags, spec=raw_spec_data_dict) + except FileNotFoundError: + self.logger.error(f"Swagger spec file not found: {file_path}") + except json.JSONDecodeError as e: + self.logger.error(f"Error decoding JSON from Swagger spec file {file_path}: {e}") except Exception as e: - logger.error(f"解析Swagger文件时出错: {str(e)}") - return None - - def parse_business_logic_flow(self, flow_description: str) -> Optional[ParsedBusinessLogic]: - """ - Parses a business logic flow description. - The format of this description is TBD and this parser would need to be built accordingly. - - Args: - flow_description: The string content describing the business logic flow. - - Returns: - A ParsedBusinessLogic object or None if parsing fails. - """ - print(f"[InputParser] Placeholder: Parsing business logic flow. Content: {flow_description[:100]}...") - # Placeholder: Actual parsing logic will depend on the defined format. - return ParsedBusinessLogic(name="Example Flow", steps=["Step 1 API call", "Step 2 Validate Response"]) - - # Add other parsers as needed (e.g., for data object definitions) \ No newline at end of file + self.logger.error(f"An unexpected error occurred while parsing Swagger spec {file_path}: {e}", exc_info=True) + return None \ No newline at end of file diff --git a/ddms_compliance_suite/json_schema_validator/__pycache__/validator.cpython-312.pyc b/ddms_compliance_suite/json_schema_validator/__pycache__/validator.cpython-312.pyc index 09873781f89c754adf553b450211fc63f6dd76d3..4e8cce4dad824515a7fc3320eff64828f953d06f 100644 GIT binary patch delta 119 zcmdmMvcrV;G%qg~0}x!`GRb(ckynk0jjbTDxHxsPHB%nr&&jKpyjj8g&3~Bk8QH{T zJ6L+SHy5%TVq*862QgZWLjs=1Mnm;AX delta 124 zcmdmCve$(7G%qg~0}$lyQOx+Xkynk0gCnyzzAP~(bFw8<9^>!HE1105p(2}qFy%9{ zNh)@*^zd%ZWjVye?mNqOqWFr+&1UR2jOr#pV_Fz)vZ#J!;bv7|Ao76$NUbQ@;JmUD S%sgRoAt3mq<>nb23j_g~K`2=O diff --git a/ddms_compliance_suite/json_schema_validator/validator.py b/ddms_compliance_suite/json_schema_validator/validator.py index 9479c3e..d6a12a0 100644 --- a/ddms_compliance_suite/json_schema_validator/validator.py +++ b/ddms_compliance_suite/json_schema_validator/validator.py @@ -20,22 +20,22 @@ logger = logging.getLogger(__name__) class ValidationResult: """Validation result container""" - def __init__(self, is_valid: bool, errors: List[str] = None, warnings: List[str] = None): + def __init__(self, passed: bool, errors: List[str] = None, warnings: List[str] = None): """ Initialize a validation result Args: - is_valid: Whether the data is valid according to the schema + passed: Whether the data is valid according to the schema errors: List of error messages (if any) warnings: List of warning messages (if any) """ - self.is_valid = is_valid + self.passed = passed self.errors = errors or [] self.warnings = warnings or [] def __str__(self) -> str: """String representation of validation result""" - status = "Valid" if self.is_valid else "Invalid" + status = "Valid" if self.passed else "Invalid" result = f"Validation Result: {status}\n" if self.errors: diff --git a/ddms_compliance_suite/test_framework_core.py b/ddms_compliance_suite/test_framework_core.py index 63c208e..e476f1c 100644 --- a/ddms_compliance_suite/test_framework_core.py +++ b/ddms_compliance_suite/test_framework_core.py @@ -93,18 +93,20 @@ class BaseAPITestCase: use_llm_for_query_params: bool = False use_llm_for_headers: bool = False - def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None): + def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[Any] = None): """ 初始化测试用例。 Args: endpoint_spec: 当前被测API端点的详细定义 (来自YAPI/Swagger解析结果)。 global_api_spec: 完整的API规范文档 (来自YAPI/Swagger解析结果)。 json_schema_validator: APITestOrchestrator 传入的 JSONSchemaValidator 实例 (可选)。 + llm_service: APITestOrchestrator 传入的 LLMService 实例 (可选)。 """ self.endpoint_spec = endpoint_spec self.global_api_spec = global_api_spec self.logger = logging.getLogger(f"testcase.{self.id}") self.json_schema_validator = json_schema_validator # 存储传入的校验器实例 + self.llm_service = llm_service # 存储注入的 LLMService 实例 self.logger.debug(f"Test case '{self.id}' initialized for endpoint: {self.endpoint_spec.get('method', '')} {self.endpoint_spec.get('path', '')}") # --- 1. 请求生成与修改阶段 --- @@ -120,6 +122,20 @@ class BaseAPITestCase: self.logger.debug(f"Hook: generate_request_body, current body type: {type(current_body)}") return current_body + def generate_path_params(self, current_path_params: Dict[str, Any]) -> Dict[str, Any]: + """ + 允许测试用例修改或生成路径参数。 + 这些参数将用于替换URL中的占位符,例如 /users/{userId}。 + + Args: + current_path_params: 从API规范或编排器默认逻辑生成的初始路径参数。 + + Returns: + 最终要使用的路径参数字典。 + """ + self.logger.debug(f"Hook: generate_path_params, current: {current_path_params}") + return current_path_params + # --- 1.5. 请求URL修改阶段 (新增钩子) --- def modify_request_url(self, current_url: str) -> str: """ @@ -180,26 +196,40 @@ class BaseAPITestCase: results.append(self.failed(f"{context_message_prefix} schema validation skipped: Validator not available.")) return results - is_valid, errors = self.json_schema_validator.validate(data_to_validate, schema_definition) + # validator_result 是 JSONSchemaValidator 内部定义的 ValidationResult 对象 + validator_result = self.json_schema_validator.validate(data_to_validate, schema_definition) - if is_valid: - results.append(self.passed(f"{context_message_prefix} conforms to the JSON schema.")) + if validator_result.passed: + success_message = f"{context_message_prefix} conforms to the JSON schema." + # 可以选择性地将 validator 的警告信息添加到 details + current_details = {} + if validator_result.warnings: + current_details["schema_warnings"] = validator_result.warnings + # 如果 validator_result 有其他有用的成功信息,也可以加入 message 或 details + results.append(self.passed(success_message, details=current_details if current_details else None)) else: - error_messages = [] - if isinstance(errors, list): - for error in errors: # jsonschema.exceptions.ValidationError 对象 - error_messages.append(f"- Path: '{list(error.path)}', Message: {error.message}") # error.path 是一个deque - elif isinstance(errors, str): # 兼容旧版或简单错误字符串 - error_messages.append(errors) + # 从 validator_result.errors 构建 message 和 details + error_reason = "Validation failed." + if validator_result.errors: + error_reason = "Errors:\n" + "\n".join([f"- {e}" for e in validator_result.errors]) - full_message = f"{context_message_prefix} does not conform to the JSON schema. Errors:\n" + "\n".join(error_messages) + full_message = f"{context_message_prefix} does not conform to the JSON schema. {error_reason}" + + current_details = { + "schema_errors": validator_result.errors, + "validated_data_sample": str(data_to_validate)[:200] + } + if validator_result.warnings: + current_details["schema_warnings"] = validator_result.warnings + results.append(self.failed( message=full_message, - details={"schema_errors": error_messages, "validated_data_sample": str(data_to_validate)[:200]} + details=current_details )) self.logger.warning(f"{context_message_prefix} schema validation failed: {full_message}") return results + # --- Helper to easily create a passed ValidationResult --- @staticmethod def passed(message: str, details: Optional[Dict[str, Any]] = None) -> ValidationResult: diff --git a/ddms_compliance_suite/test_orchestrator.py b/ddms_compliance_suite/test_orchestrator.py index 12f81ce..37ab934 100644 --- a/ddms_compliance_suite/test_orchestrator.py +++ b/ddms_compliance_suite/test_orchestrator.py @@ -640,21 +640,22 @@ class APITestOrchestrator: validation_results: List[ValidationResult] = [] overall_status: ExecutedTestCaseResult.Status execution_message = "" + test_case_instance: Optional[BaseAPITestCase] = None # Initialize to None # 将 endpoint_spec 转换为字典,如果它还不是的话 endpoint_spec_dict: Dict[str, Any] if isinstance(endpoint_spec, dict): endpoint_spec_dict = endpoint_spec - self.logger.debug(f"endpoint_spec 已经是字典类型。") + # self.logger.debug(f"endpoint_spec 已经是字典类型。") elif hasattr(endpoint_spec, 'to_dict') and callable(endpoint_spec.to_dict): try: endpoint_spec_dict = endpoint_spec.to_dict() - self.logger.debug(f"成功通过 to_dict() 方法将类型为 {type(endpoint_spec)} 的 endpoint_spec 转换为字典。") + # self.logger.debug(f"成功通过 to_dict() 方法将类型为 {type(endpoint_spec)} 的 endpoint_spec 转换为字典。") if not endpoint_spec_dict: # 如果 to_dict() 返回空字典 - self.logger.warning(f"endpoint_spec.to_dict() (类型: {type(endpoint_spec)}) 返回了一个空字典。") + # self.logger.warning(f"endpoint_spec.to_dict() (类型: {type(endpoint_spec)}) 返回了一个空字典。") # 尝试备用转换 if isinstance(endpoint_spec, (YAPIEndpoint, SwaggerEndpoint)): - self.logger.debug(f"尝试从 {type(endpoint_spec).__name__} 对象的属性手动构建 endpoint_spec_dict。") + # self.logger.debug(f"尝试从 {type(endpoint_spec).__name__} 对象的属性手动构建 endpoint_spec_dict。") endpoint_spec_dict = { "method": getattr(endpoint_spec, 'method', 'UNKNOWN_METHOD').upper(), "path": getattr(endpoint_spec, 'path', 'UNKNOWN_PATH'), @@ -667,7 +668,7 @@ class APITestOrchestrator: "_original_object_type": type(endpoint_spec).__name__ } if not any(endpoint_spec_dict.values()): # 如果手动构建后仍基本为空 - self.logger.error(f"手动从属性构建 endpoint_spec_dict (类型: {type(endpoint_spec)}) 后仍然为空或无效。") + # self.logger.error(f"手动从属性构建 endpoint_spec_dict (类型: {type(endpoint_spec)}) 后仍然为空或无效。") endpoint_spec_dict = {} # 重置为空,触发下方错误处理 except Exception as e: self.logger.error(f"调用 endpoint_spec (类型: {type(endpoint_spec)}) 的 to_dict() 方法时出错: {e}。尝试备用转换。") @@ -691,10 +692,10 @@ class APITestOrchestrator: endpoint_spec_dict = {} # 转换失败 elif hasattr(endpoint_spec, 'data') and isinstance(getattr(endpoint_spec, 'data'), dict): # 兼容 YAPIEndpoint 结构 endpoint_spec_dict = getattr(endpoint_spec, 'data') - self.logger.debug(f"使用了类型为 {type(endpoint_spec)} 的 endpoint_spec 的 .data 属性。") + # self.logger.debug(f"使用了类型为 {type(endpoint_spec)} 的 endpoint_spec 的 .data 属性。") else: # 如果没有 to_dict, 也不是已知可直接访问 .data 的类型,则尝试最后的通用转换或手动构建 if isinstance(endpoint_spec, (YAPIEndpoint, SwaggerEndpoint)): - self.logger.debug(f"类型为 {type(endpoint_spec).__name__} 的 endpoint_spec 没有 to_dict() 或 data,尝试从属性手动构建。") + # self.logger.debug(f"类型为 {type(endpoint_spec).__name__} 的 endpoint_spec 没有 to_dict() 或 data,尝试从属性手动构建。") endpoint_spec_dict = { "method": getattr(endpoint_spec, 'method', 'UNKNOWN_METHOD').upper(), "path": getattr(endpoint_spec, 'path', 'UNKNOWN_PATH'), @@ -795,7 +796,8 @@ class APITestOrchestrator: test_case_instance = test_case_class( endpoint_spec=endpoint_spec_dict, global_api_spec=global_spec_dict, - json_schema_validator=self.validator + json_schema_validator=self.validator, + llm_service=self.llm_service # Pass the orchestrator's LLM service instance ) self.logger.info(f"开始执行测试用例 '{test_case_instance.id}' ({test_case_instance.name}) for endpoint '{endpoint_spec_dict.get('method', 'N/A')} {endpoint_spec_dict.get('path', 'N/A')}'") @@ -928,226 +930,199 @@ class APITestOrchestrator: ) except Exception as e: - self.logger.error(f"执行测试用例 '{test_case_class.id if test_case_instance else test_case_class.__name__}' 时发生严重错误: {e}", exc_info=True) + self.logger.error(f"执行测试用例 '{test_case_class.id if hasattr(test_case_class, 'id') else test_case_class.__name__}' (在实例化阶段或之前) 时发生严重错误: {e}", exc_info=True) + # 如果 test_case_instance 在实例化时失败,它将是 None + tc_id_for_log = test_case_instance.id if test_case_instance else (test_case_class.id if hasattr(test_case_class, 'id') else "unknown_tc_id_instantiation_error") + tc_name_for_log = test_case_instance.name if test_case_instance else (test_case_class.name if hasattr(test_case_class, 'name') else test_case_class.__name__) + # 实例化失败,严重性默认为CRITICAL + tc_severity_for_log = test_case_instance.severity if test_case_instance else TestSeverity.CRITICAL + tc_duration = time.monotonic() - start_time + # validation_results 可能在此阶段为空,或包含来自先前步骤的条目(如果错误发生在实例化之后) return ExecutedTestCaseResult( - test_case_id=test_case_instance.id if test_case_instance else test_case_class.id if hasattr(test_case_class, 'id') else "unknown_tc_id", - test_case_name=test_case_instance.name if test_case_instance else test_case_class.name if hasattr(test_case_class, 'name') else "Unknown Test Case Name", - test_case_severity=test_case_instance.severity if test_case_instance else TestSeverity.CRITICAL, + test_case_id=tc_id_for_log, + test_case_name=tc_name_for_log, + test_case_severity=tc_severity_for_log, status=ExecutedTestCaseResult.Status.ERROR, - validation_points=validation_results, - message=f"测试用例执行时发生内部错误: {str(e)}", + validation_points=validation_results, # Ensure validation_results is defined (it is, at the start of the function) + message=f"测试用例执行时发生内部错误 (可能在实例化期间): {str(e)}", duration=tc_duration ) def _prepare_initial_request_data( self, - endpoint_spec: Dict[str, Any], - test_case_instance: Optional[BaseAPITestCase] = None - ) -> Tuple[str, Dict[str, Any], Dict[str, Any], Dict[str, Any], Optional[Any]]: + endpoint_spec: Dict[str, Any], # 已经转换为字典 + test_case_instance: Optional[BaseAPITestCase] = None # 传入测试用例实例以便访问其LLM配置 + ) -> APIRequestContext: # 返回 APIRequestContext 对象 """ - 根据OpenAPI端点规格和测试用例实例准备初始请求数据。 - 包含端点级别的LLM参数缓存逻辑。 + 根据API端点规范,准备初始的请求数据,包括URL(模板)、路径参数、查询参数、头部和请求体。 + 这些数据将作为测试用例中 generate_* 方法的输入。 """ - method = endpoint_spec.get("method", "get").upper() - operation_id = endpoint_spec.get("operationId", f"{method}_{endpoint_spec.get('path', '')}") - endpoint_cache_key = f"{method}_{endpoint_spec.get('path', '')}" - - self.logger.info(f"[{operation_id}] 开始为端点 {endpoint_cache_key} 准备初始请求数据 (TC: {test_case_instance.id if test_case_instance else 'N/A'})") + method = endpoint_spec.get('method', 'GET').upper() + path_template = endpoint_spec.get('path', '/') # 这是路径模板, e.g., /users/{id} + operation_id = endpoint_spec.get('operationId') or f"{method}_{path_template.replace('/', '_').replace('{', '_').replace('}','')}" - # 尝试从缓存加载参数 - if endpoint_cache_key in self.llm_endpoint_params_cache: - cached_params = self.llm_endpoint_params_cache[endpoint_cache_key] - self.logger.info(f"[{operation_id}] 从缓存加载了端点 '{endpoint_cache_key}' 的LLM参数。") - # 直接从缓存中获取各类参数,如果存在的话 - path_params_data = cached_params.get("path_params", {}) - query_params_data = cached_params.get("query_params", {}) - headers_data = cached_params.get("headers", {}) - body_data = cached_params.get("body") # Body可能是None + initial_path_params: Dict[str, Any] = {} + initial_query_params: Dict[str, Any] = {} + initial_headers: Dict[str, str] = {} + initial_body: Optional[Any] = None + + parameters = endpoint_spec.get('parameters', []) + + # 1. 处理路径参数 + path_param_specs = [p for p in parameters if p.get('in') == 'path'] + for param_spec in path_param_specs: + name = param_spec.get('name') + if not name: continue - # 即使从缓存加载,仍需确保默认头部(如Accept, Content-Type)存在或被正确设置 - # Content-Type应基于body_data是否存在来决定 - default_headers = {"Accept": "application/json"} - if body_data is not None and method not in ["GET", "DELETE", "HEAD", "OPTIONS"]: - default_headers["Content-Type"] = "application/json" + should_use_llm = self._should_use_llm_for_param_type("path_params", test_case_instance) + if should_use_llm and self.llm_service: + self.logger.info(f"Attempting LLM generation for path parameter '{name}' in '{operation_id}'") + # generated_value = self.llm_service.generate_data_for_parameter(param_spec, endpoint_spec, "path") + # initial_path_params[name] = generated_value if generated_value is not None else f"llm_placeholder_for_{name}" + initial_path_params[name] = f"llm_path_{name}" # Placeholder + else: + if 'example' in param_spec: + initial_path_params[name] = param_spec['example'] + elif param_spec.get('schema') and 'example' in param_spec['schema']: + initial_path_params[name] = param_spec['schema']['example'] # OpenAPI 3.0 `parameter.schema.example` + elif 'default' in param_spec.get('schema', {}): + initial_path_params[name] = param_spec['schema']['default'] + elif 'default' in param_spec: # OpenAPI 2.0 `parameter.default` + initial_path_params[name] = param_spec['default'] + else: + schema = param_spec.get('schema', {}) + param_type = schema.get('type', 'string') + if param_type == 'integer': initial_path_params[name] = 123 + elif param_type == 'number': initial_path_params[name] = 1.23 + elif param_type == 'boolean': initial_path_params[name] = True + elif param_type == 'string' and schema.get('format') == 'uuid': initial_path_params[name] = str(UUID(int=0)) # Example UUID + elif param_type == 'string' and schema.get('format') == 'date': initial_path_params[name] = dt.date.today().isoformat() + elif param_type == 'string' and schema.get('format') == 'date-time': initial_path_params[name] = dt.datetime.now().isoformat() + else: initial_path_params[name] = f"param_{name}" + self.logger.debug(f"Initial path param for '{operation_id}': {name} = {initial_path_params.get(name)}") + + # 2. 处理查询参数 + query_param_specs = [p for p in parameters if p.get('in') == 'query'] + for param_spec in query_param_specs: + name = param_spec.get('name') + if not name: continue + should_use_llm = self._should_use_llm_for_param_type("query_params", test_case_instance) + if should_use_llm and self.llm_service: + self.logger.info(f"Attempting LLM generation for query parameter '{name}' in '{operation_id}'") + initial_query_params[name] = f"llm_query_{name}" # Placeholder + else: + if 'example' in param_spec: + initial_query_params[name] = param_spec['example'] + elif param_spec.get('schema') and 'example' in param_spec['schema']: + initial_query_params[name] = param_spec['schema']['example'] + elif 'default' in param_spec.get('schema', {}): + initial_query_params[name] = param_spec['schema']['default'] + elif 'default' in param_spec: + initial_query_params[name] = param_spec['default'] + else: + initial_query_params[name] = f"query_val_{name}" # Simplified default + self.logger.debug(f"Initial query param for '{operation_id}': {name} = {initial_query_params.get(name)}") + + # 3. 处理请求头参数 (包括规范定义的和标准的 Content-Type/Accept) + header_param_specs = [p for p in parameters if p.get('in') == 'header'] + for param_spec in header_param_specs: + name = param_spec.get('name') + if not name: continue + # 标准头 Content-Type 和 Accept 会在后面专门处理 + if name.lower() in ['content-type', 'accept', 'authorization']: + self.logger.debug(f"Skipping standard header '{name}' in parameter processing for '{operation_id}'. It will be handled separately.") + continue - headers_data = {**default_headers, **headers_data} # 合并,缓存中的优先 - - self.logger.debug(f"[{operation_id}] (缓存加载) 准备的请求数据: method={method}, path_params={path_params_data}, query_params={query_params_data}, headers={list(headers_data.keys())}, body_type={type(body_data).__name__}") - return method, path_params_data, query_params_data, headers_data, body_data + should_use_llm = self._should_use_llm_for_param_type("headers", test_case_instance) + if should_use_llm and self.llm_service: + self.logger.info(f"Attempting LLM generation for header '{name}' in '{operation_id}'") + initial_headers[name] = f"llm_header_{name}" # Placeholder + else: + if 'example' in param_spec: + initial_headers[name] = str(param_spec['example']) + elif param_spec.get('schema') and 'example' in param_spec['schema']: + initial_headers[name] = str(param_spec['schema']['example']) + elif 'default' in param_spec.get('schema', {}): + initial_headers[name] = str(param_spec['schema']['default']) + elif 'default' in param_spec: + initial_headers[name] = str(param_spec['default']) + else: + initial_headers[name] = f"header_val_{name}" + self.logger.debug(f"Initial custom header param for '{operation_id}': {name} = {initial_headers.get(name)}") - # 缓存未命中,需要生成参数 - self.logger.info(f"[{operation_id}] 端点 '{endpoint_cache_key}' 的参数未在缓存中找到,开始生成。") - generated_params_for_endpoint: Dict[str, Any] = {} - - path_params_data: Dict[str, Any] = {} - query_params_data: Dict[str, Any] = {} - headers_data_generated: Dict[str, Any] = {} # LLM或常规生成的,不含默认 - body_data: Optional[Any] = None + # 3.1 设置 Content-Type + # 优先从 requestBody.content 获取 (OpenAPI 3.x) + request_body_spec = endpoint_spec.get('requestBody', {}) + if 'content' in request_body_spec: + content_types = list(request_body_spec['content'].keys()) + if content_types: + # 优先选择 application/json 如果存在 + initial_headers['Content-Type'] = next((ct for ct in content_types if 'json' in ct.lower()), content_types[0]) + elif 'consumes' in endpoint_spec: # 然后是 consumes (OpenAPI 2.0) + consumes = endpoint_spec['consumes'] + if consumes: + initial_headers['Content-Type'] = next((c for c in consumes if 'json' in c.lower()), consumes[0]) + elif method in ['POST', 'PUT', 'PATCH'] and not initial_headers.get('Content-Type'): + initial_headers['Content-Type'] = 'application/json' # 默认对于这些方法 + self.logger.debug(f"Initial Content-Type for '{operation_id}': {initial_headers.get('Content-Type')}") - # 提取各类参数的定义列表 - path_params_spec_list = [p for p in endpoint_spec.get("parameters", []) if p.get("in") == "path"] - query_params_spec_list = [p for p in endpoint_spec.get("parameters", []) if p.get("in") == "query"] - headers_spec_list = [p for p in endpoint_spec.get("parameters", []) if p.get("in") == "header"] - request_body_spec = endpoint_spec.get("requestBody", {}).get("content", {}).get("application/json", {}).get("schema") + # 3.2 设置 Accept + # 优先从 responses..content 获取 (OpenAPI 3.x) + responses_spec = endpoint_spec.get('responses', {}) + accept_header_set = False + for code, response_def in responses_spec.items(): + if 'content' in response_def: + accept_types = list(response_def['content'].keys()) + if accept_types: + initial_headers['Accept'] = next((at for at in accept_types if 'json' in at.lower() or '*/*' in at), accept_types[0]) + accept_header_set = True + break + if not accept_header_set and 'produces' in endpoint_spec: # 然后是 produces (OpenAPI 2.0) + produces = endpoint_spec['produces'] + if produces: + initial_headers['Accept'] = next((p for p in produces if 'json' in p.lower() or '*/*' in p), produces[0]) + accept_header_set = True + if not accept_header_set and not initial_headers.get('Accept'): + initial_headers['Accept'] = 'application/json, */*' # 更通用的默认值 + self.logger.debug(f"Initial Accept header for '{operation_id}': {initial_headers.get('Accept')}") - # --- 1. 处理路径参数 --- - param_type_key = "path_params" - if self._should_use_llm_for_param_type(param_type_key, test_case_instance) and path_params_spec_list: - self.logger.info(f"[{operation_id}] 尝试使用LLM生成路径参数。") - object_schema, model_name = self._build_object_schema_for_params(path_params_spec_list, f"DynamicPathParamsFor_{operation_id}") - if object_schema and model_name: - try: - PydanticModel = self._create_pydantic_model_from_schema(object_schema, model_name) - if PydanticModel: - llm_generated = self.llm_service.generate_parameters_from_schema( - PydanticModel, - prompt_instruction=f"Generate valid path parameters for API operation: {operation_id}. Description: {endpoint_spec.get('description', '') or endpoint_spec.get('summary', 'N/A')}" - ) - if isinstance(llm_generated, dict): - path_params_data = llm_generated - self.logger.info(f"[{operation_id}] LLM成功生成路径参数: {path_params_data}") - else: - self.logger.warning(f"[{operation_id}] LLM为路径参数返回了非字典类型: {type(llm_generated)}。回退到常规生成。") - path_params_data = self._generate_params_from_list(path_params_spec_list, operation_id, "path") - else: - path_params_data = self._generate_params_from_list(path_params_spec_list, operation_id, "path") - except Exception as e: - self.logger.error(f"[{operation_id}] LLM生成路径参数失败: {e}。回退到常规生成。", exc_info=True) - path_params_data = self._generate_params_from_list(path_params_spec_list, operation_id, "path") - else: # _build_object_schema_for_params 返回 None - path_params_data = self._generate_params_from_list(path_params_spec_list, operation_id, "path") - else: # 不使用LLM或LLM服务不可用,或者 path_params_spec_list 为空但仍需确保path_params_data被赋值 - if self._should_use_llm_for_param_type(param_type_key, test_case_instance) and not path_params_spec_list: - self.logger.info(f"[{operation_id}] 配置为路径参数使用LLM,但没有定义路径参数规格。") - # 对于不使用LLM或LLM不适用的情况,或者 spec_list 为空的情况,都执行常规生成(如果 spec_list 非空则会记录) - if path_params_spec_list and not self._should_use_llm_for_param_type(param_type_key, test_case_instance): - self.logger.info(f"[{operation_id}] 使用常规方法或LLM未启用,为路径参数。") - path_params_data = self._generate_params_from_list(path_params_spec_list, operation_id, "path") - generated_params_for_endpoint[param_type_key] = path_params_data + # 4. 处理请求体 (Body) + request_body_schema: Optional[Dict[str, Any]] = None + # 确定请求体 schema 的来源,优先 OpenAPI 3.x 的 requestBody + content_type_for_body_schema = initial_headers.get('Content-Type', 'application/json').split(';')[0].strip() - # --- 2. 处理查询参数 --- - param_type_key = "query_params" - if self._should_use_llm_for_param_type(param_type_key, test_case_instance) and query_params_spec_list: - self.logger.info(f"[{operation_id}] 尝试使用LLM生成查询参数。") - object_schema, model_name = self._build_object_schema_for_params(query_params_spec_list, f"DynamicQueryParamsFor_{operation_id}") - if object_schema and model_name: - try: - PydanticModel = self._create_pydantic_model_from_schema(object_schema, model_name) - if PydanticModel: - llm_generated = self.llm_service.generate_parameters_from_schema( - PydanticModel, - prompt_instruction=f"Generate valid query parameters for API operation: {operation_id}. Description: {endpoint_spec.get('description', '') or endpoint_spec.get('summary', 'N/A')}" - ) - if isinstance(llm_generated, dict): - query_params_data = llm_generated - self.logger.info(f"[{operation_id}] LLM成功生成查询参数: {query_params_data}") - else: - self.logger.warning(f"[{operation_id}] LLM为查询参数返回了非字典类型: {type(llm_generated)}。回退到常规生成。") - query_params_data = self._generate_params_from_list(query_params_spec_list, operation_id, "query") - else: - query_params_data = self._generate_params_from_list(query_params_spec_list, operation_id, "query") - except Exception as e: - self.logger.error(f"[{operation_id}] LLM生成查询参数失败: {e}。回退到常规生成。", exc_info=True) - query_params_data = self._generate_params_from_list(query_params_spec_list, operation_id, "query") - else: # _build_object_schema_for_params 返回 None - query_params_data = self._generate_params_from_list(query_params_spec_list, operation_id, "query") - else: # 不使用LLM或LLM服务不可用,或者 query_params_spec_list 为空 - if self._should_use_llm_for_param_type(param_type_key, test_case_instance) and not query_params_spec_list: - self.logger.info(f"[{operation_id}] 配置为查询参数使用LLM,但没有定义查询参数规格。") - if query_params_spec_list and not self._should_use_llm_for_param_type(param_type_key, test_case_instance): - self.logger.info(f"[{operation_id}] 使用常规方法或LLM未启用,为查询参数。") - query_params_data = self._generate_params_from_list(query_params_spec_list, operation_id, "query") - generated_params_for_endpoint[param_type_key] = query_params_data + if 'content' in request_body_spec and content_type_for_body_schema in request_body_spec['content']: + request_body_schema = request_body_spec['content'][content_type_for_body_schema].get('schema') + elif 'parameters' in endpoint_spec: # OpenAPI 2.0 (Swagger) body parameter + body_param = next((p for p in parameters if p.get('in') == 'body'), None) + if body_param and 'schema' in body_param: + request_body_schema = body_param['schema'] - # --- 3. 处理头部参数 --- - param_type_key = "headers" - if self._should_use_llm_for_param_type(param_type_key, test_case_instance) and headers_spec_list: - self.logger.info(f"[{operation_id}] 尝试使用LLM生成头部参数。") - object_schema, model_name = self._build_object_schema_for_params(headers_spec_list, f"DynamicHeadersFor_{operation_id}") - if object_schema and model_name: - try: - PydanticModel = self._create_pydantic_model_from_schema(object_schema, model_name) - if PydanticModel: - llm_generated = self.llm_service.generate_parameters_from_schema( - PydanticModel, - prompt_instruction=f"Generate valid HTTP headers for API operation: {operation_id}. Description: {endpoint_spec.get('description', '') or endpoint_spec.get('summary', 'N/A')}" - ) - if isinstance(llm_generated, dict): - headers_data_generated = llm_generated # Store LLM generated ones separately first - self.logger.info(f"[{operation_id}] LLM成功生成头部参数: {headers_data_generated}") - else: - self.logger.warning(f"[{operation_id}] LLM为头部参数返回了非字典类型: {type(llm_generated)}。回退到常规生成。") - headers_data_generated = self._generate_params_from_list(headers_spec_list, operation_id, "header") - else: - headers_data_generated = self._generate_params_from_list(headers_spec_list, operation_id, "header") - except Exception as e: - self.logger.error(f"[{operation_id}] LLM生成头部参数失败: {e}。回退到常规生成。", exc_info=True) - headers_data_generated = self._generate_params_from_list(headers_spec_list, operation_id, "header") - else: # _build_object_schema_for_params 返回 None - headers_data_generated = self._generate_params_from_list(headers_spec_list, operation_id, "header") - else: # 不使用LLM或LLM服务不可用,或者 headers_spec_list 为空 - if self._should_use_llm_for_param_type(param_type_key, test_case_instance) and not headers_spec_list: - self.logger.info(f"[{operation_id}] 配置为头部参数使用LLM,但没有定义头部参数规格。") - if headers_spec_list and not self._should_use_llm_for_param_type(param_type_key, test_case_instance): - self.logger.info(f"[{operation_id}] 使用常规方法或LLM未启用,为头部参数。") - headers_data_generated = self._generate_params_from_list(headers_spec_list, operation_id, "header") - generated_params_for_endpoint[param_type_key] = headers_data_generated - - # --- 4. 处理请求体 --- - param_type_key = "body" - if self._should_use_llm_for_param_type(param_type_key, test_case_instance) and request_body_spec: - self.logger.info(f"[{operation_id}] 尝试使用LLM生成请求体。") - model_name = f"DynamicBodyFor_{operation_id}" - try: - PydanticModel = self._create_pydantic_model_from_schema(request_body_spec, model_name) - if PydanticModel: - llm_generated_body = self.llm_service.generate_parameters_from_schema( - PydanticModel, - prompt_instruction=f"Generate a valid JSON request body for API operation: {operation_id}. Description: {endpoint_spec.get('description', '') or endpoint_spec.get('summary', 'N/A')}. Schema: {json.dumps(request_body_spec, indent=2)}" - ) - if isinstance(llm_generated_body, dict): - try: - body_data = PydanticModel(**llm_generated_body).model_dump(by_alias=True) - self.logger.info(f"[{operation_id}] LLM成功生成并验证请求体。") - except ValidationError as ve: - self.logger.error(f"[{operation_id}] LLM生成的请求体未能通过Pydantic模型验证: {ve}。回退到常规生成。") - body_data = self._generate_data_from_schema(request_body_spec, "requestBody", operation_id) - elif isinstance(llm_generated_body, BaseModel): # LLM直接返回模型实例 - body_data = llm_generated_body.model_dump(by_alias=True) - self.logger.info(f"[{operation_id}] LLM成功生成请求体 (模型实例)。") - else: - self.logger.warning(f"[{operation_id}] LLM为请求体返回了非预期类型: {type(llm_generated_body)}。回退到常规生成。") - body_data = self._generate_data_from_schema(request_body_spec, "requestBody", operation_id) - else: # _create_pydantic_model_from_schema 返回 None - self.logger.warning(f"[{operation_id}] 未能为请求体创建Pydantic模型。回退到常规生成。") - body_data = self._generate_data_from_schema(request_body_spec, "requestBody", operation_id) - except Exception as e: - self.logger.error(f"[{operation_id}] LLM生成请求体失败: {e}。回退到常规生成。", exc_info=True) - body_data = self._generate_data_from_schema(request_body_spec, "requestBody", operation_id) - elif request_body_spec: # 不使用LLM但有body spec - self.logger.info(f"[{operation_id}] 使用常规方法或LLM未启用/不适用,为请求体。") - body_data = self._generate_data_from_schema(request_body_spec, "requestBody", operation_id) - else: # 没有requestBody定义 - self.logger.info(f"[{operation_id}] 端点没有定义请求体。") - body_data = None # 明确设为None - generated_params_for_endpoint[param_type_key] = body_data + if request_body_schema: + should_use_llm_for_body = self._should_use_llm_for_param_type("body", test_case_instance) + if should_use_llm_for_body and self.llm_service: + self.logger.info(f"Attempting LLM generation for request body of '{operation_id}' with schema...") + initial_body = self.llm_service.generate_data_from_schema(request_body_schema, endpoint_spec, "requestBody") + if initial_body is None: + self.logger.warning(f"LLM failed to generate request body for '{operation_id}'. Falling back to default schema generator.") + initial_body = self._generate_data_from_schema(request_body_schema, context_name=f"{operation_id}_body", operation_id=operation_id) + else: + initial_body = self._generate_data_from_schema(request_body_schema, context_name=f"{operation_id}_body", operation_id=operation_id) + self.logger.debug(f"Initial request body generated for '{operation_id}' (type: {type(initial_body)})") + else: + self.logger.debug(f"No request body schema found or applicable for '{operation_id}' with Content-Type '{content_type_for_body_schema}'. Initial body is None.") - # 合并最终的头部 (默认头部 + 生成的头部) - final_headers = {"Accept": "application/json"} - if body_data is not None and method not in ["GET", "DELETE", "HEAD", "OPTIONS"]: - final_headers["Content-Type"] = "application/json" - final_headers.update(headers_data_generated) # headers_data_generated 是从LLM或常规生成的 - - # 将本次生成的所有参数存入缓存 - self.llm_endpoint_params_cache[endpoint_cache_key] = generated_params_for_endpoint - self.logger.info(f"[{operation_id}] 端点 '{endpoint_cache_key}' 的参数已生成并存入缓存。") - - # 确保路径参数中的值都是字符串 (URL部分必须是字符串) - path_params_data_str = {k: str(v) if v is not None else "" for k, v in path_params_data.items()} - - self.logger.debug(f"[{operation_id}] (新生成) 准备的请求数据: method={method}, path_params={path_params_data_str}, query_params={query_params_data}, headers={list(final_headers.keys())}, body_type={type(body_data).__name__}") - return method, path_params_data_str, query_params_data, final_headers, body_data + # 构造并返回APIRequestContext + return APIRequestContext( + method=method, + url=path_template, # 传递路径模板, e.g. /items/{itemId} + path_params=initial_path_params, + query_params=initial_query_params, + headers=initial_headers, + body=initial_body, + endpoint_spec=endpoint_spec # 传递原始的 endpoint_spec 字典 + ) def _build_object_schema_for_params(self, params_spec_list: List[Dict[str, Any]], model_name_base: str) -> Tuple[Optional[Dict[str, Any]], str]: """ @@ -1490,4 +1465,34 @@ class APITestOrchestrator: self.logger.debug(f"{log_prefix}_generate_data_from_schema: 未知或不支持的 schema 类型 '{schema_type}' for{context_log}. Schema: {schema}") return None + def _format_url_with_path_params(self, path_template: str, path_params: Dict[str, Any]) -> str: + """ + 使用提供的路径参数格式化URL路径模板。 + 例如: path_template='/users/{userId}/items/{itemId}', path_params={'userId': 123, 'itemId': 'abc'} + 会返回 '/users/123/items/abc' + 同时处理 base_url. + """ + # 首先确保 path_template 不以 '/' 开头,如果 self.base_url 已经以 '/' 结尾 + # 或者确保它们之间只有一个 '/' + formatted_path = path_template + for key, value in path_params.items(): + placeholder = f"{{{key}}}" + if placeholder in formatted_path: + formatted_path = formatted_path.replace(placeholder, str(value)) + else: + self.logger.warning(f"路径参数 '{key}' 在路径模板 '{path_template}' 中未找到占位符。") + + # 拼接 base_url 和格式化后的路径 + # 确保 base_url 和 path 之间只有一个斜杠 + if self.base_url.endswith('/') and formatted_path.startswith('/'): + url = self.base_url + formatted_path[1:] + elif not self.base_url.endswith('/') and not formatted_path.startswith('/'): + if formatted_path: # 避免在 base_url 后添加不必要的 '/' (如果 formatted_path 为空) + url = self.base_url + '/' + formatted_path + else: + url = self.base_url + else: + url = self.base_url + formatted_path + return url + diff --git a/log.txt b/log.txt index 85177d8..36a4fd9 100644 --- a/log.txt +++ b/log.txt @@ -1,327 +1,1077 @@ -2025-05-21 18:30:41,316 - __main__ - DEBUG - 已启用详细日志模式 -2025-05-21 18:30:41,316 - __main__ - INFO - args.api_key: sk-0213c70194624703a1d0d80e0f762b0e -2025-05-21 18:30:41,316 - ddms_compliance_suite.test_orchestrator - INFO - 初始化 TestCaseRegistry,扫描目录: ./custom_testcases -2025-05-21 18:30:41,316 - ddms_compliance_suite.test_case_registry - INFO - 开始从目录 './custom_testcases' 发现测试用例... -2025-05-21 18:30:41,316 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: basic_checks 从 ./custom_testcases/basic_checks.py -2025-05-21 18:30:41,316 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-HEADER-001' (检查响应中是否存在 'X-Request-ID' 头) 来自类 'HeaderExistenceCheck' -2025-05-21 18:30:41,316 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-STATUS-001' (基本状态码 200 检查) 来自类 'StatusCode200Check' -2025-05-21 18:30:41,316 - ddms_compliance_suite.test_case_registry - INFO - 已根据 execution_order (主要) 和类名 (次要) 对 2 个测试用例类进行了排序。 -2025-05-21 18:30:41,316 - ddms_compliance_suite.test_case_registry - INFO - 测试用例发现完成。总共注册了 2 个独特的测试用例 (基于ID)。发现并排序了 2 个测试用例类。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - TestCaseRegistry 初始化完成,发现 2 个测试用例类。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.llm_utils.llm_service - INFO - LLMService initialized for model 'qwen-plus' at https://dashscope.aliyuncs.com/compatible-mode/v1 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - LLMService 已成功初始化,模型: qwen-plus。 -2025-05-21 18:30:41,317 - __main__ - INFO - 从Swagger文件运行测试: assets/doc/井筒API示例swagger_fixed_simple.json -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - 从Swagger文件加载API定义: assets/doc/井筒API示例swagger_fixed_simple.json -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} (数据推送接口) -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 发现了 2 个适用的测试用例: ['TC-HEADER-001', 'TC-STATUS-001'] -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-HEADER-001' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,317 - testcase.TC-HEADER-001 - INFO - 测试用例 TC-HEADER-001 (检查响应中是否存在 'X-Request-ID' 头) 已初始化 for endpoint /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} -2025-05-21 18:30:41,317 - testcase.TC-HEADER-001 - INFO - 开始执行测试用例 'TC-HEADER-001' for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-HEADER-001) -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的参数未在缓存中找到,开始生成。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为路径参数。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 path 参数。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'dms_instance_code' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'dms_instance_code', 'in': 'path', 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'dms_instance_code'): example_string -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'schema' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'schema', 'in': 'path', 'description': '', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'schema'): example_string -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'version' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'version', 'in': 'path', 'description': '', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'version'): example_string -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 path 参数: {'dms_instance_code': 'example_string', 'schema': 'example_string', 'version': 'example_string'} -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - [] 没有定义 query 参数。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为头部参数。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 header 参数。 -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'tenant-id' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'tenant-id', 'in': 'header', 'description': 'tenant-id (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'Authorization' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'Authorization', 'in': 'header', 'description': 'Authorization (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string -2025-05-21 18:30:41,317 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} -2025-05-21 18:30:41,318 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点没有定义请求体。 -2025-05-21 18:30:41,318 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的参数已生成并存入缓存。 -2025-05-21 18:30:41,318 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (新生成) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_string', 'schema': 'example_string', 'version': 'example_string'}, query_params={}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,390 - testcase.TC-HEADER-001 - WARNING - 请求头 'X-Request-ID' 未在 http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/message/push/example_string/example_string 的响应中找到。 -2025-05-21 18:30:41,390 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-HEADER-001' 执行失败。 -2025-05-21 18:30:41,390 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-HEADER-001' 执行完毕,状态: 失败 -2025-05-21 18:30:41,390 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' -2025-05-21 18:30:41,390 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,390 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,390 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 初始化。 -2025-05-21 18:30:41,390 - testcase.TC-STATUS-001 - INFO - 开始执行测试用例 'TC-STATUS-001' for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' -2025-05-21 18:30:41,390 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-STATUS-001) -2025-05-21 18:30:41,390 - ddms_compliance_suite.test_orchestrator - INFO - [] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的LLM参数。 -2025-05-21 18:30:41,390 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_string', 'schema': 'example_string', 'version': 'example_string'}, query_params={}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,491 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/message/push/example_string/example_string -2025-05-21 18:30:41,491 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 -2025-05-21 18:30:41,491 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 测试完成,最终状态: 部分成功 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} (地质单元列表查询) -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 发现了 2 个适用的测试用例: ['TC-HEADER-001', 'TC-STATUS-001'] -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-HEADER-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,492 - testcase.TC-HEADER-001 - INFO - 测试用例 TC-HEADER-001 (检查响应中是否存在 'X-Request-ID' 头) 已初始化 for endpoint /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} -2025-05-21 18:30:41,492 - testcase.TC-HEADER-001 - INFO - 开始执行测试用例 'TC-HEADER-001' for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-HEADER-001) -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的参数未在缓存中找到,开始生成。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为路径参数。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 path 参数。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'dms_instance_code' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'dms_instance_code', 'in': 'path', 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'dms_instance_code'): example_string -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'version' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'version', 'in': 'path', 'description': '交换模型版本', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'version'): example_string -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 path 参数: {'dms_instance_code': 'example_string', 'version': 'example_string'} -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为查询参数。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 query 参数。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'pageNo' ('query' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'pageNo', 'in': 'query', 'required': False, 'description': '页码(从1开始)', 'type': 'string'} -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: query parameter 'pageNo'): example_string -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'pageSize' ('query' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'pageSize', 'in': 'query', 'required': False, 'description': '分页大小(最大值200)', 'type': 'string'} -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: query parameter 'pageSize'): example_string -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 query 参数: {'pageNo': 'example_string', 'pageSize': 'example_string'} -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为头部参数。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 header 参数。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'tenant-id' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'tenant-id', 'in': 'header', 'description': 'tenant-id (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'Authorization' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'Authorization', 'in': 'header', 'description': 'Authorization (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点没有定义请求体。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的参数已生成并存入缓存。 -2025-05-21 18:30:41,492 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (新生成) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_string', 'version': 'example_string'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,517 - testcase.TC-HEADER-001 - WARNING - 请求头 'X-Request-ID' 未在 http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit/example_string 的响应中找到。 -2025-05-21 18:30:41,518 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-HEADER-001' 执行失败。 -2025-05-21 18:30:41,518 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-HEADER-001' 执行完毕,状态: 失败 -2025-05-21 18:30:41,518 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' -2025-05-21 18:30:41,518 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,518 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,518 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 初始化。 -2025-05-21 18:30:41,518 - testcase.TC-STATUS-001 - INFO - 开始执行测试用例 'TC-STATUS-001' for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' -2025-05-21 18:30:41,518 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-STATUS-001) -2025-05-21 18:30:41,518 - ddms_compliance_suite.test_orchestrator - INFO - [] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的LLM参数。 -2025-05-21 18:30:41,518 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_string', 'version': 'example_string'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,539 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit/example_string -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 测试完成,最终状态: 部分成功 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit (地质单元数据修改) -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' 发现了 2 个适用的测试用例: ['TC-HEADER-001', 'TC-STATUS-001'] -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-HEADER-001' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,539 - testcase.TC-HEADER-001 - INFO - 测试用例 TC-HEADER-001 (检查响应中是否存在 'X-Request-ID' 头) 已初始化 for endpoint /api/dms/{dms_instance_code}/v1/cd_geo_unit -2025-05-21 18:30:41,539 - testcase.TC-HEADER-001 - INFO - 开始执行测试用例 'TC-HEADER-001' for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-HEADER-001) -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数未在缓存中找到,开始生成。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为路径参数。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 path 参数。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'dms_instance_code' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'dms_instance_code', 'in': 'path', 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'dms_instance_code'): example_string -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 path 参数: {'dms_instance_code': 'example_string'} -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为查询参数。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 query 参数。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'id' ('query' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'type': 'string'} -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: query parameter 'id'): example_string -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 query 参数: {'id': 'example_string'} -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为头部参数。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 header 参数。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'tenant-id' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'tenant-id', 'in': 'header', 'description': 'tenant-id (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'Authorization' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'Authorization', 'in': 'header', 'description': 'Authorization (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点没有定义请求体。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数已生成并存入缓存。 -2025-05-21 18:30:41,539 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (新生成) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_string'}, query_params={'id': 'example_string'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,557 - testcase.TC-HEADER-001 - WARNING - 请求头 'X-Request-ID' 未在 http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit 的响应中找到。 -2025-05-21 18:30:41,557 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-HEADER-001' 执行失败。 -2025-05-21 18:30:41,557 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-HEADER-001' 执行完毕,状态: 失败 -2025-05-21 18:30:41,557 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,557 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,557 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,557 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 -2025-05-21 18:30:41,557 - testcase.TC-STATUS-001 - INFO - 开始执行测试用例 'TC-STATUS-001' for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,557 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-STATUS-001) -2025-05-21 18:30:41,557 - ddms_compliance_suite.test_orchestrator - INFO - [] 从缓存加载了端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 -2025-05-21 18:30:41,557 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (缓存加载) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_string'}, query_params={'id': 'example_string'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,578 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' 测试完成,最终状态: 部分成功 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit (地质单元数据删除) -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' 发现了 2 个适用的测试用例: ['TC-HEADER-001', 'TC-STATUS-001'] -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-HEADER-001' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,578 - testcase.TC-HEADER-001 - INFO - 测试用例 TC-HEADER-001 (检查响应中是否存在 'X-Request-ID' 头) 已初始化 for endpoint /api/dms/{dms_instance_code}/v1/cd_geo_unit -2025-05-21 18:30:41,578 - testcase.TC-HEADER-001 - INFO - 开始执行测试用例 'TC-HEADER-001' for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-HEADER-001) -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数未在缓存中找到,开始生成。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为路径参数。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 path 参数。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'dms_instance_code' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'dms_instance_code', 'in': 'path', 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'dms_instance_code'): example_string -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 path 参数: {'dms_instance_code': 'example_string'} -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为查询参数。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 query 参数。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'id' ('query' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'type': 'string'} -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: query parameter 'id'): example_string -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 query 参数: {'id': 'example_string'} -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为头部参数。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 header 参数。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'tenant-id' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'tenant-id', 'in': 'header', 'description': 'tenant-id (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'Authorization' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'Authorization', 'in': 'header', 'description': 'Authorization (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点没有定义请求体。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数已生成并存入缓存。 -2025-05-21 18:30:41,578 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (新生成) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_string'}, query_params={'id': 'example_string'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,604 - testcase.TC-HEADER-001 - WARNING - 请求头 'X-Request-ID' 未在 http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit 的响应中找到。 -2025-05-21 18:30:41,604 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-HEADER-001' 执行失败。 -2025-05-21 18:30:41,604 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-HEADER-001' 执行完毕,状态: 失败 -2025-05-21 18:30:41,604 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,604 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,604 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,604 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 -2025-05-21 18:30:41,604 - testcase.TC-STATUS-001 - INFO - 开始执行测试用例 'TC-STATUS-001' for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,604 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-STATUS-001) -2025-05-21 18:30:41,604 - ddms_compliance_suite.test_orchestrator - INFO - [] 从缓存加载了端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 -2025-05-21 18:30:41,604 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (缓存加载) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_string'}, query_params={'id': 'example_string'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,624 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' 测试完成,最终状态: 部分成功 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: POST /api/dms/{dms_instance_code}/v1/cd_geo_unit (地质单元数据添加) -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' 发现了 2 个适用的测试用例: ['TC-HEADER-001', 'TC-STATUS-001'] -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-HEADER-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,624 - testcase.TC-HEADER-001 - INFO - 测试用例 TC-HEADER-001 (检查响应中是否存在 'X-Request-ID' 头) 已初始化 for endpoint /api/dms/{dms_instance_code}/v1/cd_geo_unit -2025-05-21 18:30:41,624 - testcase.TC-HEADER-001 - INFO - 开始执行测试用例 'TC-HEADER-001' for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-HEADER-001) -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数未在缓存中找到,开始生成。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为路径参数。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 path 参数。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'dms_instance_code' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'dms_instance_code', 'in': 'path', 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'dms_instance_code'): example_string -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 path 参数: {'dms_instance_code': 'example_string'} -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 没有定义 query 参数。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为头部参数。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 header 参数。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'tenant-id' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'tenant-id', 'in': 'header', 'description': 'tenant-id (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'Authorization' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'Authorization', 'in': 'header', 'description': 'Authorization (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点没有定义请求体。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数已生成并存入缓存。 -2025-05-21 18:30:41,624 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (新生成) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_string'}, query_params={}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,639 - testcase.TC-HEADER-001 - WARNING - 请求头 'X-Request-ID' 未在 http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit 的响应中找到。 -2025-05-21 18:30:41,639 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-HEADER-001' 执行失败。 -2025-05-21 18:30:41,639 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-HEADER-001' 执行完毕,状态: 失败 -2025-05-21 18:30:41,639 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,639 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,639 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,639 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 -2025-05-21 18:30:41,639 - testcase.TC-STATUS-001 - INFO - 开始执行测试用例 'TC-STATUS-001' for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' -2025-05-21 18:30:41,639 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-STATUS-001) -2025-05-21 18:30:41,639 - ddms_compliance_suite.test_orchestrator - INFO - [] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 -2025-05-21 18:30:41,639 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_string'}, query_params={}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,656 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' 测试完成,最终状态: 部分成功 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id} (地质单元查询详情) -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-HEADER-001' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' 发现了 2 个适用的测试用例: ['TC-HEADER-001', 'TC-STATUS-001'] -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-HEADER-001' for 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,656 - testcase.TC-HEADER-001 - INFO - 测试用例 TC-HEADER-001 (检查响应中是否存在 'X-Request-ID' 头) 已初始化 for endpoint /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id} -2025-05-21 18:30:41,656 - testcase.TC-HEADER-001 - INFO - 开始执行测试用例 'TC-HEADER-001' for endpoint 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 GET_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id} 准备初始请求数据 (TC: TC-HEADER-001) -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'GET_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' 的参数未在缓存中找到,开始生成。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为路径参数。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 path 参数。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'dms_instance_code' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'dms_instance_code', 'in': 'path', 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'dms_instance_code'): example_string -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'version' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'version', 'in': 'path', 'description': '交换模型版本', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'version'): example_string -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'id' ('path' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'id', 'in': 'path', 'description': '', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: path parameter 'id'): example_string -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 path 参数: {'dms_instance_code': 'example_string', 'version': 'example_string', 'id': 'example_string'} -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 没有定义 query 参数。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法或LLM未启用,为头部参数。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 使用常规方法生成 header 参数。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'tenant-id' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'tenant-id', 'in': 'header', 'description': 'tenant-id (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 参数 'Authorization' ('header' 类型) 缺少嵌套 'schema' 字段,尝试从顶层 'type' 构建临时schema用于常规生成。 Param spec: {'name': 'Authorization', 'in': 'header', 'description': 'Authorization (Only:undefined)', 'required': True, 'type': 'string'} -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点没有定义请求体。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - INFO - [] 端点 'GET_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' 的参数已生成并存入缓存。 -2025-05-21 18:30:41,656 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (新生成) 准备的请求数据: method=GET, path_params={'dms_instance_code': 'example_string', 'version': 'example_string', 'id': 'example_string'}, query_params={}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,674 - testcase.TC-HEADER-001 - WARNING - 请求头 'X-Request-ID' 未在 http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit/example_string/example_string 的响应中找到。 -2025-05-21 18:30:41,674 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-HEADER-001' 执行失败。 -2025-05-21 18:30:41,674 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-HEADER-001' 执行完毕,状态: 失败 -2025-05-21 18:30:41,674 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' -2025-05-21 18:30:41,674 - ddms_compliance_suite.test_orchestrator - DEBUG - Manually converting endpoint_spec of type SwaggerEndpoint to dict. -2025-05-21 18:30:41,674 - ddms_compliance_suite.test_orchestrator - WARNING - global_api_spec无法转换为字典,实际类型: -2025-05-21 18:30:41,674 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' 初始化。 -2025-05-21 18:30:41,674 - testcase.TC-STATUS-001 - INFO - 开始执行测试用例 'TC-STATUS-001' for endpoint 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' -2025-05-21 18:30:41,674 - ddms_compliance_suite.test_orchestrator - INFO - [] 开始为端点 GET_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id} 准备初始请求数据 (TC: TC-STATUS-001) -2025-05-21 18:30:41,674 - ddms_compliance_suite.test_orchestrator - INFO - [] 从缓存加载了端点 'GET_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' 的LLM参数。 -2025-05-21 18:30:41,674 - ddms_compliance_suite.test_orchestrator - DEBUG - [] (缓存加载) 准备的请求数据: method=GET, path_params={'dms_instance_code': 'example_string', 'version': 'example_string', 'id': 'example_string'}, query_params={}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=NoneType -2025-05-21 18:30:41,691 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_string/v1/cd_geo_unit/example_string/example_string -2025-05-21 18:30:41,691 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 -2025-05-21 18:30:41,691 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 -2025-05-21 18:30:41,691 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}' 测试完成,最终状态: 部分成功 -2025-05-21 18:30:41,692 - __main__ - INFO - 测试结果已保存为JSON: test_report.json - -===== 测试运行摘要 ===== -开始时间: 2025-05-21T18:30:41.317570 -结束时间: 2025-05-21T18:30:41.691839 -总耗时: 0.37 秒 - ---- 端点统计 --- -定义的端点总数: 6 -实际测试的端点数: 6 - 通过: 0 - 失败: 0 - 部分成功: 6 - 执行错误: 0 - 跳过执行: 0 - 端点通过率: 0.00% - ---- 测试用例统计 --- -适用的测试用例总数 (计划执行): 12 -实际执行的测试用例总数: 12 - 通过: 6 - 失败: 6 - 执行错误 (测试用例代码问题): 0 - 跳过 (在端点内被跳过): 0 - 测试用例通过率: 50.00% +2025-05-26 14:59:38,221 - __main__ - DEBUG - 已启用详细日志模式 +2025-05-26 14:59:38,221 - __main__ - INFO - args.api_key: sk-0213c70194624703a1d0d80e0f762b0e +2025-05-26 14:59:38,221 - ddms_compliance_suite.test_orchestrator - INFO - 初始化 TestCaseRegistry,扫描目录: ./custom_testcases +2025-05-26 14:59:38,221 - ddms_compliance_suite.test_case_registry - INFO - 开始从目录 './custom_testcases' 及其子目录发现测试用例... +2025-05-26 14:59:38,222 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: basic_checks 从 ./custom_testcases/basic_checks.py +2025-05-26 14:59:38,222 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-STATUS-001' (基本状态码 200 检查) 来自类 'StatusCode200Check' (路径: ./custom_testcases/basic_checks.py) +2025-05-26 14:59:38,222 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: https_mandatory_case 从 ./custom_testcases/compliance_catalog/security/https_mandatory_case.py +2025-05-26 14:59:38,222 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-SECURITY-001' (HTTPS Protocol Mandatory Verification) 来自类 'HTTPSMandatoryCase' (路径: ./custom_testcases/compliance_catalog/security/https_mandatory_case.py) +2025-05-26 14:59:38,224 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: url_llm_checks 从 ./custom_testcases/compliance_catalog/normative_spec/url_llm_checks.py +2025-05-26 14:59:38,224 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' (综合URL规范与RESTful风格检查 (LLM)) 来自类 'ComprehensiveURLCheckLLMCase' (路径: ./custom_testcases/compliance_catalog/normative_spec/url_llm_checks.py) +2025-05-26 14:59:38,224 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: http_method_usage_case 从 ./custom_testcases/compliance_catalog/normative_spec/http_method_usage_case.py +2025-05-26 14:59:38,224 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: missing_required_field_query_case 从 ./custom_testcases/compliance_catalog/error_handling/missing_required_field_query_case.py +2025-05-26 14:59:38,224 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-ERROR-4003-QUERY' (Error Code 4003 - Missing Required Query Parameter Validation) 来自类 'MissingRequiredFieldQueryCase' (路径: ./custom_testcases/compliance_catalog/error_handling/missing_required_field_query_case.py) +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: type_mismatch_body_case 从 ./custom_testcases/compliance_catalog/error_handling/type_mismatch_body_case.py +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-ERROR-4001-BODY' (Error Code 4001 - Request Body Type Mismatch Validation) 来自类 'TypeMismatchBodyCase' (路径: ./custom_testcases/compliance_catalog/error_handling/type_mismatch_body_case.py) +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: missing_required_field_body_case 从 ./custom_testcases/compliance_catalog/error_handling/missing_required_field_body_case.py +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-ERROR-4003-BODY' (Error Code 4003 - Missing Required Request Body Field Validation) 来自类 'MissingRequiredFieldBodyCase' (路径: ./custom_testcases/compliance_catalog/error_handling/missing_required_field_body_case.py) +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: type_mismatch_query_param_case 从 ./custom_testcases/compliance_catalog/error_handling/type_mismatch_query_param_case.py +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-ERROR-4001-QUERY' (Error Code 4001 - Query Parameter Type Mismatch Validation) 来自类 'TypeMismatchQueryParamCase' (路径: ./custom_testcases/compliance_catalog/error_handling/type_mismatch_query_param_case.py) +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - DEBUG - 成功导入模块: schema_validation_case 从 ./custom_testcases/compliance_catalog/core_functionality/schema_validation_case.py +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - INFO - 已注册测试用例: 'TC-CORE-FUNC-001' (Response Body JSON Schema Validation) 来自类 'ResponseSchemaValidationCase' (路径: ./custom_testcases/compliance_catalog/core_functionality/schema_validation_case.py) +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - INFO - 已根据 execution_order (主要) 和类名 (次要) 对 8 个测试用例类进行了排序。 +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_case_registry - INFO - 测试用例发现完成。总共注册了 8 个独特的测试用例 (基于ID)。发现并排序了 8 个测试用例类。 +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_orchestrator - INFO - TestCaseRegistry 初始化完成,发现 8 个测试用例类。 +2025-05-26 14:59:38,225 - ddms_compliance_suite.llm_utils.llm_service - INFO - LLMService initialized for model 'qwen-plus' at https://dashscope.aliyuncs.com/compatible-mode/v1 +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_orchestrator - INFO - LLMService 已成功初始化,模型: qwen-plus。 +2025-05-26 14:59:38,225 - __main__ - INFO - 从YAPI文件运行测试: assets/doc/井筒API示例_simple.json +2025-05-26 14:59:38,225 - ddms_compliance_suite.test_orchestrator - INFO - 从YAPI文件加载API定义: assets/doc/井筒API示例_simple.json +2025-05-26 14:59:38,225 - ddms_compliance_suite.input_parser.parser - INFO - Parsing YAPI spec from: assets/doc/井筒API示例_simple.json +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} (数据推送接口) +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}'。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 发现了 8 个适用的测试用例: ['TC-STATUS-001', 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001', 'TC-CORE-FUNC-001', 'TC-SECURITY-001', 'TC-ERROR-4001-QUERY', 'TC-ERROR-4001-BODY', 'TC-ERROR-4003-BODY', 'TC-ERROR-4003-QUERY'] +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: StatusCode200Check 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:38,226 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 初始化。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-STATUS-001' (基本状态码 200 检查) for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-STATUS-001) +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的参数未在缓存中找到,开始生成。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 使用常规方法或LLM未启用,为路径参数。 +2025-05-26 14:59:38,226 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 使用常规方法生成 path 参数。 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 使用 schema 中的 'example' 值 for (context: path parameter 'dms_instance_code'): example_dms_instance_code +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 使用 schema 中的 'example' 值 for (context: path parameter 'schema'): example_schema +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 使用 schema 中的 'example' 值 for (context: path parameter 'version'): example_version +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 常规方法生成的 path 参数: {'dms_instance_code': 'example_dms_instance_code', 'schema': 'example_schema', 'version': 'example_version'} +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 没有定义 query 参数。 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 使用常规方法或LLM未启用,为头部参数。 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 使用常规方法生成 header 参数。 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 使用常规方法或LLM未启用/不适用,为请求体。 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 object 类型数据 for (context: requestBody). Properties: ['isSearchCount', 'query'] +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 使用 schema 中的 'default' 值 for (context: requestBody.isSearchCount): True +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 object 类型数据 for (context: requestBody.query). Properties: ['dataRegions', 'fields', 'filter', 'groupFields', 'groupFilter', 'sort'] +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 array 类型数据 for (context: requestBody.query.dataRegions). Items schema: {'description': '数据域,如:JD、DG、TL', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.dataRegions[0]): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 array 类型数据 for (context: requestBody.query.fields). Items schema: {'description': '查询的字段', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.fields[0]): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 object 类型数据 for (context: requestBody.query.filter). Properties: ['key', 'logic', 'realValue', 'singleValue', 'subFilter', 'symbol'] +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.filter.key): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.filter.logic): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 array 类型数据 for (context: requestBody.query.filter.realValue). Items schema: {'description': '条件值', 'type': 'object', 'properties': {}}, minItems: 1 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 object 类型数据 for (context: requestBody.query.filter.realValue[0]). Properties: [] +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 object 类型数据 for (context: requestBody.query.filter.singleValue). Properties: [] +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 array 类型数据 for (context: requestBody.query.filter.subFilter). Items schema: {'$ref': '#/components/schemas/FilterVO', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.filter.subFilter[0]): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.filter.symbol): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 array 类型数据 for (context: requestBody.query.groupFields). Items schema: {'description': '分组字段group by', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.groupFields[0]): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 object 类型数据 for (context: requestBody.query.groupFilter). Properties: ['key', 'logic', 'realValue', 'singleValue', 'subFilter', 'symbol'] +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.groupFilter.key): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.groupFilter.logic): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 array 类型数据 for (context: requestBody.query.groupFilter.realValue). Items schema: {'description': '条件值', 'type': 'object', 'properties': {}}, minItems: 1 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 object 类型数据 for (context: requestBody.query.groupFilter.realValue[0]). Properties: [] +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 object 类型数据 for (context: requestBody.query.groupFilter.singleValue). Properties: [] +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 array 类型数据 for (context: requestBody.query.groupFilter.subFilter). Items schema: {'$ref': '#/components/schemas/FilterVO', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.groupFilter.subFilter[0]): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 string 类型数据 ('') for (context: requestBody.query.groupFilter.symbol): example_string +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 生成 object 类型数据 for (context: requestBody.query.sort). Properties: [] +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的参数已生成并存入缓存。 +2025-05-26 14:59:38,227 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] (新生成) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'schema': 'example_schema', 'version': 'example_version'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:38,289 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/message/push/example_schema/example_version +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: ComprehensiveURLCheckLLMCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' (综合URL规范与RESTful风格检查 (LLM)) for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001) +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的LLM参数。 +2025-05-26 14:59:38,289 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'schema': 'example_schema', 'version': 'example_version'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:38,289 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - 向LLM发送请求,评估路径: /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} (POST) +2025-05-26 14:59:38,289 - ddms_compliance_suite.llm_utils.llm_service - DEBUG - LLM API Request Payload: +{ + "model": "qwen-plus", + "messages": [ + { + "role": "system", + "content": "你是一位API设计评审专家,专注于评估API的URL规范性和RESTful风格。你的输出必须是严格的JSON格式。" + }, + { + "role": "user", + "content": "\n请扮演一位资深的API设计评审员。我将提供一个API端点的路径模板、HTTP方法以及可能的接口名称。\n请根据以下石油行业API设计规范评估此API端点,并以严格的JSON格式返回您的评估结果。\nJSON对象应包含一个名为 \"assessments\" 的键,其值为一个对象列表,每个对象代表对一个标准的评估,包含 \"standard_name\" (字符串), \"is_compliant\" (布尔值), 和 \"reason\" (字符串) 三个键。\n\nAPI端点信息:\n- HTTP方法: POST\n- 路径模板: /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}\n- 路径中提取的参数名: [dms_instance_code, schema, version]\n\n评估标准:\n\n1. **接口名称规范 (接口名称需要你从路径模板中提取,一般是路径中除了参数名以外的最后的一个单词)**:\n - 规则: 采用'动词+名词'结构,明确业务语义 (例如: GetWellLog, SubmitSeismicJob)。\n - standard_name: \"interface_naming_convention\"\n\n2. **HTTP方法使用规范**:\n - 规则: 遵循RESTful规范:GET用于数据检索, POST用于创建资源, PUT用于更新资源, DELETE用于删除资源。\n - standard_name: \"http_method_usage\"\n\n3. **URL路径结构规范**:\n - 规则: 格式为 `<前缀>/<专业领域>/v<版本号>/<资源类型>` (例如: /logging/v1.2/wells, /seismicprospecting/v1.0/datasets)。\n - 前缀: 示例: /api/dms\n - 专业领域: 专业领域示例: seismicprospecting, welllogging, reservoirevaluation\n - 版本号: 语义化版本,例如 v1, v1.0, v2.1.3。\n - 资源类型: 通常为名词复数。\n - standard_name: \"url_path_structure\"\n\n4. **URL路径参数命名规范**:\n - 规则: 路径参数(如果存在)必须使用全小写字母(可以是一个单词)或小写字母加下划线命名(这是多个单词的情况),并能反映资源的唯一标识 (例如: {well_id},{version},{schema})。\n - standard_name: \"url_path_parameter_naming\"\n\n5. **资源命名规范 (在路径中)**:\n - 规则: 资源集合应使用名词的复数形式表示 (例如 `/wells`, `/logs`);应优先使用石油行业的标准术语 (例如用 `trajectory` 而非 `path` 来表示井轨迹)。\n - standard_name: \"resource_naming_in_path\"\n - standard_name: \"resource\"\n - standard_name: \"schema\"\n - standard_name: \"version\"\n\n\n\n请确保您的输出是一个可以被 `json.loads()` 直接解析的JSON对象。\n例如:\n{\n \"assessments\": [\n {\n \"standard_name\": \"interface_naming_convention\",\n \"is_compliant\": true,\n \"reason\": \"接口名称 'GetWellboreTrajectory' 符合动词+名词结构。\"\n },\n {\n \"standard_name\": \"http_method_usage\",\n \"is_compliant\": true,\n \"reason\": \"GET方法用于检索资源,符合规范。\"\n }\n // ... 其他标准的评估 ...\n ]\n}\n" + } + ], + "max_tokens": 1024, + "temperature": 0.2 +} +2025-05-26 14:59:51,690 - ddms_compliance_suite.llm_utils.llm_service - DEBUG - LLM API Response: +{ + "choices": [ + { + "message": { + "role": "assistant", + "content": "```json\n{\n \"assessments\": [\n {\n \"standard_name\": \"interface_naming_convention\",\n \"is_compliant\": false,\n \"reason\": \"接口名称 'push' 不符合动词+名词结构,建议改为更明确的业务语义名称,例如 'PushMessage'。\"\n },\n {\n \"standard_name\": \"http_method_usage\",\n \"is_compliant\": true,\n \"reason\": \"POST方法用于创建资源(如推送消息),符合RESTful规范。\"\n },\n {\n \"standard_name\": \"url_path_structure\",\n \"is_compliant\": true,\n \"reason\": \"URL路径结构为 '/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}',符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式。\"\n },\n {\n \"standard_name\": \"url_path_parameter_naming\",\n \"is_compliant\": true,\n \"reason\": \"路径参数 {dms_instance_code}, {schema}, {version} 均使用小写字母或下划线命名,符合命名规范。\"\n },\n {\n \"standard_name\": \"resource_naming_in_path\",\n \"is_compliant\": false,\n \"reason\": \"路径中的 'message' 和 'push' 不完全符合石油行业标准术语,建议使用更具体的资源集合名称(如 'messages')。此外,'push' 应作为操作而非资源名处理。\"\n }\n ]\n}\n```" + }, + "finish_reason": "stop", + "index": 0, + "logprobs": null + } + ], + "object": "chat.completion", + "usage": { + "prompt_tokens": 810, + "completion_tokens": 324, + "total_tokens": 1134, + "prompt_tokens_details": { + "cached_tokens": 0 + } + }, + "created": 1748242792, + "system_fingerprint": null, + "model": "qwen-plus", + "id": "chatcmpl-08a69523-abf1-9131-bcc6-b5d6f16e94ec" +} +2025-05-26 14:59:51,692 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - WARNING - LLM评估 - 标准 'interface_naming_convention' for '/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}': 不符合。原因: 接口名称 'push' 不符合动词+名词结构,建议改为更明确的业务语义名称,例如 'PushMessage'。 +2025-05-26 14:59:51,692 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'http_method_usage' for '/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}': 符合。原因: POST方法用于创建资源(如推送消息),符合RESTful规范。 +2025-05-26 14:59:51,692 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'url_path_structure' for '/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}': 符合。原因: URL路径结构为 '/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}',符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式。 +2025-05-26 14:59:51,692 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'url_path_parameter_naming' for '/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}': 符合。原因: 路径参数 {dms_instance_code}, {schema}, {version} 均使用小写字母或下划线命名,符合命名规范。 +2025-05-26 14:59:51,692 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - WARNING - LLM评估 - 标准 'resource_naming_in_path' for '/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}': 不符合。原因: 路径中的 'message' 和 'push' 不完全符合石油行业标准术语,建议使用更具体的资源集合名称(如 'messages')。此外,'push' 应作为操作而非资源名处理。 +2025-05-26 14:59:51,766 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 执行失败。 +2025-05-26 14:59:51,767 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 执行完毕,状态: 失败 +2025-05-26 14:59:51,767 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-CORE-FUNC-001' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,767 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:51,767 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:51,767 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: ResponseSchemaValidationCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:51,767 - testcase.TC-CORE-FUNC-001 - INFO - 测试用例 'TC-CORE-FUNC-001' 已为端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 初始化。 +2025-05-26 14:59:51,767 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-CORE-FUNC-001' (Response Body JSON Schema Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,767 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-CORE-FUNC-001) +2025-05-26 14:59:51,767 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的LLM参数。 +2025-05-26 14:59:51,767 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'schema': 'example_schema', 'version': 'example_version'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:51,793 - testcase.TC-CORE-FUNC-001 - INFO - 响应包含JSON体,但在API规范中未找到针对状态码 200 的JSON schema。跳过schema验证。 +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-CORE-FUNC-001' 执行成功。 +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-CORE-FUNC-001' 执行完毕,状态: 通过 +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-SECURITY-001' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: HTTPSMandatoryCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:51,793 - testcase.TC-SECURITY-001 - INFO - 测试用例 'TC-SECURITY-001' 已为端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 初始化。 +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-SECURITY-001' (HTTPS Protocol Mandatory Verification) for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-SECURITY-001) +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的LLM参数。 +2025-05-26 14:59:51,793 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'schema': 'example_schema', 'version': 'example_version'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:51,793 - testcase.TC-SECURITY-001 - WARNING - 原始URL 'http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/message/push/example_schema/example_version' 不是HTTPS。跳过此测试用例的URL修改。 +2025-05-26 14:59:51,812 - testcase.TC-SECURITY-001 - ERROR - 安全漏洞:API允许通过HTTP成功响应 (200)。 +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-SECURITY-001' 执行失败。 +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-SECURITY-001' 执行完毕,状态: 失败 +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4001-QUERY' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: TypeMismatchQueryParamCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY _try_find_mismatch_target_in_query >>> STARTED +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - DEBUG - 开始为端点 POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 初始化查询参数类型不匹配测试的目标字段查找。 +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY _try_find_mismatch_target_in_query >>> Parameters to be processed: [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'schema', 'in': 'path', 'required': True, 'description': '', 'schema': {'type': 'string', 'example': 'example_schema'}}, {'name': 'version', 'in': 'path', 'required': True, 'description': '', 'schema': {'type': 'string', 'example': 'example_version'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - DEBUG - 传入的参数列表 (在 TC-ERROR-4001-QUERY中): [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'schema', 'in': 'path', 'required': True, 'description': '', 'schema': {'type': 'string', 'example': 'example_schema'}}, {'name': 'version', 'in': 'path', 'required': True, 'description': '', 'schema': {'type': 'string', 'example': 'example_version'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - INFO - 最终,在端点 POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 的查询参数中,均未找到可用于测试类型不匹配的字段。 +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY __INIT__ >>> STARTED +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - DEBUG - 开始为端点 POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 初始化查询参数类型不匹配测试的目标字段查找。 +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY __INIT__ >>> Parameters to be processed: [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'schema', 'in': 'path', 'required': True, 'description': '', 'schema': {'type': 'string', 'example': 'example_schema'}}, {'name': 'version', 'in': 'path', 'required': True, 'description': '', 'schema': {'type': 'string', 'example': 'example_version'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - DEBUG - 传入的参数列表 (在 TC-ERROR-4001-QUERY中): [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'schema', 'in': 'path', 'required': True, 'description': '', 'schema': {'type': 'string', 'example': 'example_schema'}}, {'name': 'version', 'in': 'path', 'required': True, 'description': '', 'schema': {'type': 'string', 'example': 'example_version'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - INFO - 最终,在端点 POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 的查询参数中,均未找到可用于测试类型不匹配的字段。 +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4001-QUERY' (Error Code 4001 - Query Parameter Type Mismatch Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-ERROR-4001-QUERY) +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的LLM参数。 +2025-05-26 14:59:51,812 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'schema': 'example_schema', 'version': 'example_version'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: generate_headers, current keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - DEBUG - TC-ERROR-4001-QUERY is focused on query parameters, generate_request_body will not modify the body. +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: modify_request_url, original URL: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/message/push/example_schema/example_version +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - DEBUG - Test case 'TC-ERROR-4001-QUERY' did not modify the URL via modify_request_url hook. +2025-05-26 14:59:51,812 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_url, url: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/message/push/example_schema/example_version +2025-05-26 14:59:51,813 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_headers, header keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 14:59:51,813 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_body, body type: +2025-05-26 14:59:51,832 - testcase.TC-ERROR-4001-QUERY - INFO - TC-ERROR-4001-QUERY: 由于未识别到目标查询参数字段,跳过类型不匹配测试。 +2025-05-26 14:59:51,832 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: check_performance, elapsed: 0.01949787139892578 +2025-05-26 14:59:51,832 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-ERROR-4001-QUERY' 执行成功。 +2025-05-26 14:59:51,832 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 执行完毕,状态: 通过 +2025-05-26 14:59:51,832 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4001-BODY' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,832 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:51,833 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:51,833 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: TypeMismatchBodyCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - CRITICAL - TC-ERROR-4001-BODY __INIT__ >>> STARTED +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - 开始为端点 POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 初始化请求体类型不匹配测试的目标字段查找。 +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - 从顶层 'requestBody' 中获取到 schema: ['properties', 'type', '$$ref'] +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - 最终用于检查的请求体 schema: ['properties', 'type', '$$ref'] +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Enter _find_target_field_in_schema for base_path: '', schema_to_search keys: ['properties', 'type', '$$ref'] +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: '', Resolved Schema Type: 'object', Keys: ['properties', 'type', '$$ref'] +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: '', Type is 'object'. Checking properties: ['isSearchCount', 'query'] +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'isSearchCount', Property Schema (Original): {'default': True, 'description': '是否统计总条数', 'type': 'boolean'} +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'isSearchCount', Property Schema (Resolved): {'default': True, 'description': '是否统计总条数', 'type': 'boolean'} +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'isSearchCount', Resolved Property Type: 'boolean' +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - INFO - 目标字段(请求体): 'isSearchCount' (原始类型: 'boolean') FOUND! +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - INFO - 类型不匹配测试的目标字段(请求体): isSearchCount,原始类型: boolean +2025-05-26 14:59:51,833 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4001-BODY' (Error Code 4001 - Request Body Type Mismatch Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,833 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-ERROR-4001-BODY) +2025-05-26 14:59:51,833 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的LLM参数。 +2025-05-26 14:59:51,833 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'schema': 'example_schema', 'version': 'example_version'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - TC-ERROR-4001-BODY is focused on request body, generate_query_params will not modify query parameters. +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: generate_headers, current keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - 准备修改请求体以测试类型不匹配。目标路径: ['isSearchCount'], 原始类型: boolean +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - INFO - 在路径 ['isSearchCount'] (键 'isSearchCount') 处,将值从 'True' 修改为 'not-a-boolean' (原始类型: boolean) +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: modify_request_url, original URL: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/message/push/example_schema/example_version +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Test case 'TC-ERROR-4001-BODY' did not modify the URL via modify_request_url hook. +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_url, url: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/message/push/example_schema/example_version +2025-05-26 14:59:51,833 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_headers, header keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 14:59:51,834 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_body, body type: +2025-05-26 14:59:51,850 - testcase.TC-ERROR-4001-BODY - WARNING - TC-ERROR-4001-BODY: 类型不匹配测试失败。字段: body.isSearchCount, 期望状态码: [400, 422], 实际: 200。 +2025-05-26 14:59:51,851 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: check_performance, elapsed: 0.016666889190673828 +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4001-BODY' 执行失败。 +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 执行完毕,状态: 失败 +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4003-BODY' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: MissingRequiredFieldBodyCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:51,851 - testcase.TC-ERROR-4003-BODY - INFO - 在请求体 schema 中未找到可用于测试 "必填字段缺失" 的字段。 +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4003-BODY' (Error Code 4003 - Missing Required Request Body Field Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-ERROR-4003-BODY) +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的LLM参数。 +2025-05-26 14:59:51,851 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'schema': 'example_schema', 'version': 'example_version'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:51,872 - testcase.TC-ERROR-4003-BODY - INFO - 由于未识别到可移除的必填请求体字段,跳过此测试用例。 +2025-05-26 14:59:51,872 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-ERROR-4003-BODY' 执行成功。 +2025-05-26 14:59:51,872 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 执行完毕,状态: 通过 +2025-05-26 14:59:51,872 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4003-QUERY' for 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,872 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:51,872 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:51,872 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: MissingRequiredFieldQueryCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:51,873 - testcase.TC-ERROR-4003-QUERY - INFO - 在此端点规范中未找到可用于测试 "必填查询参数缺失" 的字段。 +2025-05-26 14:59:51,873 - testcase.TC-ERROR-4003-QUERY - INFO - 测试用例 TC-ERROR-4003-QUERY (Error Code 4003 - Missing Required Query Parameter Validation) 已针对端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 初始化。Target param to remove: None +2025-05-26 14:59:51,873 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4003-QUERY' (Error Code 4003 - Missing Required Query Parameter Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' +2025-05-26 14:59:51,873 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version} 准备初始请求数据 (TC: TC-ERROR-4003-QUERY) +2025-05-26 14:59:51,873 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 的LLM参数。 +2025-05-26 14:59:51,873 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_message_push_schema_version_135716] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'schema': 'example_schema', 'version': 'example_version'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:51,895 - testcase.TC-ERROR-4003-QUERY - INFO - 由于未识别到可移除的必填查询参数,跳过此测试用例。 +2025-05-26 14:59:51,895 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-ERROR-4003-QUERY' 执行成功。 +2025-05-26 14:59:51,895 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 执行完毕,状态: 通过 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}' 测试完成,最终状态: 失败 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} (地质单元列表查询) +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}'。 +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 发现了 8 个适用的测试用例: ['TC-STATUS-001', 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001', 'TC-CORE-FUNC-001', 'TC-SECURITY-001', 'TC-ERROR-4001-QUERY', 'TC-ERROR-4001-BODY', 'TC-ERROR-4003-BODY', 'TC-ERROR-4003-QUERY'] +2025-05-26 14:59:51,896 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 14:59:51,897 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:51,897 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:51,897 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: StatusCode200Check 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:51,897 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 初始化。 +2025-05-26 14:59:51,897 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-STATUS-001' (基本状态码 200 检查) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 14:59:51,897 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-STATUS-001) +2025-05-26 14:59:51,897 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的参数未在缓存中找到,开始生成。 +2025-05-26 14:59:51,898 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用常规方法或LLM未启用,为路径参数。 +2025-05-26 14:59:51,898 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用常规方法生成 path 参数。 +2025-05-26 14:59:51,898 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用 schema 中的 'example' 值 for (context: path parameter 'dms_instance_code'): example_dms_instance_code +2025-05-26 14:59:51,898 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用 schema 中的 'example' 值 for (context: path parameter 'version'): 1.0.0 +2025-05-26 14:59:51,898 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 常规方法生成的 path 参数: {'dms_instance_code': 'example_dms_instance_code', 'version': '1.0.0'} +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用常规方法或LLM未启用,为查询参数。 +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用常规方法生成 query 参数。 +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: query parameter 'pageNo'): example_string +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: query parameter 'pageSize'): example_string +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 常规方法生成的 query 参数: {'pageNo': 'example_string', 'pageSize': 'example_string'} +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用常规方法或LLM未启用,为头部参数。 +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用常规方法生成 header 参数。 +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用常规方法或LLM未启用/不适用,为请求体。 +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 object 类型数据 for (context: requestBody). Properties: ['isSearchCount', 'query'] +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 使用 schema 中的 'default' 值 for (context: requestBody.isSearchCount): True +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 object 类型数据 for (context: requestBody.query). Properties: ['dataRegions', 'fields', 'filter', 'groupFields', 'groupFilter', 'sort'] +2025-05-26 14:59:51,899 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 array 类型数据 for (context: requestBody.query.dataRegions). Items schema: {'description': '数据域,如:JD、DG、TL', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.dataRegions[0]): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 array 类型数据 for (context: requestBody.query.fields). Items schema: {'description': '查询的字段', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.fields[0]): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 object 类型数据 for (context: requestBody.query.filter). Properties: ['key', 'logic', 'realValue', 'singleValue', 'subFilter', 'symbol'] +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.filter.key): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.filter.logic): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 array 类型数据 for (context: requestBody.query.filter.realValue). Items schema: {'description': '条件值', 'type': 'object', 'properties': {}}, minItems: 1 +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 object 类型数据 for (context: requestBody.query.filter.realValue[0]). Properties: [] +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 object 类型数据 for (context: requestBody.query.filter.singleValue). Properties: [] +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 array 类型数据 for (context: requestBody.query.filter.subFilter). Items schema: {'$ref': '#/components/schemas/FilterVO', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.filter.subFilter[0]): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.filter.symbol): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 array 类型数据 for (context: requestBody.query.groupFields). Items schema: {'description': '分组字段group by', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.groupFields[0]): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 object 类型数据 for (context: requestBody.query.groupFilter). Properties: ['key', 'logic', 'realValue', 'singleValue', 'subFilter', 'symbol'] +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.groupFilter.key): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.groupFilter.logic): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 array 类型数据 for (context: requestBody.query.groupFilter.realValue). Items schema: {'description': '条件值', 'type': 'object', 'properties': {}}, minItems: 1 +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 object 类型数据 for (context: requestBody.query.groupFilter.realValue[0]). Properties: [] +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 object 类型数据 for (context: requestBody.query.groupFilter.singleValue). Properties: [] +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 array 类型数据 for (context: requestBody.query.groupFilter.subFilter). Items schema: {'$ref': '#/components/schemas/FilterVO', 'type': 'string'}, minItems: 1 +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.groupFilter.subFilter[0]): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 string 类型数据 ('') for (context: requestBody.query.groupFilter.symbol): example_string +2025-05-26 14:59:51,900 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 生成 object 类型数据 for (context: requestBody.query.sort). Properties: [] +2025-05-26 14:59:51,901 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的参数已生成并存入缓存。 +2025-05-26 14:59:51,901 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] (新生成) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'version': '1.0.0'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:51,919 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit/1.0.0 +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: ComprehensiveURLCheckLLMCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' (综合URL规范与RESTful风格检查 (LLM)) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001) +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的LLM参数。 +2025-05-26 14:59:51,919 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'version': '1.0.0'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 14:59:51,919 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - 向LLM发送请求,评估路径: /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} (POST) +2025-05-26 14:59:51,920 - ddms_compliance_suite.llm_utils.llm_service - DEBUG - LLM API Request Payload: +{ + "model": "qwen-plus", + "messages": [ + { + "role": "system", + "content": "你是一位API设计评审专家,专注于评估API的URL规范性和RESTful风格。你的输出必须是严格的JSON格式。" + }, + { + "role": "user", + "content": "\n请扮演一位资深的API设计评审员。我将提供一个API端点的路径模板、HTTP方法以及可能的接口名称。\n请根据以下石油行业API设计规范评估此API端点,并以严格的JSON格式返回您的评估结果。\nJSON对象应包含一个名为 \"assessments\" 的键,其值为一个对象列表,每个对象代表对一个标准的评估,包含 \"standard_name\" (字符串), \"is_compliant\" (布尔值), 和 \"reason\" (字符串) 三个键。\n\nAPI端点信息:\n- HTTP方法: POST\n- 路径模板: /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}\n- 路径中提取的参数名: [dms_instance_code, version]\n\n评估标准:\n\n1. **接口名称规范 (接口名称需要你从路径模板中提取,一般是路径中除了参数名以外的最后的一个单词)**:\n - 规则: 采用'动词+名词'结构,明确业务语义 (例如: GetWellLog, SubmitSeismicJob)。\n - standard_name: \"interface_naming_convention\"\n\n2. **HTTP方法使用规范**:\n - 规则: 遵循RESTful规范:GET用于数据检索, POST用于创建资源, PUT用于更新资源, DELETE用于删除资源。\n - standard_name: \"http_method_usage\"\n\n3. **URL路径结构规范**:\n - 规则: 格式为 `<前缀>/<专业领域>/v<版本号>/<资源类型>` (例如: /logging/v1.2/wells, /seismicprospecting/v1.0/datasets)。\n - 前缀: 示例: /api/dms\n - 专业领域: 专业领域示例: seismicprospecting, welllogging, reservoirevaluation\n - 版本号: 语义化版本,例如 v1, v1.0, v2.1.3。\n - 资源类型: 通常为名词复数。\n - standard_name: \"url_path_structure\"\n\n4. **URL路径参数命名规范**:\n - 规则: 路径参数(如果存在)必须使用全小写字母(可以是一个单词)或小写字母加下划线命名(这是多个单词的情况),并能反映资源的唯一标识 (例如: {well_id},{version},{schema})。\n - standard_name: \"url_path_parameter_naming\"\n\n5. **资源命名规范 (在路径中)**:\n - 规则: 资源集合应使用名词的复数形式表示 (例如 `/wells`, `/logs`);应优先使用石油行业的标准术语 (例如用 `trajectory` 而非 `path` 来表示井轨迹)。\n - standard_name: \"resource_naming_in_path\"\n - standard_name: \"resource\"\n - standard_name: \"schema\"\n - standard_name: \"version\"\n\n\n\n请确保您的输出是一个可以被 `json.loads()` 直接解析的JSON对象。\n例如:\n{\n \"assessments\": [\n {\n \"standard_name\": \"interface_naming_convention\",\n \"is_compliant\": true,\n \"reason\": \"接口名称 'GetWellboreTrajectory' 符合动词+名词结构。\"\n },\n {\n \"standard_name\": \"http_method_usage\",\n \"is_compliant\": true,\n \"reason\": \"GET方法用于检索资源,符合规范。\"\n }\n // ... 其他标准的评估 ...\n ]\n}\n" + } + ], + "max_tokens": 1024, + "temperature": 0.2 +} +2025-05-26 15:00:11,869 - ddms_compliance_suite.llm_utils.llm_service - DEBUG - LLM API Response: +{ + "choices": [ + { + "message": { + "role": "assistant", + "content": "{\n \"assessments\": [\n {\n \"standard_name\": \"interface_naming_convention\",\n \"is_compliant\": false,\n \"reason\": \"接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。\"\n },\n {\n \"standard_name\": \"http_method_usage\",\n \"is_compliant\": true,\n \"reason\": \"POST方法用于创建资源,符合RESTful规范。\"\n },\n {\n \"standard_name\": \"url_path_structure\",\n \"is_compliant\": false,\n \"reason\": \"路径模板不符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的结构,其中 `cd_geo_unit` 不是石油行业的标准术语,且未明确表示资源集合的复数形式。\"\n },\n {\n \"standard_name\": \"url_path_parameter_naming\",\n \"is_compliant\": true,\n \"reason\": \"路径参数 `{dms_instance_code}` 和 `{version}` 均使用小写字母命名,符合命名规则。\"\n },\n {\n \"standard_name\": \"resource_naming_in_path\",\n \"is_compliant\": false,\n \"reason\": \"`cd_geo_unit` 应使用名词复数形式表示资源集合,并优先采用石油行业的标准术语。例如,可以考虑更改为 `geo_units` 或其他更具体的术语。\"\n }\n ]\n}" + }, + "finish_reason": "stop", + "index": 0, + "logprobs": null + } + ], + "object": "chat.completion", + "usage": { + "prompt_tokens": 807, + "completion_tokens": 298, + "total_tokens": 1105, + "prompt_tokens_details": { + "cached_tokens": 0 + } + }, + "created": 1748242812, + "system_fingerprint": null, + "model": "qwen-plus", + "id": "chatcmpl-3ce6bbde-e584-9c6f-9024-897fcdee1dad" +} +2025-05-26 15:00:11,874 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - WARNING - LLM评估 - 标准 'interface_naming_convention' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}': 不符合。原因: 接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。 +2025-05-26 15:00:11,875 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'http_method_usage' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}': 符合。原因: POST方法用于创建资源,符合RESTful规范。 +2025-05-26 15:00:11,875 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - WARNING - LLM评估 - 标准 'url_path_structure' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}': 不符合。原因: 路径模板不符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的结构,其中 `cd_geo_unit` 不是石油行业的标准术语,且未明确表示资源集合的复数形式。 +2025-05-26 15:00:11,875 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'url_path_parameter_naming' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}': 符合。原因: 路径参数 `{dms_instance_code}` 和 `{version}` 均使用小写字母命名,符合命名规则。 +2025-05-26 15:00:11,875 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - WARNING - LLM评估 - 标准 'resource_naming_in_path' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}': 不符合。原因: `cd_geo_unit` 应使用名词复数形式表示资源集合,并优先采用石油行业的标准术语。例如,可以考虑更改为 `geo_units` 或其他更具体的术语。 +2025-05-26 15:00:11,957 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 执行失败。 +2025-05-26 15:00:11,957 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 执行完毕,状态: 失败 +2025-05-26 15:00:11,957 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-CORE-FUNC-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:11,957 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:11,957 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:11,957 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: ResponseSchemaValidationCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:11,957 - testcase.TC-CORE-FUNC-001 - INFO - 测试用例 'TC-CORE-FUNC-001' 已为端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 初始化。 +2025-05-26 15:00:11,958 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-CORE-FUNC-001' (Response Body JSON Schema Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:11,958 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-CORE-FUNC-001) +2025-05-26 15:00:11,958 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的LLM参数。 +2025-05-26 15:00:11,958 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'version': '1.0.0'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:11,984 - testcase.TC-CORE-FUNC-001 - INFO - 响应包含JSON体,但在API规范中未找到针对状态码 200 的JSON schema。跳过schema验证。 +2025-05-26 15:00:11,984 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-CORE-FUNC-001' 执行成功。 +2025-05-26 15:00:11,984 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-CORE-FUNC-001' 执行完毕,状态: 通过 +2025-05-26 15:00:11,984 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-SECURITY-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:11,984 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:11,984 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:11,984 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: HTTPSMandatoryCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:11,984 - testcase.TC-SECURITY-001 - INFO - 测试用例 'TC-SECURITY-001' 已为端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 初始化。 +2025-05-26 15:00:11,985 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-SECURITY-001' (HTTPS Protocol Mandatory Verification) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:11,985 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-SECURITY-001) +2025-05-26 15:00:11,985 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的LLM参数。 +2025-05-26 15:00:11,985 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'version': '1.0.0'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:11,985 - testcase.TC-SECURITY-001 - WARNING - 原始URL 'http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit/1.0.0' 不是HTTPS。跳过此测试用例的URL修改。 +2025-05-26 15:00:12,004 - testcase.TC-SECURITY-001 - ERROR - 安全漏洞:API允许通过HTTP成功响应 (200)。 +2025-05-26 15:00:12,004 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-SECURITY-001' 执行失败。 +2025-05-26 15:00:12,004 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-SECURITY-001' 执行完毕,状态: 失败 +2025-05-26 15:00:12,004 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4001-QUERY' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:12,004 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:12,004 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:12,004 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: TypeMismatchQueryParamCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:12,004 - testcase.TC-ERROR-4001-QUERY - DEBUG - Test case 'TC-ERROR-4001-QUERY' initialized for endpoint: POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} +2025-05-26 15:00:12,004 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY _try_find_mismatch_target_in_query >>> STARTED +2025-05-26 15:00:12,004 - testcase.TC-ERROR-4001-QUERY - DEBUG - 开始为端点 POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 初始化查询参数类型不匹配测试的目标字段查找。 +2025-05-26 15:00:12,004 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY _try_find_mismatch_target_in_query >>> Parameters to be processed: [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'version', 'in': 'path', 'required': True, 'description': '交换模型版本', 'schema': {'type': 'string', 'example': '1.0.0'}}, {'name': 'pageNo', 'in': 'query', 'required': False, 'description': '页码(从1开始)', 'schema': {'type': 'string'}}, {'name': 'pageSize', 'in': 'query', 'required': False, 'description': '分页大小(最大值200)', 'schema': {'type': 'string'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - 传入的参数列表 (在 TC-ERROR-4001-QUERY中): [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'version', 'in': 'path', 'required': True, 'description': '交换模型版本', 'schema': {'type': 'string', 'example': '1.0.0'}}, {'name': 'pageNo', 'in': 'query', 'required': False, 'description': '页码(从1开始)', 'schema': {'type': 'string'}}, {'name': 'pageSize', 'in': 'query', 'required': False, 'description': '分页大小(最大值200)', 'schema': {'type': 'string'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - 检查查询参数: 'pageNo' +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - 查询参数 'pageNo' 包含嵌套 schema,尝试在其内部查找简单类型字段。 +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - INFO - 目标字段(查询参数 - schema为简单类型): pageNo,原始类型: string +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY __INIT__ >>> STARTED +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - 开始为端点 POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 初始化查询参数类型不匹配测试的目标字段查找。 +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY __INIT__ >>> Parameters to be processed: [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'version', 'in': 'path', 'required': True, 'description': '交换模型版本', 'schema': {'type': 'string', 'example': '1.0.0'}}, {'name': 'pageNo', 'in': 'query', 'required': False, 'description': '页码(从1开始)', 'schema': {'type': 'string'}}, {'name': 'pageSize', 'in': 'query', 'required': False, 'description': '分页大小(最大值200)', 'schema': {'type': 'string'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - 传入的参数列表 (在 TC-ERROR-4001-QUERY中): [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'version', 'in': 'path', 'required': True, 'description': '交换模型版本', 'schema': {'type': 'string', 'example': '1.0.0'}}, {'name': 'pageNo', 'in': 'query', 'required': False, 'description': '页码(从1开始)', 'schema': {'type': 'string'}}, {'name': 'pageSize', 'in': 'query', 'required': False, 'description': '分页大小(最大值200)', 'schema': {'type': 'string'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - 检查查询参数: 'pageNo' +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - 查询参数 'pageNo' 包含嵌套 schema,尝试在其内部查找简单类型字段。 +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - INFO - 目标字段(查询参数 - schema为简单类型): pageNo,原始类型: string +2025-05-26 15:00:12,005 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4001-QUERY' (Error Code 4001 - Query Parameter Type Mismatch Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:12,005 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-ERROR-4001-QUERY) +2025-05-26 15:00:12,005 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的LLM参数。 +2025-05-26 15:00:12,005 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'version': '1.0.0'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - 准备修改查询参数以测试类型不匹配。目标路径: ['pageNo'], 原始类型: string +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - INFO - 在查询参数路径 ['pageNo'] (键 'pageNo') 处,将值从 'example_string' 修改为 '12345' (原始类型: string) +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: generate_headers, current keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - TC-ERROR-4001-QUERY is focused on query parameters, generate_request_body will not modify the body. +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: modify_request_url, original URL: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit/1.0.0 +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - Test case 'TC-ERROR-4001-QUERY' did not modify the URL via modify_request_url hook. +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_url, url: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit/1.0.0 +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_headers, header keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 15:00:12,005 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_body, body type: +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-QUERY - WARNING - TC-ERROR-4001-QUERY: 类型不匹配测试失败。字段: query.pageNo, 期望状态码: [400, 422], 实际: 200。 +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: check_performance, elapsed: 0.03896188735961914 +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4001-QUERY' 执行失败。 +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 执行完毕,状态: 失败 +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4001-BODY' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: TypeMismatchBodyCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - Test case 'TC-ERROR-4001-BODY' initialized for endpoint: POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - CRITICAL - TC-ERROR-4001-BODY __INIT__ >>> STARTED +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - 开始为端点 POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 初始化请求体类型不匹配测试的目标字段查找。 +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - 从顶层 'requestBody' 中获取到 schema: ['properties', 'type', '$$ref'] +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - 最终用于检查的请求体 schema: ['properties', 'type', '$$ref'] +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - Enter _find_target_field_in_schema for base_path: '', schema_to_search keys: ['properties', 'type', '$$ref'] +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: '', Resolved Schema Type: 'object', Keys: ['properties', 'type', '$$ref'] +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: '', Type is 'object'. Checking properties: ['isSearchCount', 'query'] +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'isSearchCount', Property Schema (Original): {'default': True, 'description': '是否统计总条数', 'type': 'boolean'} +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'isSearchCount', Property Schema (Resolved): {'default': True, 'description': '是否统计总条数', 'type': 'boolean'} +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'isSearchCount', Resolved Property Type: 'boolean' +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - INFO - 目标字段(请求体): 'isSearchCount' (原始类型: 'boolean') FOUND! +2025-05-26 15:00:12,045 - testcase.TC-ERROR-4001-BODY - INFO - 类型不匹配测试的目标字段(请求体): isSearchCount,原始类型: boolean +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4001-BODY' (Error Code 4001 - Request Body Type Mismatch Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-ERROR-4001-BODY) +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的LLM参数。 +2025-05-26 15:00:12,045 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'version': '1.0.0'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:12,046 - testcase.TC-ERROR-4001-BODY - DEBUG - TC-ERROR-4001-BODY is focused on request body, generate_query_params will not modify query parameters. +2025-05-26 15:00:12,046 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: generate_headers, current keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 15:00:12,046 - testcase.TC-ERROR-4001-BODY - DEBUG - 准备修改请求体以测试类型不匹配。目标路径: ['isSearchCount'], 原始类型: boolean +2025-05-26 15:00:12,046 - testcase.TC-ERROR-4001-BODY - INFO - 在路径 ['isSearchCount'] (键 'isSearchCount') 处,将值从 'True' 修改为 'not-a-boolean' (原始类型: boolean) +2025-05-26 15:00:12,046 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: modify_request_url, original URL: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit/1.0.0 +2025-05-26 15:00:12,046 - testcase.TC-ERROR-4001-BODY - DEBUG - Test case 'TC-ERROR-4001-BODY' did not modify the URL via modify_request_url hook. +2025-05-26 15:00:12,046 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_url, url: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit/1.0.0 +2025-05-26 15:00:12,046 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_headers, header keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 15:00:12,046 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_body, body type: +2025-05-26 15:00:12,063 - testcase.TC-ERROR-4001-BODY - WARNING - TC-ERROR-4001-BODY: 类型不匹配测试失败。字段: body.isSearchCount, 期望状态码: [400, 422], 实际: 200。 +2025-05-26 15:00:12,063 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: check_performance, elapsed: 0.016969919204711914 +2025-05-26 15:00:12,063 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4001-BODY' 执行失败。 +2025-05-26 15:00:12,063 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 执行完毕,状态: 失败 +2025-05-26 15:00:12,063 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4003-BODY' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:12,063 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:12,063 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:12,063 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: MissingRequiredFieldBodyCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:12,064 - testcase.TC-ERROR-4003-BODY - INFO - 在请求体 schema 中未找到可用于测试 "必填字段缺失" 的字段。 +2025-05-26 15:00:12,064 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4003-BODY' (Error Code 4003 - Missing Required Request Body Field Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:12,064 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-ERROR-4003-BODY) +2025-05-26 15:00:12,064 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的LLM参数。 +2025-05-26 15:00:12,064 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'version': '1.0.0'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:12,081 - testcase.TC-ERROR-4003-BODY - INFO - 由于未识别到可移除的必填请求体字段,跳过此测试用例。 +2025-05-26 15:00:12,081 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-ERROR-4003-BODY' 执行成功。 +2025-05-26 15:00:12,081 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 执行完毕,状态: 通过 +2025-05-26 15:00:12,081 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4003-QUERY' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:12,081 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:12,081 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:12,081 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: MissingRequiredFieldQueryCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:12,081 - testcase.TC-ERROR-4003-QUERY - INFO - 在此端点规范中未找到可用于测试 "必填查询参数缺失" 的字段。 +2025-05-26 15:00:12,081 - testcase.TC-ERROR-4003-QUERY - INFO - 测试用例 TC-ERROR-4003-QUERY (Error Code 4003 - Missing Required Query Parameter Validation) 已针对端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 初始化。Target param to remove: None +2025-05-26 15:00:12,081 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4003-QUERY' (Error Code 4003 - Missing Required Query Parameter Validation) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' +2025-05-26 15:00:12,081 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version} 准备初始请求数据 (TC: TC-ERROR-4003-QUERY) +2025-05-26 15:00:12,081 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 的LLM参数。 +2025-05-26 15:00:12,082 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_version_135751] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code', 'version': '1.0.0'}, query_params={'pageNo': 'example_string', 'pageSize': 'example_string'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:12,098 - testcase.TC-ERROR-4003-QUERY - INFO - 由于未识别到可移除的必填查询参数,跳过此测试用例。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-ERROR-4003-QUERY' 执行成功。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 执行完毕,状态: 通过 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}' 测试完成,最终状态: 失败 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit (地质单元数据修改) +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' 发现了 8 个适用的测试用例: ['TC-STATUS-001', 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001', 'TC-CORE-FUNC-001', 'TC-SECURITY-001', 'TC-ERROR-4001-QUERY', 'TC-ERROR-4001-BODY', 'TC-ERROR-4003-BODY', 'TC-ERROR-4003-QUERY'] +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:12,098 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: StatusCode200Check 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:12,099 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-STATUS-001' (基本状态码 200 检查) for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-STATUS-001) +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数未在缓存中找到,开始生成。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 使用常规方法或LLM未启用,为路径参数。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 使用常规方法生成 path 参数。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 使用 schema 中的 'example' 值 for (context: path parameter 'dms_instance_code'): example_dms_instance_code +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 常规方法生成的 path 参数: {'dms_instance_code': 'example_dms_instance_code'} +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 使用常规方法或LLM未启用,为查询参数。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 使用常规方法生成 query 参数。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 使用 schema 中的 'example' 值 for (context: query parameter 'id'): dsid +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 常规方法生成的 query 参数: {'id': 'dsid'} +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 使用常规方法或LLM未启用,为头部参数。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 使用常规方法生成 header 参数。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 使用常规方法或LLM未启用/不适用,为请求体。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 object 类型数据 for (context: requestBody). Properties: ['version', 'data'] +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 string 类型数据 ('') for (context: requestBody.version): example_string +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 array 类型数据 for (context: requestBody.data). Items schema: {'type': 'object', 'properties': {'bsflag': {'type': 'number'}, 'wellCommonName': {'type': 'string'}, 'wellId': {'type': 'string'}, 'dataRegion': {'type': 'string'}}, 'required': ['bsflag', 'wellCommonName', 'wellId', 'dataRegion']}, minItems: 1 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 object 类型数据 for (context: requestBody.data[0]). Properties: ['bsflag', 'wellCommonName', 'wellId', 'dataRegion'] +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 number/integer 类型数据 for (context: requestBody.data[0].bsflag): 0.0 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 string 类型数据 ('') for (context: requestBody.data[0].wellCommonName): example_string +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 string 类型数据 ('') for (context: requestBody.data[0].wellId): example_string +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 生成 string 类型数据 ('') for (context: requestBody.data[0].dataRegion): example_string +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数已生成并存入缓存。 +2025-05-26 15:00:12,099 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] (新生成) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:12,119 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: ComprehensiveURLCheckLLMCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' (综合URL规范与RESTful风格检查 (LLM)) for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001) +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 从缓存加载了端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:12,119 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] (缓存加载) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:12,119 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - 向LLM发送请求,评估路径: /api/dms/{dms_instance_code}/v1/cd_geo_unit (PUT) +2025-05-26 15:00:12,120 - ddms_compliance_suite.llm_utils.llm_service - DEBUG - LLM API Request Payload: +{ + "model": "qwen-plus", + "messages": [ + { + "role": "system", + "content": "你是一位API设计评审专家,专注于评估API的URL规范性和RESTful风格。你的输出必须是严格的JSON格式。" + }, + { + "role": "user", + "content": "\n请扮演一位资深的API设计评审员。我将提供一个API端点的路径模板、HTTP方法以及可能的接口名称。\n请根据以下石油行业API设计规范评估此API端点,并以严格的JSON格式返回您的评估结果。\nJSON对象应包含一个名为 \"assessments\" 的键,其值为一个对象列表,每个对象代表对一个标准的评估,包含 \"standard_name\" (字符串), \"is_compliant\" (布尔值), 和 \"reason\" (字符串) 三个键。\n\nAPI端点信息:\n- HTTP方法: PUT\n- 路径模板: /api/dms/{dms_instance_code}/v1/cd_geo_unit\n- 路径中提取的参数名: [dms_instance_code]\n\n评估标准:\n\n1. **接口名称规范 (接口名称需要你从路径模板中提取,一般是路径中除了参数名以外的最后的一个单词)**:\n - 规则: 采用'动词+名词'结构,明确业务语义 (例如: GetWellLog, SubmitSeismicJob)。\n - standard_name: \"interface_naming_convention\"\n\n2. **HTTP方法使用规范**:\n - 规则: 遵循RESTful规范:GET用于数据检索, POST用于创建资源, PUT用于更新资源, DELETE用于删除资源。\n - standard_name: \"http_method_usage\"\n\n3. **URL路径结构规范**:\n - 规则: 格式为 `<前缀>/<专业领域>/v<版本号>/<资源类型>` (例如: /logging/v1.2/wells, /seismicprospecting/v1.0/datasets)。\n - 前缀: 示例: /api/dms\n - 专业领域: 专业领域示例: seismicprospecting, welllogging, reservoirevaluation\n - 版本号: 语义化版本,例如 v1, v1.0, v2.1.3。\n - 资源类型: 通常为名词复数。\n - standard_name: \"url_path_structure\"\n\n4. **URL路径参数命名规范**:\n - 规则: 路径参数(如果存在)必须使用全小写字母(可以是一个单词)或小写字母加下划线命名(这是多个单词的情况),并能反映资源的唯一标识 (例如: {well_id},{version},{schema})。\n - standard_name: \"url_path_parameter_naming\"\n\n5. **资源命名规范 (在路径中)**:\n - 规则: 资源集合应使用名词的复数形式表示 (例如 `/wells`, `/logs`);应优先使用石油行业的标准术语 (例如用 `trajectory` 而非 `path` 来表示井轨迹)。\n - standard_name: \"resource_naming_in_path\"\n - standard_name: \"resource\"\n - standard_name: \"schema\"\n - standard_name: \"version\"\n\n\n\n请确保您的输出是一个可以被 `json.loads()` 直接解析的JSON对象。\n例如:\n{\n \"assessments\": [\n {\n \"standard_name\": \"interface_naming_convention\",\n \"is_compliant\": true,\n \"reason\": \"接口名称 'GetWellboreTrajectory' 符合动词+名词结构。\"\n },\n {\n \"standard_name\": \"http_method_usage\",\n \"is_compliant\": true,\n \"reason\": \"GET方法用于检索资源,符合规范。\"\n }\n // ... 其他标准的评估 ...\n ]\n}\n" + } + ], + "max_tokens": 1024, + "temperature": 0.2 +} +2025-05-26 15:00:24,176 - ddms_compliance_suite.llm_utils.llm_service - DEBUG - LLM API Response: +{ + "choices": [ + { + "message": { + "role": "assistant", + "content": "{\n \"assessments\": [\n {\n \"standard_name\": \"interface_naming_convention\",\n \"is_compliant\": false,\n \"reason\": \"接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。\"\n },\n {\n \"standard_name\": \"http_method_usage\",\n \"is_compliant\": true,\n \"reason\": \"PUT方法用于更新资源,符合RESTful规范。\"\n },\n {\n \"standard_name\": \"url_path_structure\",\n \"is_compliant\": true,\n \"reason\": \"路径结构 '/api/dms/{dms_instance_code}/v1/cd_geo_unit' 符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式要求。\"\n },\n {\n \"standard_name\": \"url_path_parameter_naming\",\n \"is_compliant\": true,\n \"reason\": \"路径参数 '{dms_instance_code}' 使用了小写字母加下划线的命名方式,符合规范。\"\n },\n {\n \"standard_name\": \"resource_naming_in_path\",\n \"is_compliant\": false,\n \"reason\": \"'cd_geo_unit' 应使用复数形式表示资源集合,并且应优先使用石油行业的标准术语(例如 'geological_units')。\"\n }\n ]\n}" + }, + "finish_reason": "stop", + "index": 0, + "logprobs": null + } + ], + "object": "chat.completion", + "usage": { + "prompt_tokens": 803, + "completion_tokens": 285, + "total_tokens": 1088, + "prompt_tokens_details": { + "cached_tokens": 0 + } + }, + "created": 1748242824, + "system_fingerprint": null, + "model": "qwen-plus", + "id": "chatcmpl-432a0881-3667-9874-92bd-9a3c322cd4b6" +} +2025-05-26 15:00:24,177 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - WARNING - LLM评估 - 标准 'interface_naming_convention' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 不符合。原因: 接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。 +2025-05-26 15:00:24,177 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'http_method_usage' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 符合。原因: PUT方法用于更新资源,符合RESTful规范。 +2025-05-26 15:00:24,177 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'url_path_structure' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 符合。原因: 路径结构 '/api/dms/{dms_instance_code}/v1/cd_geo_unit' 符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式要求。 +2025-05-26 15:00:24,177 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'url_path_parameter_naming' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 符合。原因: 路径参数 '{dms_instance_code}' 使用了小写字母加下划线的命名方式,符合规范。 +2025-05-26 15:00:24,177 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - WARNING - LLM评估 - 标准 'resource_naming_in_path' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 不符合。原因: 'cd_geo_unit' 应使用复数形式表示资源集合,并且应优先使用石油行业的标准术语(例如 'geological_units')。 +2025-05-26 15:00:24,250 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 执行失败。 +2025-05-26 15:00:24,251 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 执行完毕,状态: 失败 +2025-05-26 15:00:24,251 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-CORE-FUNC-001' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,251 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:24,251 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:24,251 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: ResponseSchemaValidationCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:24,252 - testcase.TC-CORE-FUNC-001 - INFO - 测试用例 'TC-CORE-FUNC-001' 已为端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 +2025-05-26 15:00:24,253 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-CORE-FUNC-001' (Response Body JSON Schema Validation) for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,253 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-CORE-FUNC-001) +2025-05-26 15:00:24,254 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 从缓存加载了端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:24,254 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] (缓存加载) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:24,289 - testcase.TC-CORE-FUNC-001 - INFO - 将根据路径 'responses.200.content.application/json.schema' 的schema验证响应体。 +2025-05-26 15:00:24,296 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-CORE-FUNC-001' 执行成功。 +2025-05-26 15:00:24,296 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-CORE-FUNC-001' 执行完毕,状态: 通过 +2025-05-26 15:00:24,296 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-SECURITY-001' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,296 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:24,296 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:24,297 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: HTTPSMandatoryCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:24,297 - testcase.TC-SECURITY-001 - INFO - 测试用例 'TC-SECURITY-001' 已为端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 +2025-05-26 15:00:24,297 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-SECURITY-001' (HTTPS Protocol Mandatory Verification) for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,297 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-SECURITY-001) +2025-05-26 15:00:24,297 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 从缓存加载了端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:24,297 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] (缓存加载) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:24,297 - testcase.TC-SECURITY-001 - WARNING - 原始URL 'http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit' 不是HTTPS。跳过此测试用例的URL修改。 +2025-05-26 15:00:24,322 - testcase.TC-SECURITY-001 - ERROR - 安全漏洞:API允许通过HTTP成功响应 (200)。 +2025-05-26 15:00:24,323 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-SECURITY-001' 执行失败。 +2025-05-26 15:00:24,323 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-SECURITY-001' 执行完毕,状态: 失败 +2025-05-26 15:00:24,323 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4001-QUERY' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,323 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:24,323 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:24,323 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: TypeMismatchQueryParamCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - DEBUG - Test case 'TC-ERROR-4001-QUERY' initialized for endpoint: PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY _try_find_mismatch_target_in_query >>> STARTED +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - DEBUG - 开始为端点 PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit 初始化查询参数类型不匹配测试的目标字段查找。 +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY _try_find_mismatch_target_in_query >>> Parameters to be processed: [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'schema': {'type': 'string', 'example': 'dsid'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - DEBUG - 传入的参数列表 (在 TC-ERROR-4001-QUERY中): [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'schema': {'type': 'string', 'example': 'dsid'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - DEBUG - 检查查询参数: 'id' +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - DEBUG - 查询参数 'id' 包含嵌套 schema,尝试在其内部查找简单类型字段。 +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - INFO - 目标字段(查询参数 - schema为简单类型): id,原始类型: string +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY __INIT__ >>> STARTED +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - DEBUG - 开始为端点 PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit 初始化查询参数类型不匹配测试的目标字段查找。 +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY __INIT__ >>> Parameters to be processed: [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'schema': {'type': 'string', 'example': 'dsid'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - DEBUG - 传入的参数列表 (在 TC-ERROR-4001-QUERY中): [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'schema': {'type': 'string', 'example': 'dsid'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - DEBUG - 检查查询参数: 'id' +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - DEBUG - 查询参数 'id' 包含嵌套 schema,尝试在其内部查找简单类型字段。 +2025-05-26 15:00:24,323 - testcase.TC-ERROR-4001-QUERY - INFO - 目标字段(查询参数 - schema为简单类型): id,原始类型: string +2025-05-26 15:00:24,323 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4001-QUERY' (Error Code 4001 - Query Parameter Type Mismatch Validation) for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,323 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-ERROR-4001-QUERY) +2025-05-26 15:00:24,324 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 从缓存加载了端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:24,324 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] (缓存加载) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:24,324 - testcase.TC-ERROR-4001-QUERY - DEBUG - 准备修改查询参数以测试类型不匹配。目标路径: ['id'], 原始类型: string +2025-05-26 15:00:24,324 - testcase.TC-ERROR-4001-QUERY - INFO - 在查询参数路径 ['id'] (键 'id') 处,将值从 'dsid' 修改为 '12345' (原始类型: string) +2025-05-26 15:00:24,324 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: generate_headers, current keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 15:00:24,324 - testcase.TC-ERROR-4001-QUERY - DEBUG - TC-ERROR-4001-QUERY is focused on query parameters, generate_request_body will not modify the body. +2025-05-26 15:00:24,324 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: modify_request_url, original URL: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:24,324 - testcase.TC-ERROR-4001-QUERY - DEBUG - Test case 'TC-ERROR-4001-QUERY' did not modify the URL via modify_request_url hook. +2025-05-26 15:00:24,324 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_url, url: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:24,324 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_headers, header keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 15:00:24,324 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_body, body type: +2025-05-26 15:00:24,348 - testcase.TC-ERROR-4001-QUERY - WARNING - TC-ERROR-4001-QUERY: 类型不匹配测试失败。字段: query.id, 期望状态码: [400, 422], 实际: 200。 +2025-05-26 15:00:24,348 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: check_performance, elapsed: 0.02383112907409668 +2025-05-26 15:00:24,348 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4001-QUERY' 执行失败。 +2025-05-26 15:00:24,349 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 执行完毕,状态: 失败 +2025-05-26 15:00:24,349 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4001-BODY' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,349 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:24,349 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:24,349 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: TypeMismatchBodyCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:24,349 - testcase.TC-ERROR-4001-BODY - DEBUG - Test case 'TC-ERROR-4001-BODY' initialized for endpoint: PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit +2025-05-26 15:00:24,349 - testcase.TC-ERROR-4001-BODY - CRITICAL - TC-ERROR-4001-BODY __INIT__ >>> STARTED +2025-05-26 15:00:24,349 - testcase.TC-ERROR-4001-BODY - DEBUG - 开始为端点 PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit 初始化请求体类型不匹配测试的目标字段查找。 +2025-05-26 15:00:24,349 - testcase.TC-ERROR-4001-BODY - DEBUG - 从顶层 'requestBody' 中获取到 schema: ['$schema', 'type', 'properties'] +2025-05-26 15:00:24,349 - testcase.TC-ERROR-4001-BODY - DEBUG - 最终用于检查的请求体 schema: ['$schema', 'type', 'properties'] +2025-05-26 15:00:24,349 - testcase.TC-ERROR-4001-BODY - DEBUG - Enter _find_target_field_in_schema for base_path: '', schema_to_search keys: ['$schema', 'type', 'properties'] +2025-05-26 15:00:24,349 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: '', Resolved Schema Type: 'object', Keys: ['$schema', 'type', 'properties'] +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: '', Type is 'object'. Checking properties: ['version', 'data'] +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'version', Property Schema (Original): {'type': 'string'} +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'version', Property Schema (Resolved): {'type': 'string'} +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'version', Resolved Property Type: 'string' +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - INFO - 目标字段(请求体): 'version' (原始类型: 'string') FOUND! +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - INFO - 类型不匹配测试的目标字段(请求体): version,原始类型: string +2025-05-26 15:00:24,350 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4001-BODY' (Error Code 4001 - Request Body Type Mismatch Validation) for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,350 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-ERROR-4001-BODY) +2025-05-26 15:00:24,350 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 从缓存加载了端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:24,350 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] (缓存加载) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - TC-ERROR-4001-BODY is focused on request body, generate_query_params will not modify query parameters. +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: generate_headers, current keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - 准备修改请求体以测试类型不匹配。目标路径: ['version'], 原始类型: string +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - INFO - 在路径 ['version'] (键 'version') 处,将值从 'example_string' 修改为 '12345' (原始类型: string) +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: modify_request_url, original URL: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Test case 'TC-ERROR-4001-BODY' did not modify the URL via modify_request_url hook. +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_url, url: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_headers, header keys: ['Accept', 'Content-Type', 'tenant-id', 'Authorization'] +2025-05-26 15:00:24,350 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_body, body type: +2025-05-26 15:00:24,378 - testcase.TC-ERROR-4001-BODY - WARNING - TC-ERROR-4001-BODY: 类型不匹配测试失败。字段: body.version, 期望状态码: [400, 422], 实际: 200。 +2025-05-26 15:00:24,378 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: check_performance, elapsed: 0.026877880096435547 +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4001-BODY' 执行失败。 +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 执行完毕,状态: 失败 +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4003-BODY' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: MissingRequiredFieldBodyCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:24,378 - testcase.TC-ERROR-4003-BODY - INFO - 策略2: 在数组属性 'data' (路径 root) 的元素内找到必填字段: 'bsflag'. 将尝试移除路径: ['data', 0, 'bsflag'] +2025-05-26 15:00:24,378 - testcase.TC-ERROR-4003-BODY - INFO - 必填字段缺失测试的目标字段 (请求体): 'data.0.bsflag' +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4003-BODY' (Error Code 4003 - Missing Required Request Body Field Validation) for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-ERROR-4003-BODY) +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 从缓存加载了端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:24,378 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] (缓存加载) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:24,378 - testcase.TC-ERROR-4003-BODY - INFO - 为进行必填字段缺失测试,已从请求体中移除字段路径 'data.0.bsflag' (原值: '0.0')。 +2025-05-26 15:00:24,394 - testcase.TC-ERROR-4003-BODY - WARNING - 必填请求体字段缺失测试失败:期望状态码 [400, 422],实际为 200。移除的字段:'body.data.0.bsflag' +2025-05-26 15:00:24,394 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4003-BODY' 执行失败。 +2025-05-26 15:00:24,394 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 执行完毕,状态: 失败 +2025-05-26 15:00:24,395 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4003-QUERY' for 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,395 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:24,395 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:24,395 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: MissingRequiredFieldQueryCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:24,395 - testcase.TC-ERROR-4003-QUERY - INFO - 必填字段缺失测试的目标字段 (查询参数): 'id' +2025-05-26 15:00:24,395 - testcase.TC-ERROR-4003-QUERY - INFO - 测试用例 TC-ERROR-4003-QUERY (Error Code 4003 - Missing Required Query Parameter Validation) 已针对端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。Target param to remove: id +2025-05-26 15:00:24,395 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4003-QUERY' (Error Code 4003 - Missing Required Query Parameter Validation) for endpoint 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,395 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 开始为端点 PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-ERROR-4003-QUERY) +2025-05-26 15:00:24,395 - ddms_compliance_suite.test_orchestrator - INFO - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] 从缓存加载了端点 'PUT_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:24,396 - ddms_compliance_suite.test_orchestrator - DEBUG - [put__api_dms_dms_instance_code_v1_cd_geo_unit_135749] (缓存加载) 准备的请求数据: method=PUT, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:24,396 - testcase.TC-ERROR-4003-QUERY - INFO - 为进行必填查询参数缺失测试,已从查询参数中移除 'id' (原值: 'dsid')。 +2025-05-26 15:00:24,414 - testcase.TC-ERROR-4003-QUERY - WARNING - 必填查询参数缺失测试失败:期望状态码 [400, 422],实际为 200。移除的参数:'id' +2025-05-26 15:00:24,414 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4003-QUERY' 执行失败。 +2025-05-26 15:00:24,414 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 执行完毕,状态: 失败 +2025-05-26 15:00:24,414 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit' 测试完成,最终状态: 失败 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit (地质单元数据删除) +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' 发现了 8 个适用的测试用例: ['TC-STATUS-001', 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001', 'TC-CORE-FUNC-001', 'TC-SECURITY-001', 'TC-ERROR-4001-QUERY', 'TC-ERROR-4001-BODY', 'TC-ERROR-4003-BODY', 'TC-ERROR-4003-QUERY'] +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: StatusCode200Check 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:24,415 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-STATUS-001' (基本状态码 200 检查) for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-STATUS-001) +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数未在缓存中找到,开始生成。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 使用常规方法或LLM未启用,为路径参数。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 使用常规方法生成 path 参数。 +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 使用 schema 中的 'example' 值 for (context: path parameter 'dms_instance_code'): example_dms_instance_code +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 常规方法生成的 path 参数: {'dms_instance_code': 'example_dms_instance_code'} +2025-05-26 15:00:24,415 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 使用常规方法或LLM未启用,为查询参数。 +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 使用常规方法生成 query 参数。 +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 使用 schema 中的 'example' 值 for (context: query parameter 'id'): dsid +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 常规方法生成的 query 参数: {'id': 'dsid'} +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 使用常规方法或LLM未启用,为头部参数。 +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 使用常规方法生成 header 参数。 +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 使用常规方法或LLM未启用/不适用,为请求体。 +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 生成 object 类型数据 for (context: requestBody). Properties: ['version', 'data'] +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 生成 string 类型数据 ('') for (context: requestBody.version): example_string +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 生成 array 类型数据 for (context: requestBody.data). Items schema: {'type': 'string'}, minItems: 1 +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 生成 string 类型数据 ('') for (context: requestBody.data[0]): example_string +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数已生成并存入缓存。 +2025-05-26 15:00:24,416 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] (新生成) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:24,434 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: ComprehensiveURLCheckLLMCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' (综合URL规范与RESTful风格检查 (LLM)) for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001) +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 从缓存加载了端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:24,435 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] (缓存加载) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:24,436 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - 向LLM发送请求,评估路径: /api/dms/{dms_instance_code}/v1/cd_geo_unit (DELETE) +2025-05-26 15:00:24,436 - ddms_compliance_suite.llm_utils.llm_service - DEBUG - LLM API Request Payload: +{ + "model": "qwen-plus", + "messages": [ + { + "role": "system", + "content": "你是一位API设计评审专家,专注于评估API的URL规范性和RESTful风格。你的输出必须是严格的JSON格式。" + }, + { + "role": "user", + "content": "\n请扮演一位资深的API设计评审员。我将提供一个API端点的路径模板、HTTP方法以及可能的接口名称。\n请根据以下石油行业API设计规范评估此API端点,并以严格的JSON格式返回您的评估结果。\nJSON对象应包含一个名为 \"assessments\" 的键,其值为一个对象列表,每个对象代表对一个标准的评估,包含 \"standard_name\" (字符串), \"is_compliant\" (布尔值), 和 \"reason\" (字符串) 三个键。\n\nAPI端点信息:\n- HTTP方法: DELETE\n- 路径模板: /api/dms/{dms_instance_code}/v1/cd_geo_unit\n- 路径中提取的参数名: [dms_instance_code]\n\n评估标准:\n\n1. **接口名称规范 (接口名称需要你从路径模板中提取,一般是路径中除了参数名以外的最后的一个单词)**:\n - 规则: 采用'动词+名词'结构,明确业务语义 (例如: GetWellLog, SubmitSeismicJob)。\n - standard_name: \"interface_naming_convention\"\n\n2. **HTTP方法使用规范**:\n - 规则: 遵循RESTful规范:GET用于数据检索, POST用于创建资源, PUT用于更新资源, DELETE用于删除资源。\n - standard_name: \"http_method_usage\"\n\n3. **URL路径结构规范**:\n - 规则: 格式为 `<前缀>/<专业领域>/v<版本号>/<资源类型>` (例如: /logging/v1.2/wells, /seismicprospecting/v1.0/datasets)。\n - 前缀: 示例: /api/dms\n - 专业领域: 专业领域示例: seismicprospecting, welllogging, reservoirevaluation\n - 版本号: 语义化版本,例如 v1, v1.0, v2.1.3。\n - 资源类型: 通常为名词复数。\n - standard_name: \"url_path_structure\"\n\n4. **URL路径参数命名规范**:\n - 规则: 路径参数(如果存在)必须使用全小写字母(可以是一个单词)或小写字母加下划线命名(这是多个单词的情况),并能反映资源的唯一标识 (例如: {well_id},{version},{schema})。\n - standard_name: \"url_path_parameter_naming\"\n\n5. **资源命名规范 (在路径中)**:\n - 规则: 资源集合应使用名词的复数形式表示 (例如 `/wells`, `/logs`);应优先使用石油行业的标准术语 (例如用 `trajectory` 而非 `path` 来表示井轨迹)。\n - standard_name: \"resource_naming_in_path\"\n - standard_name: \"resource\"\n - standard_name: \"schema\"\n - standard_name: \"version\"\n\n\n\n请确保您的输出是一个可以被 `json.loads()` 直接解析的JSON对象。\n例如:\n{\n \"assessments\": [\n {\n \"standard_name\": \"interface_naming_convention\",\n \"is_compliant\": true,\n \"reason\": \"接口名称 'GetWellboreTrajectory' 符合动词+名词结构。\"\n },\n {\n \"standard_name\": \"http_method_usage\",\n \"is_compliant\": true,\n \"reason\": \"GET方法用于检索资源,符合规范。\"\n }\n // ... 其他标准的评估 ...\n ]\n}\n" + } + ], + "max_tokens": 1024, + "temperature": 0.2 +} +2025-05-26 15:00:48,176 - ddms_compliance_suite.llm_utils.llm_service - DEBUG - LLM API Response: +{ + "choices": [ + { + "message": { + "role": "assistant", + "content": "{\n \"assessments\": [\n {\n \"standard_name\": \"interface_naming_convention\",\n \"is_compliant\": false,\n \"reason\": \"接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。\"\n },\n {\n \"standard_name\": \"http_method_usage\",\n \"is_compliant\": true,\n \"reason\": \"DELETE方法用于删除资源,符合RESTful规范。\"\n },\n {\n \"standard_name\": \"url_path_structure\",\n \"is_compliant\": true,\n \"reason\": \"路径结构 '/api/dms/{dms_instance_code}/v1/cd_geo_unit' 符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式要求。\"\n },\n {\n \"standard_name\": \"url_path_parameter_naming\",\n \"is_compliant\": true,\n \"reason\": \"路径参数 '{dms_instance_code}' 使用了小写字母加下划线的命名方式,符合命名规范。\"\n },\n {\n \"standard_name\": \"resource_naming_in_path\",\n \"is_compliant\": false,\n \"reason\": \"资源名称 'cd_geo_unit' 应使用复数形式表示集合资源,并且建议使用更具体的石油行业术语(例如 'geological_units')。\"\n }\n ]\n}" + }, + "finish_reason": "stop", + "index": 0, + "logprobs": null + } + ], + "object": "chat.completion", + "usage": { + "prompt_tokens": 803, + "completion_tokens": 289, + "total_tokens": 1092, + "prompt_tokens_details": { + "cached_tokens": 0 + } + }, + "created": 1748242848, + "system_fingerprint": null, + "model": "qwen-plus", + "id": "chatcmpl-4879ac12-4f68-982c-be1d-85de8824af0f" +} +2025-05-26 15:00:48,177 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - WARNING - LLM评估 - 标准 'interface_naming_convention' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 不符合。原因: 接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。 +2025-05-26 15:00:48,178 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'http_method_usage' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 符合。原因: DELETE方法用于删除资源,符合RESTful规范。 +2025-05-26 15:00:48,178 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'url_path_structure' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 符合。原因: 路径结构 '/api/dms/{dms_instance_code}/v1/cd_geo_unit' 符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式要求。 +2025-05-26 15:00:48,178 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - LLM评估 - 标准 'url_path_parameter_naming' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 符合。原因: 路径参数 '{dms_instance_code}' 使用了小写字母加下划线的命名方式,符合命名规范。 +2025-05-26 15:00:48,178 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - WARNING - LLM评估 - 标准 'resource_naming_in_path' for '/api/dms/{dms_instance_code}/v1/cd_geo_unit': 不符合。原因: 资源名称 'cd_geo_unit' 应使用复数形式表示集合资源,并且建议使用更具体的石油行业术语(例如 'geological_units')。 +2025-05-26 15:00:48,298 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 执行失败。 +2025-05-26 15:00:48,299 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 执行完毕,状态: 失败 +2025-05-26 15:00:48,299 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-CORE-FUNC-001' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,299 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:48,299 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:48,299 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: ResponseSchemaValidationCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:48,299 - testcase.TC-CORE-FUNC-001 - INFO - 测试用例 'TC-CORE-FUNC-001' 已为端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 +2025-05-26 15:00:48,299 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-CORE-FUNC-001' (Response Body JSON Schema Validation) for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,299 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-CORE-FUNC-001) +2025-05-26 15:00:48,299 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 从缓存加载了端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:48,299 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] (缓存加载) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:48,324 - testcase.TC-CORE-FUNC-001 - INFO - 将根据路径 'responses.200.content.application/json.schema' 的schema验证响应体。 +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-CORE-FUNC-001' 执行成功。 +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-CORE-FUNC-001' 执行完毕,状态: 通过 +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-SECURITY-001' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: HTTPSMandatoryCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:48,324 - testcase.TC-SECURITY-001 - INFO - 测试用例 'TC-SECURITY-001' 已为端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-SECURITY-001' (HTTPS Protocol Mandatory Verification) for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-SECURITY-001) +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 从缓存加载了端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:48,324 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] (缓存加载) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:48,324 - testcase.TC-SECURITY-001 - WARNING - 原始URL 'http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit' 不是HTTPS。跳过此测试用例的URL修改。 +2025-05-26 15:00:48,351 - testcase.TC-SECURITY-001 - ERROR - 安全漏洞:API允许通过HTTP成功响应 (200)。 +2025-05-26 15:00:48,351 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-SECURITY-001' 执行失败。 +2025-05-26 15:00:48,351 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-SECURITY-001' 执行完毕,状态: 失败 +2025-05-26 15:00:48,351 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4001-QUERY' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,351 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:48,351 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:48,351 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: TypeMismatchQueryParamCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:48,351 - testcase.TC-ERROR-4001-QUERY - DEBUG - Test case 'TC-ERROR-4001-QUERY' initialized for endpoint: DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit +2025-05-26 15:00:48,351 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY _try_find_mismatch_target_in_query >>> STARTED +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - 开始为端点 DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit 初始化查询参数类型不匹配测试的目标字段查找。 +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY _try_find_mismatch_target_in_query >>> Parameters to be processed: [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'schema': {'type': 'string', 'example': 'dsid'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - 传入的参数列表 (在 TC-ERROR-4001-QUERY中): [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'schema': {'type': 'string', 'example': 'dsid'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - 检查查询参数: 'id' +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - 查询参数 'id' 包含嵌套 schema,尝试在其内部查找简单类型字段。 +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - INFO - 目标字段(查询参数 - schema为简单类型): id,原始类型: string +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY __INIT__ >>> STARTED +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - 开始为端点 DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit 初始化查询参数类型不匹配测试的目标字段查找。 +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - CRITICAL - TC-ERROR-4001-QUERY __INIT__ >>> Parameters to be processed: [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'schema': {'type': 'string', 'example': 'dsid'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - 传入的参数列表 (在 TC-ERROR-4001-QUERY中): [{'name': 'dms_instance_code', 'in': 'path', 'required': True, 'description': '注册实例code\n井筒中心 well_kd_wellbore_ideas01', 'schema': {'type': 'string', 'example': 'example_dms_instance_code'}}, {'name': 'id', 'in': 'query', 'required': True, 'description': '主键id的key', 'schema': {'type': 'string', 'example': 'dsid'}}, {'name': 'tenant-id', 'in': 'header', 'required': True, 'description': 'tenant-id (Only:undefined)', 'schema': {'type': 'string'}}, {'name': 'Authorization', 'in': 'header', 'required': True, 'description': 'Authorization (Only:undefined)', 'schema': {'type': 'string'}}] +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - 检查查询参数: 'id' +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - 查询参数 'id' 包含嵌套 schema,尝试在其内部查找简单类型字段。 +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - INFO - 目标字段(查询参数 - schema为简单类型): id,原始类型: string +2025-05-26 15:00:48,352 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4001-QUERY' (Error Code 4001 - Query Parameter Type Mismatch Validation) for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,352 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-ERROR-4001-QUERY) +2025-05-26 15:00:48,352 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 从缓存加载了端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:48,352 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] (缓存加载) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - 准备修改查询参数以测试类型不匹配。目标路径: ['id'], 原始类型: string +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - INFO - 在查询参数路径 ['id'] (键 'id') 处,将值从 'dsid' 修改为 '12345' (原始类型: string) +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: generate_headers, current keys: ['Accept', 'tenant-id', 'Authorization'] +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - TC-ERROR-4001-QUERY is focused on query parameters, generate_request_body will not modify the body. +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: modify_request_url, original URL: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - Test case 'TC-ERROR-4001-QUERY' did not modify the URL via modify_request_url hook. +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_url, url: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_headers, header keys: ['Accept', 'tenant-id', 'Authorization'] +2025-05-26 15:00:48,352 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: validate_request_body, body type: +2025-05-26 15:00:48,376 - testcase.TC-ERROR-4001-QUERY - WARNING - TC-ERROR-4001-QUERY: 类型不匹配测试失败。字段: query.id, 期望状态码: [400, 422], 实际: 200。 +2025-05-26 15:00:48,376 - testcase.TC-ERROR-4001-QUERY - DEBUG - Hook: check_performance, elapsed: 0.024329185485839844 +2025-05-26 15:00:48,376 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4001-QUERY' 执行失败。 +2025-05-26 15:00:48,376 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 执行完毕,状态: 失败 +2025-05-26 15:00:48,376 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4001-BODY' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,376 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:48,376 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:48,376 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: TypeMismatchBodyCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Test case 'TC-ERROR-4001-BODY' initialized for endpoint: DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - CRITICAL - TC-ERROR-4001-BODY __INIT__ >>> STARTED +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - 开始为端点 DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit 初始化请求体类型不匹配测试的目标字段查找。 +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - 从顶层 'requestBody' 中获取到 schema: ['$schema', 'type', 'properties'] +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - 最终用于检查的请求体 schema: ['$schema', 'type', 'properties'] +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Enter _find_target_field_in_schema for base_path: '', schema_to_search keys: ['$schema', 'type', 'properties'] +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: '', Resolved Schema Type: 'object', Keys: ['$schema', 'type', 'properties'] +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: '', Type is 'object'. Checking properties: ['version', 'data'] +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'version', Property Schema (Original): {'type': 'string', 'title': '版本号'} +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'version', Property Schema (Resolved): {'type': 'string', 'title': '版本号'} +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Path: 'version', Resolved Property Type: 'string' +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - INFO - 目标字段(请求体): 'version' (原始类型: 'string') FOUND! +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - INFO - 类型不匹配测试的目标字段(请求体): version,原始类型: string +2025-05-26 15:00:48,377 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4001-BODY' (Error Code 4001 - Request Body Type Mismatch Validation) for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,377 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-ERROR-4001-BODY) +2025-05-26 15:00:48,377 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 从缓存加载了端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:48,377 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] (缓存加载) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - TC-ERROR-4001-BODY is focused on request body, generate_query_params will not modify query parameters. +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: generate_headers, current keys: ['Accept', 'tenant-id', 'Authorization'] +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - 准备修改请求体以测试类型不匹配。目标路径: ['version'], 原始类型: string +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - INFO - 在路径 ['version'] (键 'version') 处,将值从 'example_string' 修改为 '12345' (原始类型: string) +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: modify_request_url, original URL: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Test case 'TC-ERROR-4001-BODY' did not modify the URL via modify_request_url hook. +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_url, url: http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_headers, header keys: ['Accept', 'tenant-id', 'Authorization'] +2025-05-26 15:00:48,377 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: validate_request_body, body type: +2025-05-26 15:00:48,428 - testcase.TC-ERROR-4001-BODY - WARNING - TC-ERROR-4001-BODY: 类型不匹配测试失败。字段: body.version, 期望状态码: [400, 422], 实际: 200。 +2025-05-26 15:00:48,428 - testcase.TC-ERROR-4001-BODY - DEBUG - Hook: check_performance, elapsed: 0.05131697654724121 +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4001-BODY' 执行失败。 +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 执行完毕,状态: 失败 +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4003-BODY' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: MissingRequiredFieldBodyCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:48,429 - testcase.TC-ERROR-4003-BODY - INFO - 在请求体 schema 中未找到可用于测试 "必填字段缺失" 的字段。 +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4003-BODY' (Error Code 4003 - Missing Required Request Body Field Validation) for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-ERROR-4003-BODY) +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 从缓存加载了端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:48,429 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] (缓存加载) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:48,484 - testcase.TC-ERROR-4003-BODY - INFO - 由于未识别到可移除的必填请求体字段,跳过此测试用例。 +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-ERROR-4003-BODY' 执行成功。 +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 执行完毕,状态: 通过 +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-ERROR-4003-QUERY' for 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: MissingRequiredFieldQueryCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:48,484 - testcase.TC-ERROR-4003-QUERY - INFO - 必填字段缺失测试的目标字段 (查询参数): 'id' +2025-05-26 15:00:48,484 - testcase.TC-ERROR-4003-QUERY - INFO - 测试用例 TC-ERROR-4003-QUERY (Error Code 4003 - Missing Required Query Parameter Validation) 已针对端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。Target param to remove: id +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-ERROR-4003-QUERY' (Error Code 4003 - Missing Required Query Parameter Validation) for endpoint 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 开始为端点 DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-ERROR-4003-QUERY) +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - INFO - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] 从缓存加载了端点 'DELETE_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:48,484 - ddms_compliance_suite.test_orchestrator - DEBUG - [delete__api_dms_dms_instance_code_v1_cd_geo_unit_135750] (缓存加载) 准备的请求数据: method=DELETE, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={'id': 'dsid'}, headers=['Accept', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:48,484 - testcase.TC-ERROR-4003-QUERY - INFO - 为进行必填查询参数缺失测试,已从查询参数中移除 'id' (原值: 'dsid')。 +2025-05-26 15:00:48,501 - testcase.TC-ERROR-4003-QUERY - WARNING - 必填查询参数缺失测试失败:期望状态码 [400, 422],实际为 200。移除的参数:'id' +2025-05-26 15:00:48,501 - ddms_compliance_suite.test_orchestrator - DEBUG -  ❌ 测试用例 'TC-ERROR-4003-QUERY' 执行失败。 +2025-05-26 15:00:48,501 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 执行完毕,状态: 失败 +2025-05-26 15:00:48,501 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit' 测试完成,最终状态: 失败 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - 开始为端点测试: POST /api/dms/{dms_instance_code}/v1/cd_geo_unit (地质单元数据添加) +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-STATUS-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-CORE-FUNC-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-SECURITY-001' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4001-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-BODY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_case_registry - DEBUG - 测试用例 'TC-ERROR-4003-QUERY' 适用于端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit'。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - 端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' 发现了 8 个适用的测试用例: ['TC-STATUS-001', 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001', 'TC-CORE-FUNC-001', 'TC-SECURITY-001', 'TC-ERROR-4001-QUERY', 'TC-ERROR-4001-BODY', 'TC-ERROR-4003-BODY', 'TC-ERROR-4003-QUERY'] +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-STATUS-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: StatusCode200Check 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:48,502 - testcase.TC-STATUS-001 - INFO - 测试用例 TC-STATUS-001 (基本状态码 200 检查) 已针对端点 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' 初始化。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-STATUS-001' (基本状态码 200 检查) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-STATUS-001) +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数未在缓存中找到,开始生成。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 使用常规方法或LLM未启用,为路径参数。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 使用常规方法生成 path 参数。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 使用 schema 中的 'example' 值 for (context: path parameter 'dms_instance_code'): example_dms_instance_code +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 常规方法生成的 path 参数: {'dms_instance_code': 'example_dms_instance_code'} +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 没有定义 query 参数。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 使用常规方法或LLM未启用,为头部参数。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 使用常规方法生成 header 参数。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 string 类型数据 ('') for (context: header parameter 'tenant-id'): example_string +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 string 类型数据 ('') for (context: header parameter 'Authorization'): example_string +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 常规方法生成的 header 参数: {'tenant-id': 'example_string', 'Authorization': 'example_string'} +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 使用常规方法或LLM未启用/不适用,为请求体。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 object 类型数据 for (context: requestBody). Properties: ['version', 'data'] +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 string 类型数据 ('') for (context: requestBody.version): example_string +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 array 类型数据 for (context: requestBody.data). Items schema: {'type': 'object', 'properties': {'bsflag': {'type': 'number', 'title': '必填字段删除标记'}, 'wellCommonName': {'type': 'string'}, 'wellId': {'type': 'string'}, 'dataRegion': {'type': 'string'}}, 'required': ['bsflag', 'wellCommonName', 'wellId', 'dataRegion']}, minItems: 1 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 object 类型数据 for (context: requestBody.data[0]). Properties: ['bsflag', 'wellCommonName', 'wellId', 'dataRegion'] +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 number/integer 类型数据 for (context: requestBody.data[0].bsflag): 0.0 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 string 类型数据 ('') for (context: requestBody.data[0].wellCommonName): example_string +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 string 类型数据 ('') for (context: requestBody.data[0].wellId): example_string +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 生成 string 类型数据 ('') for (context: requestBody.data[0].dataRegion): example_string +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的参数已生成并存入缓存。 +2025-05-26 15:00:48,502 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] (新生成) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:48,522 - testcase.TC-STATUS-001 - INFO - 状态码验证通过: 200 == 200 for http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - DEBUG -  ✅ 测试用例 'TC-STATUS-001' 执行成功。 +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - DEBUG - 测试用例 'TC-STATUS-001' 执行完毕,状态: 通过 +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' for 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - DEBUG - 成功通过 to_dict() 方法将类型为 的 endpoint_spec 转换为字典。 +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - DEBUG - Successfully converted/retrieved global_api_spec (type: ) to dict using .spec attribute. +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - DEBUG - 准备实例化测试用例类: ComprehensiveURLCheckLLMCase 使用 endpoint_spec (keys: ['method', 'path', 'title', 'summary', 'description', 'operationId', 'tags', 'parameters', 'requestBody', 'responses', '_source_format', '_yapi_id', '_yapi_raw_data', '_global_api_spec_for_resolution']) 和 global_api_spec (keys: ['yapi_categories']) +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - INFO - 开始执行测试用例 'TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001' (综合URL规范与RESTful风格检查 (LLM)) for endpoint 'POST /api/dms/{dms_instance_code}/v1/cd_geo_unit' +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 开始为端点 POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit 准备初始请求数据 (TC: TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001) +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - INFO - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] 从缓存加载了端点 'POST_/api/dms/{dms_instance_code}/v1/cd_geo_unit' 的LLM参数。 +2025-05-26 15:00:48,522 - ddms_compliance_suite.test_orchestrator - DEBUG - [post__api_dms_dms_instance_code_v1_cd_geo_unit_135748] (缓存加载) 准备的请求数据: method=POST, path_params={'dms_instance_code': 'example_dms_instance_code'}, query_params={}, headers=['Accept', 'Content-Type', 'tenant-id', 'Authorization'], body_type=dict +2025-05-26 15:00:48,522 - testcase.TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001 - INFO - 向LLM发送请求,评估路径: /api/dms/{dms_instance_code}/v1/cd_geo_unit (POST) +2025-05-26 15:00:48,522 - ddms_compliance_suite.llm_utils.llm_service - DEBUG - LLM API Request Payload: +{ + "model": "qwen-plus", + "messages": [ + { + "role": "system", + "content": "你是一位API设计评审专家,专注于评估API的URL规范性和RESTful风格。你的输出必须是严格的JSON格式。" + }, + { + "role": "user", + "content": "\n请扮演一位资深的API设计评审员。我将提供一个API端点的路径模板、HTTP方法以及可能的接口名称。\n请根据以下石油行业API设计规范评估此API端点,并以严格的JSON格式返回您的评估结果。\nJSON对象应包含一个名为 \"assessments\" 的键,其值为一个对象列表,每个对象代表对一个标准的评估,包含 \"standard_name\" (字符串), \"is_compliant\" (布尔值), 和 \"reason\" (字符串) 三个键。\n\nAPI端点信息:\n- HTTP方法: POST\n- 路径模板: /api/dms/{dms_instance_code}/v1/cd_geo_unit\n- 路径中提取的参数名: [dms_instance_code]\n\n评估标准:\n\n1. **接口名称规范 (接口名称需要你从路径模板中提取,一般是路径中除了参数名以外的最后的一个单词)**:\n - 规则: 采用'动词+名词'结构,明确业务语义 (例如: GetWellLog, SubmitSeismicJob)。\n - standard_name: \"interface_naming_convention\"\n\n2. **HTTP方法使用规范**:\n - 规则: 遵循RESTful规范:GET用于数据检索, POST用于创建资源, PUT用于更新资源, DELETE用于删除资源。\n - standard_name: \"http_method_usage\"\n\n3. **URL路径结构规范**:\n - 规则: 格式为 `<前缀>/<专业领域>/v<版本号>/<资源类型>` (例如: /logging/v1.2/wells, /seismicprospecting/v1.0/datasets)。\n - 前缀: 示例: /api/dms\n - 专业领域: 专业领域示例: seismicprospecting, welllogging, reservoirevaluation\n - 版本号: 语义化版本,例如 v1, v1.0, v2.1.3。\n - 资源类型: 通常为名词复数。\n - standard_name: \"url_path_structure\"\n\n4. **URL路径参数命名规范**:\n - 规则: 路径参数(如果存在)必须使用全小写字母(可以是一个单词)或小写字母加下划线命名(这是多个单词的情况),并能反映资源的唯一标识 (例如: {well_id},{version},{schema})。\n - standard_name: \"url_path_parameter_naming\"\n\n5. **资源命名规范 (在路径中)**:\n - 规则: 资源集合应使用名词的复数形式表示 (例如 `/wells`, `/logs`);应优先使用石油行业的标准术语 (例如用 `trajectory` 而非 `path` 来表示井轨迹)。\n - standard_name: \"resource_naming_in_path\"\n - standard_name: \"resource\"\n - standard_name: \"schema\"\n - standard_name: \"version\"\n\n\n\n请确保您的输出是一个可以被 `json.loads()` 直接解析的JSON对象。\n例如:\n{\n \"assessments\": [\n {\n \"standard_name\": \"interface_naming_convention\",\n \"is_compliant\": true,\n \"reason\": \"接口名称 'GetWellboreTrajectory' 符合动词+名词结构。\"\n },\n {\n \"standard_name\": \"http_method_usage\",\n \"is_compliant\": true,\n \"reason\": \"GET方法用于检索资源,符合规范。\"\n }\n // ... 其他标准的评估 ...\n ]\n}\n" + } + ], + "max_tokens": 1024, + "temperature": 0.2 +} diff --git a/test_report.json b/test_report.json index cb8f8f2..4f9bf37 100644 --- a/test_report.json +++ b/test_report.json @@ -1,45 +1,180 @@ { "summary_metadata": { - "start_time": "2025-05-23T12:04:50.246346", - "end_time": "2025-05-23T12:04:51.085891", - "duration_seconds": "0.84" + "start_time": "2025-05-26T14:55:54.921765", + "end_time": "2025-05-26T14:57:41.419930", + "duration_seconds": "106.50" }, "endpoint_stats": { "total_defined": 6, "total_tested": 6, - "passed": 3, - "failed": 3, + "passed": 0, + "failed": 6, "partial_success": 0, "error": 0, "skipped": 0, - "success_rate_percentage": "50.00" + "success_rate_percentage": "0.00" }, "test_case_stats": { - "total_applicable": 12, - "total_executed": 12, - "passed": 8, - "failed": 4, + "total_applicable": 48, + "total_executed": 48, + "passed": 23, + "failed": 25, "error_in_execution": 0, "skipped_during_endpoint_execution": 0, - "success_rate_percentage": "66.67" + "success_rate_percentage": "47.92" }, "detailed_results": [ { "endpoint_id": "POST /api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}", "endpoint_name": "数据推送接口", - "overall_status": "通过", - "duration_seconds": 0.208552, - "start_time": "2025-05-23T12:04:50.246523", - "end_time": "2025-05-23T12:04:50.455075", + "overall_status": "失败", + "duration_seconds": 18.219482, + "start_time": "2025-05-26T14:55:54.922121", + "end_time": "2025-05-26T14:56:13.141603", "executed_test_cases": [ + { + "test_case_id": "TC-STATUS-001", + "test_case_name": "基本状态码 200 检查", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.06069170800037682, + "timestamp": "2025-05-26T14:55:54.982899", + "validation_points": [ + { + "passed": true, + "message": "响应状态码为 200,符合预期 200。" + } + ] + }, + { + "test_case_id": "TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001", + "test_case_name": "综合URL规范与RESTful风格检查 (LLM)", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 17.99431545799598, + "timestamp": "2025-05-26T14:56:12.977385", + "validation_points": [ + { + "standard_name": "interface_naming_convention", + "is_compliant_by_llm": false, + "llm_reason": "接口名称 'push' 不符合动词+名词结构,建议改为更明确的业务语义名称,例如 'PushMessage'。", + "path_template": "/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}", + "http_method": "POST" + }, + { + "standard_name": "http_method_usage", + "is_compliant_by_llm": true, + "llm_reason": "POST方法用于创建资源,符合规范。", + "path_template": "/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}", + "http_method": "POST" + }, + { + "standard_name": "url_path_structure", + "is_compliant_by_llm": false, + "llm_reason": "路径模板不符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的结构。`/message/push/{schema}/{version}` 部分未清晰体现专业领域和资源集合。建议调整为类似 `/api/dms/v1/messages` 的形式。", + "path_template": "/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}", + "http_method": "POST" + }, + { + "standard_name": "url_path_parameter_naming", + "is_compliant_by_llm": false, + "llm_reason": "路径参数 `{schema}` 和 `{version}` 不符合全小写字母或小写字母加下划线命名规则。建议改为 `{message_schema}` 和 `{message_version}`。", + "path_template": "/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}", + "http_method": "POST" + }, + { + "standard_name": "resource_naming_in_path", + "is_compliant_by_llm": false, + "llm_reason": "`push` 是动作而非资源集合,且未使用复数形式表示资源。建议将资源部分改为石油行业标准术语的复数形式,例如 `/messages`。", + "path_template": "/api/dms/{dms_instance_code}/v1/message/push/{schema}/{version}", + "http_method": "POST" + } + ] + }, + { + "test_case_id": "TC-CORE-FUNC-001", + "test_case_name": "Response Body JSON Schema Validation", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.02988595818169415, + "timestamp": "2025-05-26T14:56:13.007527", + "validation_points": [ + { + "passed": true, + "message": "Schema验证步骤完成(未发现问题,或schema不适用/未为此响应定义)。" + } + ] + }, + { + "test_case_id": "TC-SECURITY-001", + "test_case_name": "HTTPS Protocol Mandatory Verification", + "test_case_severity": "严重", + "status": "失败", + "message": "", + "duration_seconds": 0.034258499974384904, + "timestamp": "2025-05-26T14:56:13.041896", + "validation_points": [ + { + "status_code": 200 + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-QUERY", + "test_case_name": "Error Code 4001 - Query Parameter Type Mismatch Validation", + "test_case_severity": "中", + "status": "通过", + "message": "", + "duration_seconds": 0.02747187507338822, + "timestamp": "2025-05-26T14:56:13.069433", + "validation_points": [ + { + "passed": true, + "message": "跳过测试:在查询参数中未找到合适的字段来测试类型不匹配。" + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-BODY", + "test_case_name": "Error Code 4001 - Request Body Type Mismatch Validation", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 0.023718375014141202, + "timestamp": "2025-05-26T14:56:13.093203", + "validation_points": [ + { + "status_code": 200, + "response_body": { + "code": 4, + "message": "non laborum culpa in do", + "data": { + "total": 9, + "list": [ + { + "dsid": "78", + "dataRegion": "enim aliqua", + "gasReleaseMon": null, + "gasReleaseYear": null, + "releaseGasCum": null + } + ] + } + } + } + ] + }, { "test_case_id": "TC-ERROR-4003-BODY", "test_case_name": "Error Code 4003 - Missing Required Request Body Field Validation", "test_case_severity": "高", "status": "通过", "message": "", - "duration_seconds": 0.14286641706712544, - "timestamp": "2025-05-23T12:04:50.389451", + "duration_seconds": 0.024443208007141948, + "timestamp": "2025-05-26T14:56:13.117697", "validation_points": [ { "passed": true, @@ -53,8 +188,8 @@ "test_case_severity": "高", "status": "通过", "message": "", - "duration_seconds": 0.06538325012661517, - "timestamp": "2025-05-23T12:04:50.454968", + "duration_seconds": 0.02363429218530655, + "timestamp": "2025-05-26T14:56:13.141391", "validation_points": [ { "passed": true, @@ -67,19 +202,183 @@ { "endpoint_id": "POST /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}", "endpoint_name": "地质单元列表查询", - "overall_status": "通过", - "duration_seconds": 0.149931, - "start_time": "2025-05-23T12:04:50.455128", - "end_time": "2025-05-23T12:04:50.605059", + "overall_status": "失败", + "duration_seconds": 23.64672, + "start_time": "2025-05-26T14:56:13.141802", + "end_time": "2025-05-26T14:56:36.788522", "executed_test_cases": [ + { + "test_case_id": "TC-STATUS-001", + "test_case_name": "基本状态码 200 检查", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.03243400016799569, + "timestamp": "2025-05-26T14:56:13.174754", + "validation_points": [ + { + "passed": true, + "message": "响应状态码为 200,符合预期 200。" + } + ] + }, + { + "test_case_id": "TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001", + "test_case_name": "综合URL规范与RESTful风格检查 (LLM)", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 23.482325999997556, + "timestamp": "2025-05-26T14:56:36.657293", + "validation_points": [ + { + "standard_name": "interface_naming_convention", + "is_compliant_by_llm": false, + "llm_reason": "接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}", + "http_method": "POST" + }, + { + "standard_name": "http_method_usage", + "is_compliant_by_llm": true, + "llm_reason": "POST方法用于创建资源,符合RESTful规范。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}", + "http_method": "POST" + }, + { + "standard_name": "url_path_structure", + "is_compliant_by_llm": false, + "llm_reason": "路径模板不符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式,`cd_geo_unit` 应该属于资源类型但未使用复数形式,且版本号 `{version}` 应为固定的语义化版本(如 v1.0)。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}", + "http_method": "POST" + }, + { + "standard_name": "url_path_parameter_naming", + "is_compliant_by_llm": true, + "llm_reason": "路径参数 `dms_instance_code` 和 `version` 均采用小写字母加下划线的命名方式,符合规范。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}", + "http_method": "POST" + }, + { + "standard_name": "resource_naming_in_path", + "is_compliant_by_llm": false, + "llm_reason": "资源名称 `cd_geo_unit` 使用了单数形式,应改为复数形式(如 `cd_geo_units`),以符合资源集合的命名规则。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}", + "http_method": "POST" + } + ] + }, + { + "test_case_id": "TC-CORE-FUNC-001", + "test_case_name": "Response Body JSON Schema Validation", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.024684624979272485, + "timestamp": "2025-05-26T14:56:36.682462", + "validation_points": [ + { + "passed": true, + "message": "Schema验证步骤完成(未发现问题,或schema不适用/未为此响应定义)。" + } + ] + }, + { + "test_case_id": "TC-SECURITY-001", + "test_case_name": "HTTPS Protocol Mandatory Verification", + "test_case_severity": "严重", + "status": "失败", + "message": "", + "duration_seconds": 0.023783958982676268, + "timestamp": "2025-05-26T14:56:36.706430", + "validation_points": [ + { + "status_code": 200 + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-QUERY", + "test_case_name": "Error Code 4001 - Query Parameter Type Mismatch Validation", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 0.019799625035375357, + "timestamp": "2025-05-26T14:56:36.726515", + "validation_points": [ + { + "status_code": 200, + "response_body": { + "code": 4, + "message": "reprehenderit do Ut", + "data": { + "total": 35, + "list": [ + { + "dsid": "93", + "dataRegion": "nisi", + "gasReleaseMon": null, + "gasReleaseYear": null, + "releaseGasCum": null + }, + { + "dsid": "68", + "dataRegion": "incididunt ad", + "gasReleaseMon": null, + "gasReleaseYear": null, + "releaseGasCum": null + } + ] + } + } + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-BODY", + "test_case_name": "Error Code 4001 - Request Body Type Mismatch Validation", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 0.018980999942868948, + "timestamp": "2025-05-26T14:56:36.745637", + "validation_points": [ + { + "status_code": 200, + "response_body": { + "code": 21, + "message": "nisi sed", + "data": { + "total": 67, + "list": [ + { + "dsid": "10", + "dataRegion": "incididunt", + "gasReleaseMon": null, + "gasReleaseYear": null, + "releaseGasCum": null + }, + { + "dsid": "7", + "dataRegion": "qui dolor", + "gasReleaseMon": null, + "gasReleaseYear": null, + "releaseGasCum": null + } + ] + } + } + } + ] + }, { "test_case_id": "TC-ERROR-4003-BODY", "test_case_name": "Error Code 4003 - Missing Required Request Body Field Validation", "test_case_severity": "高", "status": "通过", "message": "", - "duration_seconds": 0.0675940418150276, - "timestamp": "2025-05-23T12:04:50.522809", + "duration_seconds": 0.021431999979540706, + "timestamp": "2025-05-26T14:56:36.767326", "validation_points": [ { "passed": true, @@ -93,8 +392,8 @@ "test_case_severity": "高", "status": "通过", "message": "", - "duration_seconds": 0.08191158319823444, - "timestamp": "2025-05-23T12:04:50.604854", + "duration_seconds": 0.020639707800000906, + "timestamp": "2025-05-26T14:56:36.788257", "validation_points": [ { "passed": true, @@ -108,25 +407,153 @@ "endpoint_id": "PUT /api/dms/{dms_instance_code}/v1/cd_geo_unit", "endpoint_name": "地质单元数据修改", "overall_status": "失败", - "duration_seconds": 0.093809, - "start_time": "2025-05-23T12:04:50.605172", - "end_time": "2025-05-23T12:04:50.698981", + "duration_seconds": 18.066158, + "start_time": "2025-05-26T14:56:36.788795", + "end_time": "2025-05-26T14:56:54.854953", "executed_test_cases": [ + { + "test_case_id": "TC-STATUS-001", + "test_case_name": "基本状态码 200 检查", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.016432959120720625, + "timestamp": "2025-05-26T14:56:36.805789", + "validation_points": [ + { + "passed": true, + "message": "响应状态码为 200,符合预期 200。" + } + ] + }, + { + "test_case_id": "TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001", + "test_case_name": "综合URL规范与RESTful风格检查 (LLM)", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 17.868815666995943, + "timestamp": "2025-05-26T14:56:54.674934", + "validation_points": [ + { + "standard_name": "interface_naming_convention", + "is_compliant_by_llm": false, + "llm_reason": "接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "PUT" + }, + { + "standard_name": "http_method_usage", + "is_compliant_by_llm": true, + "llm_reason": "PUT方法用于更新资源,符合RESTful规范。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "PUT" + }, + { + "standard_name": "url_path_structure", + "is_compliant_by_llm": true, + "llm_reason": "URL路径结构 '/api/dms/{dms_instance_code}/v1/cd_geo_unit' 符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式要求。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "PUT" + }, + { + "standard_name": "url_path_parameter_naming", + "is_compliant_by_llm": true, + "llm_reason": "路径参数 '{dms_instance_code}' 使用了小写字母加下划线的命名方式,且能反映资源唯一标识。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "PUT" + }, + { + "standard_name": "resource_naming_in_path", + "is_compliant_by_llm": false, + "llm_reason": "资源类型 'cd_geo_unit' 应使用复数形式表示集合,并应优先采用石油行业的标准术语。当前命名可能不够清晰和标准化。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "PUT" + } + ] + }, + { + "test_case_id": "TC-CORE-FUNC-001", + "test_case_name": "Response Body JSON Schema Validation", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.03891233308240771, + "timestamp": "2025-05-26T14:56:54.714121", + "validation_points": [ + { + "passed": true, + "message": "针对 PUT http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit (状态码 200) 的响应体 conforms to the JSON schema." + } + ] + }, + { + "test_case_id": "TC-SECURITY-001", + "test_case_name": "HTTPS Protocol Mandatory Verification", + "test_case_severity": "严重", + "status": "失败", + "message": "", + "duration_seconds": 0.02052237489260733, + "timestamp": "2025-05-26T14:56:54.734798", + "validation_points": [ + { + "status_code": 200 + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-QUERY", + "test_case_name": "Error Code 4001 - Query Parameter Type Mismatch Validation", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 0.023687834152951837, + "timestamp": "2025-05-26T14:56:54.758558", + "validation_points": [ + { + "status_code": 200, + "response_body": { + "code": 12, + "message": "ad voluptate aliquip tempor irure", + "data": true + } + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-BODY", + "test_case_name": "Error Code 4001 - Request Body Type Mismatch Validation", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 0.02337870909832418, + "timestamp": "2025-05-26T14:56:54.781989", + "validation_points": [ + { + "status_code": 200, + "response_body": { + "code": 43, + "message": "reprehenderit Ut tempor dolor est", + "data": false + } + } + ] + }, { "test_case_id": "TC-ERROR-4003-BODY", "test_case_name": "Error Code 4003 - Missing Required Request Body Field Validation", "test_case_severity": "高", "status": "失败", "message": "", - "duration_seconds": 0.05135583318769932, - "timestamp": "2025-05-23T12:04:50.656709", + "duration_seconds": 0.024858917109668255, + "timestamp": "2025-05-26T14:56:54.806909", "validation_points": [ { "status_code": 200, "response_body": { - "code": 46, - "message": "id sint voluptate dolor amet", - "data": false + "code": 90, + "message": "laborum qui reprehenderit culpa do", + "data": true }, "removed_field": "body.data.0.bsflag" } @@ -138,15 +565,15 @@ "test_case_severity": "高", "status": "失败", "message": "", - "duration_seconds": 0.04197045904584229, - "timestamp": "2025-05-23T12:04:50.698867", + "duration_seconds": 0.04781029210425913, + "timestamp": "2025-05-26T14:56:54.854906", "validation_points": [ { "status_code": 200, "response_body": { - "code": 67, - "message": "Duis sint in", - "data": false + "code": 30, + "message": "mollit veniam laborum in fugiat", + "data": true }, "removed_field": "query.id" } @@ -158,18 +585,146 @@ "endpoint_id": "DELETE /api/dms/{dms_instance_code}/v1/cd_geo_unit", "endpoint_name": "地质单元数据删除", "overall_status": "失败", - "duration_seconds": 0.085489, - "start_time": "2025-05-23T12:04:50.699033", - "end_time": "2025-05-23T12:04:50.784522", + "duration_seconds": 16.398648, + "start_time": "2025-05-26T14:56:54.854996", + "end_time": "2025-05-26T14:57:11.253644", "executed_test_cases": [ + { + "test_case_id": "TC-STATUS-001", + "test_case_name": "基本状态码 200 检查", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.023985082982107997, + "timestamp": "2025-05-26T14:56:54.879085", + "validation_points": [ + { + "passed": true, + "message": "响应状态码为 200,符合预期 200。" + } + ] + }, + { + "test_case_id": "TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001", + "test_case_name": "综合URL规范与RESTful风格检查 (LLM)", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 16.23550120787695, + "timestamp": "2025-05-26T14:57:11.114734", + "validation_points": [ + { + "standard_name": "interface_naming_convention", + "is_compliant_by_llm": false, + "llm_reason": "接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "DELETE" + }, + { + "standard_name": "http_method_usage", + "is_compliant_by_llm": true, + "llm_reason": "DELETE方法用于删除资源,符合RESTful规范。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "DELETE" + }, + { + "standard_name": "url_path_structure", + "is_compliant_by_llm": true, + "llm_reason": "路径结构 '/api/dms/{dms_instance_code}/v1/cd_geo_unit' 符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式要求。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "DELETE" + }, + { + "standard_name": "url_path_parameter_naming", + "is_compliant_by_llm": true, + "llm_reason": "路径参数 '{dms_instance_code}' 使用了小写字母加下划线的命名方式,符合规范。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "DELETE" + }, + { + "standard_name": "resource_naming_in_path", + "is_compliant_by_llm": false, + "llm_reason": "资源类型 'cd_geo_unit' 应使用复数形式表示集合资源,并且应优先使用石油行业的标准术语。当前命名可能不够清晰或标准化。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "DELETE" + } + ] + }, + { + "test_case_id": "TC-CORE-FUNC-001", + "test_case_name": "Response Body JSON Schema Validation", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.025527833960950375, + "timestamp": "2025-05-26T14:57:11.140480", + "validation_points": [ + { + "passed": true, + "message": "针对 DELETE http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit (状态码 200) 的响应体 conforms to the JSON schema." + } + ] + }, + { + "test_case_id": "TC-SECURITY-001", + "test_case_name": "HTTPS Protocol Mandatory Verification", + "test_case_severity": "严重", + "status": "失败", + "message": "", + "duration_seconds": 0.02104416606016457, + "timestamp": "2025-05-26T14:57:11.161612", + "validation_points": [ + { + "status_code": 200 + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-QUERY", + "test_case_name": "Error Code 4001 - Query Parameter Type Mismatch Validation", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 0.027705333195626736, + "timestamp": "2025-05-26T14:57:11.189372", + "validation_points": [ + { + "status_code": 200, + "response_body": { + "code": 22, + "message": "qui laboris irure eu", + "data": false + } + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-BODY", + "test_case_name": "Error Code 4001 - Request Body Type Mismatch Validation", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 0.02069554105401039, + "timestamp": "2025-05-26T14:57:11.210122", + "validation_points": [ + { + "status_code": 200, + "response_body": { + "code": 52, + "message": "reprehenderit aute officia qui incididunt", + "data": true + } + } + ] + }, { "test_case_id": "TC-ERROR-4003-BODY", "test_case_name": "Error Code 4003 - Missing Required Request Body Field Validation", "test_case_severity": "高", "status": "通过", "message": "", - "duration_seconds": 0.04377300012856722, - "timestamp": "2025-05-23T12:04:50.742882", + "duration_seconds": 0.023130791960284114, + "timestamp": "2025-05-26T14:57:11.233298", "validation_points": [ { "passed": true, @@ -183,14 +738,14 @@ "test_case_severity": "高", "status": "失败", "message": "", - "duration_seconds": 0.04126858292147517, - "timestamp": "2025-05-23T12:04:50.784281", + "duration_seconds": 0.020238333148881793, + "timestamp": "2025-05-26T14:57:11.253601", "validation_points": [ { "status_code": 200, "response_body": { - "code": 95, - "message": "deserunt et enim", + "code": 13, + "message": "est labore aute consectetur ad", "data": true }, "removed_field": "query.id" @@ -203,24 +758,148 @@ "endpoint_id": "POST /api/dms/{dms_instance_code}/v1/cd_geo_unit", "endpoint_name": "地质单元数据添加", "overall_status": "失败", - "duration_seconds": 0.167005, - "start_time": "2025-05-23T12:04:50.784657", - "end_time": "2025-05-23T12:04:50.951662", + "duration_seconds": 12.880859, + "start_time": "2025-05-26T14:57:11.253685", + "end_time": "2025-05-26T14:57:24.134544", "executed_test_cases": [ + { + "test_case_id": "TC-STATUS-001", + "test_case_name": "基本状态码 200 检查", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.040113292168825865, + "timestamp": "2025-05-26T14:57:11.293916", + "validation_points": [ + { + "passed": true, + "message": "响应状态码为 200,符合预期 200。" + } + ] + }, + { + "test_case_id": "TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001", + "test_case_name": "综合URL规范与RESTful风格检查 (LLM)", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 12.704878584016114, + "timestamp": "2025-05-26T14:57:23.999175", + "validation_points": [ + { + "standard_name": "interface_naming_convention", + "is_compliant_by_llm": false, + "llm_reason": "接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "POST" + }, + { + "standard_name": "http_method_usage", + "is_compliant_by_llm": true, + "llm_reason": "POST方法用于创建资源,符合RESTful规范。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "POST" + }, + { + "standard_name": "url_path_structure", + "is_compliant_by_llm": true, + "llm_reason": "URL路径结构 '/api/dms/{dms_instance_code}/v1/cd_geo_unit' 符合 `<前缀>/<专业领域>/v<版本号>/<资源类型>` 的格式要求。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "POST" + }, + { + "standard_name": "url_path_parameter_naming", + "is_compliant_by_llm": true, + "llm_reason": "路径参数 '{dms_instance_code}' 使用了小写字母加下划线的命名方式,符合规范。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "POST" + }, + { + "standard_name": "resource_naming_in_path", + "is_compliant_by_llm": false, + "llm_reason": "'cd_geo_unit' 是单数形式,应改为复数形式以表示资源集合,例如 'cd_geo_units'。此外,术语是否为石油行业标准术语需要进一步确认。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit", + "http_method": "POST" + } + ] + }, + { + "test_case_id": "TC-CORE-FUNC-001", + "test_case_name": "Response Body JSON Schema Validation", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.026565458858385682, + "timestamp": "2025-05-26T14:57:24.025911", + "validation_points": [ + { + "passed": true, + "message": "Schema验证步骤完成(未发现问题,或schema不适用/未为此响应定义)。" + } + ] + }, + { + "test_case_id": "TC-SECURITY-001", + "test_case_name": "HTTPS Protocol Mandatory Verification", + "test_case_severity": "严重", + "status": "失败", + "message": "", + "duration_seconds": 0.017684708116576076, + "timestamp": "2025-05-26T14:57:24.043672", + "validation_points": [ + { + "status_code": 200 + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-QUERY", + "test_case_name": "Error Code 4001 - Query Parameter Type Mismatch Validation", + "test_case_severity": "中", + "status": "通过", + "message": "", + "duration_seconds": 0.01757129211910069, + "timestamp": "2025-05-26T14:57:24.061299", + "validation_points": [ + { + "passed": true, + "message": "跳过测试:在查询参数中未找到合适的字段来测试类型不匹配。" + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-BODY", + "test_case_name": "Error Code 4001 - Request Body Type Mismatch Validation", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 0.01608758303336799, + "timestamp": "2025-05-26T14:57:24.077435", + "validation_points": [ + { + "status_code": 200, + "response_body": { + "code": 27, + "message": "sit ut ullamco pariatur in", + "data": false + } + } + ] + }, { "test_case_id": "TC-ERROR-4003-BODY", "test_case_name": "Error Code 4003 - Missing Required Request Body Field Validation", "test_case_severity": "高", "status": "失败", "message": "", - "duration_seconds": 0.06845587491989136, - "timestamp": "2025-05-23T12:04:50.853268", + "duration_seconds": 0.01908508292399347, + "timestamp": "2025-05-26T14:57:24.096592", "validation_points": [ { "status_code": 200, "response_body": { - "code": 76, - "message": "et sunt deserunt", + "code": 16, + "message": "ut sit enim", "data": false }, "removed_field": "body.data.0.bsflag" @@ -233,8 +912,8 @@ "test_case_severity": "高", "status": "通过", "message": "", - "duration_seconds": 0.09789391607046127, - "timestamp": "2025-05-23T12:04:50.951331", + "duration_seconds": 0.0376933328807354, + "timestamp": "2025-05-26T14:57:24.134494", "validation_points": [ { "passed": true, @@ -247,19 +926,161 @@ { "endpoint_id": "GET /api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}", "endpoint_name": "地质单元查询详情", - "overall_status": "通过", - "duration_seconds": 0.134108, - "start_time": "2025-05-23T12:04:50.951739", - "end_time": "2025-05-23T12:04:51.085847", + "overall_status": "失败", + "duration_seconds": 17.285321, + "start_time": "2025-05-26T14:57:24.134588", + "end_time": "2025-05-26T14:57:41.419909", "executed_test_cases": [ + { + "test_case_id": "TC-STATUS-001", + "test_case_name": "基本状态码 200 检查", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.01687712501734495, + "timestamp": "2025-05-26T14:57:24.151591", + "validation_points": [ + { + "passed": true, + "message": "响应状态码为 200,符合预期 200。" + } + ] + }, + { + "test_case_id": "TC-NORMATIVE-URL-LLM-COMPREHENSIVE-001", + "test_case_name": "综合URL规范与RESTful风格检查 (LLM)", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 17.150162916164845, + "timestamp": "2025-05-26T14:57:41.301902", + "validation_points": [ + { + "standard_name": "interface_naming_convention", + "is_compliant_by_llm": false, + "llm_reason": "接口名称 'cd_geo_unit' 不符合动词+名词结构,无法明确表达业务语义。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}", + "http_method": "GET" + }, + { + "standard_name": "http_method_usage", + "is_compliant_by_llm": true, + "llm_reason": "GET方法用于检索资源,符合RESTful规范。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}", + "http_method": "GET" + }, + { + "standard_name": "url_path_structure", + "is_compliant_by_llm": false, + "llm_reason": "路径模板中的专业领域部分 '/dms/{dms_instance_code}/v1/cd_geo_unit' 不符合 `<专业领域>/v<版本号>/<资源类型>` 的结构要求,且 `cd_geo_unit` 不是有效的资源集合表示。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}", + "http_method": "GET" + }, + { + "standard_name": "url_path_parameter_naming", + "is_compliant_by_llm": true, + "llm_reason": "路径参数 {dms_instance_code}, {version}, {id} 均使用了小写字母或下划线命名,并能反映资源的唯一标识。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}", + "http_method": "GET" + }, + { + "standard_name": "resource_naming_in_path", + "is_compliant_by_llm": false, + "llm_reason": "`cd_geo_unit` 使用了单数形式,应改为复数形式(如 `cd_geo_units`),并且未使用石油行业的标准术语来描述资源。", + "path_template": "/api/dms/{dms_instance_code}/v1/cd_geo_unit/{version}/{id}", + "http_method": "GET" + } + ] + }, + { + "test_case_id": "TC-CORE-FUNC-001", + "test_case_name": "Response Body JSON Schema Validation", + "test_case_severity": "严重", + "status": "通过", + "message": "", + "duration_seconds": 0.02449162513948977, + "timestamp": "2025-05-26T14:57:41.326585", + "validation_points": [ + { + "passed": true, + "message": "针对 GET http://127.0.0.1:4523/m1/6389742-6086420-default/api/dms/example_dms_instance_code/v1/cd_geo_unit/1.0.0/example_id (状态码 200) 的响应体 conforms to the JSON schema." + } + ] + }, + { + "test_case_id": "TC-SECURITY-001", + "test_case_name": "HTTPS Protocol Mandatory Verification", + "test_case_severity": "严重", + "status": "失败", + "message": "", + "duration_seconds": 0.025857542175799608, + "timestamp": "2025-05-26T14:57:41.352535", + "validation_points": [ + { + "status_code": 200 + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-QUERY", + "test_case_name": "Error Code 4001 - Query Parameter Type Mismatch Validation", + "test_case_severity": "中", + "status": "通过", + "message": "", + "duration_seconds": 0.017973707988858223, + "timestamp": "2025-05-26T14:57:41.370605", + "validation_points": [ + { + "passed": true, + "message": "跳过测试:在查询参数中未找到合适的字段来测试类型不匹配。" + } + ] + }, + { + "test_case_id": "TC-ERROR-4001-BODY", + "test_case_name": "Error Code 4001 - Request Body Type Mismatch Validation", + "test_case_severity": "中", + "status": "失败", + "message": "", + "duration_seconds": 0.016390540869906545, + "timestamp": "2025-05-26T14:57:41.387060", + "validation_points": [ + { + "status_code": 200, + "response_body": { + "code": 76, + "message": "mollit culpa laboris", + "data": { + "total": 69, + "list": [ + { + "dsid": "100", + "dataRegion": "mollit ullamco", + "gasReleaseMon": null, + "gasReleaseYear": null, + "releaseGasCum": null + }, + { + "dsid": "62", + "dataRegion": "proident Ut adipisicing sed", + "gasReleaseMon": null, + "gasReleaseYear": null, + "releaseGasCum": null + } + ] + } + } + } + ] + }, { "test_case_id": "TC-ERROR-4003-BODY", "test_case_name": "Error Code 4003 - Missing Required Request Body Field Validation", "test_case_severity": "高", "status": "通过", "message": "", - "duration_seconds": 0.08160599996335804, - "timestamp": "2025-05-23T12:04:51.033450", + "duration_seconds": 0.016939209075644612, + "timestamp": "2025-05-26T14:57:41.404059", "validation_points": [ { "passed": true, @@ -273,8 +1094,8 @@ "test_case_severity": "高", "status": "通过", "message": "", - "duration_seconds": 0.05193216586485505, - "timestamp": "2025-05-23T12:04:51.085646", + "duration_seconds": 0.015757916029542685, + "timestamp": "2025-05-26T14:57:41.419872", "validation_points": [ { "passed": true,