add 真实well数据覆盖
This commit is contained in:
@@ -45,6 +45,12 @@ except ImportError:
|
||||
|
||||
from ddms_compliance_suite.utils.schema_provider import SchemaProvider
|
||||
|
||||
# 导入井数据管理器
|
||||
try:
|
||||
from .utils.well_data_manager import WellDataManager
|
||||
except ImportError:
|
||||
WellDataManager = None
|
||||
|
||||
_dynamic_model_cache: Dict[str, Type[BaseModel]] = {}
|
||||
|
||||
class ExecutedTestCaseResult:
|
||||
@@ -438,7 +444,8 @@ class APITestOrchestrator:
|
||||
stage_llm_config: Optional[Dict[str, bool]] = None,
|
||||
output_dir: Optional[str] = None,
|
||||
strictness_level: Optional[str] = None,
|
||||
ignore_ssl: bool = False
|
||||
ignore_ssl: bool = False,
|
||||
enable_well_data: bool = True
|
||||
):
|
||||
"""
|
||||
初始化测试编排器。
|
||||
@@ -465,6 +472,22 @@ class APITestOrchestrator:
|
||||
self.global_api_call_details: List[APICallDetail] = []
|
||||
self.ignore_ssl = ignore_ssl
|
||||
|
||||
# 初始化井数据管理器
|
||||
self.well_data_manager = None
|
||||
if enable_well_data and WellDataManager:
|
||||
try:
|
||||
self.well_data_manager = WellDataManager(
|
||||
base_url=self.base_url,
|
||||
ignore_ssl=self.ignore_ssl,
|
||||
logger=self.logger
|
||||
)
|
||||
self.logger.info("井数据管理器已初始化")
|
||||
except Exception as e:
|
||||
self.logger.warning(f"井数据管理器初始化失败: {e}")
|
||||
self.well_data_manager = None
|
||||
elif not WellDataManager:
|
||||
self.logger.info("井数据管理器模块不可用")
|
||||
|
||||
self.stages_dir = stages_dir
|
||||
self.stage_registry: Optional[StageRegistry] = None
|
||||
|
||||
@@ -503,14 +526,37 @@ class APITestOrchestrator:
|
||||
|
||||
if self.stages_dir:
|
||||
self.stage_registry = StageRegistry(stages_dir=self.stages_dir)
|
||||
if self.stage_registry and self.stage_registry.get_discovery_errors():
|
||||
for err in self.stage_registry.get_discovery_errors():
|
||||
if self.stage_registry and self.stage_registry.get_discovery_errors():
|
||||
for err in self.stage_registry.get_discovery_errors():
|
||||
self.logger.error(f"Error loading stage: {err}")
|
||||
elif self.stage_registry:
|
||||
self.logger.info(f"StageRegistry initialized. Loaded {len(self.stage_registry.get_all_stages())} stages.") # Changed from get_all_stage_classes
|
||||
else:
|
||||
self.logger.info("No stages_dir provided, stage testing will be skipped.")
|
||||
|
||||
def initialize_well_data(self) -> bool:
|
||||
"""
|
||||
初始化井数据,在测试开始前获取真实的井和井筒数据
|
||||
|
||||
Returns:
|
||||
bool: 是否成功初始化井数据
|
||||
"""
|
||||
if not self.well_data_manager:
|
||||
self.logger.info("井数据管理器未启用,跳过井数据初始化")
|
||||
return False
|
||||
|
||||
try:
|
||||
success = self.well_data_manager.initialize_well_data()
|
||||
if success:
|
||||
summary = self.well_data_manager.get_well_data_summary()
|
||||
self.logger.info(f"井数据初始化成功: {summary}")
|
||||
return success
|
||||
except Exception as e:
|
||||
self.logger.error(f"井数据初始化失败: {e}")
|
||||
return False
|
||||
|
||||
def _complete_initialization(self, output_dir: Optional[str], strictness_level: Optional[str]):
|
||||
"""完成初始化过程"""
|
||||
self.output_dir_path = Path(output_dir) if output_dir else Path("./test_reports_orchestrator")
|
||||
try:
|
||||
self.output_dir_path.mkdir(parents=True, exist_ok=True)
|
||||
@@ -537,6 +583,9 @@ class APITestOrchestrator:
|
||||
self.json_schema_validator: Optional[JSONSchemaValidator] = None
|
||||
self.schema_provider: Optional[SchemaProvider] = None
|
||||
|
||||
# 完成初始化
|
||||
self._complete_initialization(output_dir, strictness_level)
|
||||
|
||||
def get_api_call_details(self) -> List[APICallDetail]:
|
||||
"""Returns the collected list of API call details."""
|
||||
return self.global_api_call_details
|
||||
@@ -1648,13 +1697,21 @@ class APITestOrchestrator:
|
||||
# finalize_summary 和 print_summary_to_console 将在 run_api_tests.py 中进行
|
||||
return summary, parsed_swagger
|
||||
|
||||
def _generate_data_from_schema(self, schema: Dict[str, Any],
|
||||
context_name: Optional[str] = None,
|
||||
def _generate_data_from_schema(self, schema: Dict[str, Any],
|
||||
context_name: Optional[str] = None,
|
||||
operation_id: Optional[str] = None) -> Any:
|
||||
"""
|
||||
根据JSON Schema生成测试数据 (此方法基本保持不变,可能被测试用例或编排器内部使用)
|
||||
增加了 context_name 和 operation_id 用于更详细的日志。
|
||||
现在会使用井数据管理器来提供真实的井相关数据。
|
||||
"""
|
||||
# 如果有井数据管理器,使用DataGenerator来生成数据
|
||||
if self.well_data_manager:
|
||||
from .utils.data_generator import DataGenerator
|
||||
data_generator = DataGenerator(logger_param=self.logger, well_data_manager=self.well_data_manager)
|
||||
return data_generator.generate_data_from_schema(schema, context_name, operation_id, self.llm_service)
|
||||
|
||||
# 原有的生成逻辑作为后备
|
||||
log_prefix = f"[{operation_id}] " if operation_id else ""
|
||||
context_log = f" (context: {context_name})" if context_name else ""
|
||||
|
||||
@@ -2705,6 +2762,15 @@ class APITestOrchestrator:
|
||||
|
||||
parsed_spec, pagination_info = parse_result
|
||||
|
||||
# 初始化井数据(在测试开始前获取真实数据)
|
||||
if self.well_data_manager:
|
||||
self.logger.info("开始初始化井数据...")
|
||||
well_data_success = self.initialize_well_data()
|
||||
if well_data_success:
|
||||
self.logger.info("井数据初始化成功,测试将使用真实的井相关数据")
|
||||
else:
|
||||
self.logger.warning("井数据初始化失败,测试将使用模拟数据")
|
||||
|
||||
# 🔧 移除重复的run_stages_from_spec调用
|
||||
# Stage执行将在主程序中统一处理
|
||||
|
||||
|
||||
@@ -6,17 +6,25 @@ import datetime
|
||||
import uuid
|
||||
from typing import Dict, Any, Optional, List
|
||||
|
||||
# 导入井数据管理器
|
||||
try:
|
||||
from .well_data_manager import WellDataManager
|
||||
except ImportError:
|
||||
WellDataManager = None
|
||||
|
||||
class DataGenerator:
|
||||
"""
|
||||
Generates test data based on a JSON Schema.
|
||||
"""
|
||||
def __init__(self, logger_param: Optional[logging.Logger] = None):
|
||||
def __init__(self, logger_param: Optional[logging.Logger] = None, well_data_manager: Optional['WellDataManager'] = None):
|
||||
"""
|
||||
Initializes the data generator.
|
||||
Args:
|
||||
logger_param: Optional logger instance. If not provided, a module-level logger is used.
|
||||
well_data_manager: Optional well data manager for providing real well data.
|
||||
"""
|
||||
self.logger = logger_param or logging.getLogger(__name__)
|
||||
self.well_data_manager = well_data_manager
|
||||
|
||||
def generate_data_from_schema(self, schema: Dict[str, Any],
|
||||
context_name: Optional[str] = None,
|
||||
@@ -90,6 +98,11 @@ class DataGenerator:
|
||||
if isinstance(additional_properties, dict):
|
||||
self.logger.debug(f"{log_prefix}Generating an example property for additionalProperties for{context_log}")
|
||||
result['additionalProp1'] = self.generate_data_from_schema(additional_properties, f"{context_name}.additionalProp1", operation_id, llm_service)
|
||||
|
||||
# 使用井数据管理器增强数据
|
||||
if self.well_data_manager:
|
||||
result = self.well_data_manager.enhance_data_with_well_values(result)
|
||||
|
||||
return result
|
||||
|
||||
# Handle both 'array' and 'Array' (case-insensitive)
|
||||
@@ -113,6 +126,17 @@ class DataGenerator:
|
||||
if string_format == 'date-time': return datetime.datetime.now().isoformat()
|
||||
if string_format == 'email': return 'test@example.com'
|
||||
if string_format == 'uuid': return str(uuid.uuid4())
|
||||
|
||||
# 检查是否为井相关字段,如果是则尝试使用真实数据
|
||||
if self.well_data_manager and context_name:
|
||||
# 从context_name中提取字段名(去掉路径前缀)
|
||||
field_name = context_name.split('.')[-1] if '.' in context_name else context_name
|
||||
if self.well_data_manager.is_well_related_field(field_name):
|
||||
real_value = self.well_data_manager.get_well_value_for_field(field_name)
|
||||
if real_value is not None:
|
||||
self.logger.info(f"{log_prefix}🔄 使用真实井数据替换字段 '{field_name}': {real_value}")
|
||||
return str(real_value)
|
||||
|
||||
return 'example_string'
|
||||
|
||||
# Handle both 'number'/'Number' and 'integer'/'Integer' (case-insensitive)
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
"""
|
||||
井数据管理器模块
|
||||
|
||||
负责在测试开始前预获取井和井筒的真实数据,并在测试过程中提供这些真实值
|
||||
用于替换wellId、wellboreId、wellCommonName等参数的模拟值
|
||||
"""
|
||||
|
||||
import logging
|
||||
import json
|
||||
import requests
|
||||
from typing import Dict, List, Any, Optional, Tuple
|
||||
from urllib.parse import urljoin
|
||||
import random
|
||||
|
||||
class WellDataManager:
|
||||
"""
|
||||
井数据管理器
|
||||
|
||||
负责:
|
||||
1. 在测试开始前从指定的API获取井和井筒的真实数据
|
||||
2. 缓存这些数据供后续测试使用
|
||||
3. 在生成测试数据时提供真实的井相关参数值
|
||||
"""
|
||||
|
||||
def __init__(self, base_url: str, ignore_ssl: bool = False, logger: Optional[logging.Logger] = None):
|
||||
"""
|
||||
初始化井数据管理器
|
||||
|
||||
Args:
|
||||
base_url: API基础URL
|
||||
ignore_ssl: 是否忽略SSL证书验证
|
||||
logger: 日志记录器
|
||||
"""
|
||||
self.base_url = base_url.rstrip('/')
|
||||
self.ignore_ssl = ignore_ssl
|
||||
self.logger = logger or logging.getLogger(__name__)
|
||||
|
||||
# 缓存的井数据
|
||||
self.well_data: List[Dict[str, Any]] = []
|
||||
self.wellbore_data: List[Dict[str, Any]] = []
|
||||
|
||||
# 井数据API端点配置
|
||||
self.well_api_config = {
|
||||
"domain": "wb_cd",
|
||||
"name": "cd_well",
|
||||
"version": "1.0.0",
|
||||
"path": "/api/dms/well_kd_wellbore_ideas01/v1/cd_well/1.0.0"
|
||||
}
|
||||
|
||||
self.wellbore_api_config = {
|
||||
"domain": "wb_cd",
|
||||
"name": "cd_wellbore",
|
||||
"version": "1.0.0",
|
||||
"path": "/api/dms/well_kd_wellbore_ideas01/v1/cd_wellbore/1.0.0"
|
||||
}
|
||||
|
||||
# 井相关字段名称(严格按照接口定义)
|
||||
self.well_field_names = {
|
||||
'wellId', # 井ID
|
||||
'wellboreId', # 井筒ID
|
||||
'wellCommonName' # 井通用名称
|
||||
}
|
||||
|
||||
def fetch_well_data(self) -> bool:
|
||||
"""
|
||||
获取井基本信息数据
|
||||
|
||||
Returns:
|
||||
bool: 是否成功获取数据
|
||||
"""
|
||||
try:
|
||||
url = urljoin(self.base_url, self.well_api_config["path"])
|
||||
|
||||
headers = {
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
# 发送POST请求获取井数据
|
||||
response = requests.post(
|
||||
url,
|
||||
headers=headers,
|
||||
json={}, # 空的JSON body
|
||||
verify=not self.ignore_ssl,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get('code') == 0 and 'data' in data and 'list' in data['data']:
|
||||
self.well_data = data['data']['list']
|
||||
self.logger.info(f"成功获取 {len(self.well_data)} 条井基本信息数据")
|
||||
return True
|
||||
else:
|
||||
self.logger.error(f"井数据API返回错误: {data.get('message', '未知错误')}")
|
||||
return False
|
||||
else:
|
||||
self.logger.error(f"获取井数据失败,HTTP状态码: {response.status_code}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取井数据时发生异常: {str(e)}")
|
||||
return False
|
||||
|
||||
def fetch_wellbore_data(self) -> bool:
|
||||
"""
|
||||
获取井筒基本信息数据
|
||||
|
||||
Returns:
|
||||
bool: 是否成功获取数据
|
||||
"""
|
||||
try:
|
||||
url = urljoin(self.base_url, self.wellbore_api_config["path"])
|
||||
|
||||
headers = {
|
||||
"Accept-Encoding": "gzip, deflate",
|
||||
"Accept": "application/json",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
# 发送POST请求获取井筒数据
|
||||
response = requests.post(
|
||||
url,
|
||||
headers=headers,
|
||||
json={}, # 空的JSON body
|
||||
verify=not self.ignore_ssl,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get('code') == 0 and 'data' in data and 'list' in data['data']:
|
||||
self.wellbore_data = data['data']['list']
|
||||
self.logger.info(f"成功获取 {len(self.wellbore_data)} 条井筒基本信息数据")
|
||||
return True
|
||||
else:
|
||||
self.logger.error(f"井筒数据API返回错误: {data.get('message', '未知错误')}")
|
||||
return False
|
||||
else:
|
||||
self.logger.error(f"获取井筒数据失败,HTTP状态码: {response.status_code}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"获取井筒数据时发生异常: {str(e)}")
|
||||
return False
|
||||
|
||||
def initialize_well_data(self) -> bool:
|
||||
"""
|
||||
初始化井数据,获取井和井筒的真实数据
|
||||
|
||||
Returns:
|
||||
bool: 是否成功初始化所有数据
|
||||
"""
|
||||
self.logger.info("开始初始化井数据...")
|
||||
|
||||
well_success = self.fetch_well_data()
|
||||
wellbore_success = self.fetch_wellbore_data()
|
||||
|
||||
if well_success and wellbore_success:
|
||||
self.logger.info("井数据初始化完成")
|
||||
return True
|
||||
else:
|
||||
self.logger.warning("井数据初始化部分失败,某些测试可能使用模拟数据")
|
||||
return False
|
||||
|
||||
def get_random_well_data(self) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取随机的井数据
|
||||
|
||||
Returns:
|
||||
Optional[Dict[str, Any]]: 井数据字典,如果没有数据则返回None
|
||||
"""
|
||||
if not self.well_data:
|
||||
return None
|
||||
return random.choice(self.well_data)
|
||||
|
||||
def get_random_wellbore_data(self) -> Optional[Dict[str, Any]]:
|
||||
"""
|
||||
获取随机的井筒数据
|
||||
|
||||
Returns:
|
||||
Optional[Dict[str, Any]]: 井筒数据字典,如果没有数据则返回None
|
||||
"""
|
||||
if not self.wellbore_data:
|
||||
return None
|
||||
return random.choice(self.wellbore_data)
|
||||
|
||||
def get_well_value_for_field(self, field_name: str) -> Optional[Any]:
|
||||
"""
|
||||
根据字段名获取井相关的真实值
|
||||
|
||||
Args:
|
||||
field_name: 字段名称(严格匹配)
|
||||
|
||||
Returns:
|
||||
Optional[Any]: 对应的真实值,如果没有找到则返回None
|
||||
"""
|
||||
# 严格按照字段名匹配
|
||||
if field_name == 'wellId':
|
||||
well_data = self.get_random_well_data()
|
||||
if well_data:
|
||||
return well_data.get('wellId')
|
||||
|
||||
elif field_name == 'wellboreId':
|
||||
wellbore_data = self.get_random_wellbore_data()
|
||||
if wellbore_data:
|
||||
return wellbore_data.get('wellboreId')
|
||||
|
||||
elif field_name == 'wellCommonName':
|
||||
well_data = self.get_random_well_data()
|
||||
if well_data:
|
||||
return well_data.get('wellCommonName')
|
||||
|
||||
return None
|
||||
|
||||
def is_well_related_field(self, field_name: str) -> bool:
|
||||
"""
|
||||
判断字段是否与井相关
|
||||
|
||||
Args:
|
||||
field_name: 字段名称
|
||||
|
||||
Returns:
|
||||
bool: 是否为井相关字段
|
||||
"""
|
||||
return field_name in self.well_field_names
|
||||
|
||||
def enhance_data_with_well_values(self, data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
用真实的井数据增强测试数据
|
||||
|
||||
Args:
|
||||
data: 原始测试数据
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: 增强后的测试数据
|
||||
"""
|
||||
if not isinstance(data, dict):
|
||||
return data
|
||||
|
||||
enhanced_data = data.copy()
|
||||
|
||||
for field_name, value in data.items():
|
||||
if self.is_well_related_field(field_name):
|
||||
real_value = self.get_well_value_for_field(field_name)
|
||||
if real_value is not None:
|
||||
enhanced_data[field_name] = real_value
|
||||
self.logger.debug(f"替换字段 '{field_name}' 的值: {value} -> {real_value}")
|
||||
|
||||
return enhanced_data
|
||||
|
||||
def get_well_data_summary(self) -> Dict[str, Any]:
|
||||
"""
|
||||
获取井数据的摘要信息
|
||||
|
||||
Returns:
|
||||
Dict[str, Any]: 井数据摘要
|
||||
"""
|
||||
return {
|
||||
"well_count": len(self.well_data),
|
||||
"wellbore_count": len(self.wellbore_data),
|
||||
"sample_well_ids": [w.get('wellId') for w in self.well_data[:5]] if self.well_data else [],
|
||||
"sample_wellbore_ids": [w.get('wellboreId') for w in self.wellbore_data[:5]] if self.wellbore_data else [],
|
||||
"sample_well_names": [w.get('wellCommonName') for w in self.well_data[:5]] if self.well_data else []
|
||||
}
|
||||
|
||||
def clear_cache(self):
|
||||
"""
|
||||
清空缓存的井数据
|
||||
"""
|
||||
self.well_data.clear()
|
||||
self.wellbore_data.clear()
|
||||
self.logger.info("井数据缓存已清空")
|
||||
Reference in New Issue
Block a user