141 lines
6.5 KiB
Python
141 lines
6.5 KiB
Python
from ddms_compliance_suite.test_framework_core import BaseAPITestCase, ValidationResult, APIResponseContext, APIRequestContext, TestSeverity
|
||
from typing import Dict, Any, List, Optional
|
||
import re
|
||
|
||
class PaginationParamsCheckTestCase(BaseAPITestCase):
|
||
"""
|
||
检查API请求中是否包含标准分页参数:pageNo、pageSize和isSearchCount
|
||
只有名称含有"查询"一类,并且不含有"详情"一类的API才应用这个验证
|
||
"""
|
||
id = "TC-DMS-PAGINATION-001"
|
||
name = "分页参数检查"
|
||
description = "检查API请求参数中是否包含标准分页参数:pageNo、pageSize和isSearchCount。只有名称含有'查询'、'列表'等并且不含有'详情'一类的API才应用此验证。"
|
||
severity = TestSeverity.MEDIUM
|
||
tags = ["pagination", "params", "backend-guide"]
|
||
|
||
# 这个测试用例不需要发送实际请求
|
||
skip_execution = True
|
||
|
||
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)
|
||
|
||
# 定义需要验证的API名称关键词
|
||
self.include_keywords = ["查询", "列表", "分页", "page", "list", "query", "search", "find"]
|
||
# 定义排除的API名称关键词
|
||
self.exclude_keywords = ["详情", "明细", "detail", "info", "get", "查看"]
|
||
|
||
def validate_response(self, response_context: APIResponseContext, request_context: APIRequestContext) -> List[ValidationResult]:
|
||
"""
|
||
检查API请求中是否包含标准分页参数
|
||
"""
|
||
results = []
|
||
|
||
# 获取API路径和方法
|
||
path = self.endpoint_spec.get('path', '')
|
||
method = self.endpoint_spec.get('method', '').lower()
|
||
|
||
# 获取API的摘要和描述信息
|
||
summary = self.endpoint_spec.get('summary', '')
|
||
description = self.endpoint_spec.get('description', '')
|
||
operation_id = self.endpoint_spec.get('operationId', '')
|
||
|
||
# 组合所有可能包含API名称或功能描述的字段
|
||
api_description_text = f"{summary} {description} {operation_id} {path}".lower()
|
||
|
||
# 检查是否包含需要验证的关键词,且不包含排除的关键词
|
||
contains_include_keyword = any(keyword.lower() in api_description_text for keyword in self.include_keywords)
|
||
contains_exclude_keyword = any(keyword.lower() in api_description_text for keyword in self.exclude_keywords)
|
||
|
||
# 如果不满足准入规则,直接返回通过
|
||
if not contains_include_keyword or contains_exclude_keyword:
|
||
results.append(self.passed(
|
||
message=f"跳过检查:API不符合分页参数检查的准入规则(需包含'查询'/'列表'等关键词,且不包含'详情'等关键词)",
|
||
details={
|
||
"path": path,
|
||
"method": method.upper(),
|
||
"summary": summary,
|
||
"contains_include_keyword": contains_include_keyword,
|
||
"contains_exclude_keyword": contains_exclude_keyword
|
||
}
|
||
))
|
||
return results
|
||
|
||
# 如果是GET请求或可能返回列表的请求,才进行检查
|
||
if method not in ['get', 'post']:
|
||
results.append(self.passed(
|
||
message=f"跳过检查:{method.upper()} 方法,不适用于分页参数检查"
|
||
))
|
||
return results
|
||
|
||
# 初始化检查结果
|
||
found_page_no = False
|
||
found_page_size = False
|
||
found_is_search_count = False
|
||
|
||
# 检查查询参数
|
||
parameters = self.endpoint_spec.get('parameters', [])
|
||
for param in parameters:
|
||
param_name = param.get('name', '')
|
||
param_in = param.get('in', '')
|
||
|
||
if param_in == 'query':
|
||
if param_name == 'pageNo':
|
||
found_page_no = True
|
||
elif param_name == 'pageSize':
|
||
found_page_size = True
|
||
elif param_name == 'isSearchCount':
|
||
found_is_search_count = True
|
||
|
||
# 检查请求体(如果是POST请求)
|
||
if method == 'post':
|
||
request_body = self.endpoint_spec.get('requestBody', {})
|
||
content = request_body.get('content', {})
|
||
|
||
for media_type, media_content in content.items():
|
||
if 'schema' in media_content:
|
||
schema = self._get_resolved_schema(media_content['schema'])
|
||
if 'properties' in schema:
|
||
properties = schema['properties']
|
||
|
||
# 检查请求体属性
|
||
if 'pageNo' in properties:
|
||
found_page_no = True
|
||
|
||
if 'pageSize' in properties:
|
||
found_page_size = True
|
||
|
||
if 'isSearchCount' in properties:
|
||
found_is_search_count = True
|
||
|
||
# 汇总检查结果
|
||
if found_page_no and found_page_size and found_is_search_count:
|
||
results.append(self.passed(
|
||
message=f"API请求包含所有标准分页参数:pageNo、pageSize和isSearchCount",
|
||
details={"path": path, "method": method.upper()}
|
||
))
|
||
else:
|
||
# 计算缺失的参数
|
||
missing_params = []
|
||
if not found_page_no:
|
||
missing_params.append("pageNo")
|
||
if not found_page_size:
|
||
missing_params.append("pageSize")
|
||
if not found_is_search_count:
|
||
missing_params.append("isSearchCount")
|
||
|
||
if missing_params:
|
||
results.append(self.failed(
|
||
message=f"API请求缺少标准分页参数:{', '.join(missing_params)}",
|
||
details={
|
||
"path": path,
|
||
"method": method.upper(),
|
||
"missing_params": missing_params,
|
||
"found_params": {
|
||
"pageNo": found_page_no,
|
||
"pageSize": found_page_size,
|
||
"isSearchCount": found_is_search_count
|
||
}
|
||
}
|
||
))
|
||
|
||
return results |