fix:stage

This commit is contained in:
gongwenxin
2025-08-08 00:43:22 +08:00
parent 7ddb530353
commit 8df41527d6
4 changed files with 270 additions and 35 deletions
+80 -28
View File
@@ -173,7 +173,7 @@ class DmsCrudScenarioStage(BaseAPIStage):
name = "DMS Full CRUD Scenario"
description = "Performs a full Create -> Read -> Update -> Read -> Delete -> List workflow for a single DMS business object."
tags = ["dms", "crud", "scenario"]
continue_on_failure = False
continue_on_failure = True # 🔧 修改为True,让Stage在失败时继续执行其他场景
# DMS Stage专用配置:自动启用LLM智能数据生成
enable_llm_data_generation = True # 如果LLM服务可用,自动使用LLM生成测试数据
@@ -183,54 +183,106 @@ class DmsCrudScenarioStage(BaseAPIStage):
# scenarios will be populated by is_applicable_to_api_group
self.scenarios: List[Dict[str, Endpoint]] = []
self.current_scenario_index = -1
def is_applicable_to_api_group(self, api_group_name: Optional[str], global_api_spec: ParsedAPISpec) -> bool:
"""
Checks if the group of APIs contains at least one full CRUD set for a DMS object.
A full set consists of create, read, update, delete, and list operations.
"""
endpoints_in_group = self.apis_in_group
# We only care about DMS endpoints for this stage
dms_endpoints = [ep for ep in endpoints_in_group if isinstance(ep, DMSEndpoint)]
if not dms_endpoints:
return False
# 新增:指定要处理的场景索引(用于多实例模式)
self.target_scenario_index: Optional[int] = kwargs.get('target_scenario_index', None)
# Group endpoints by base resource name from operation_id
@staticmethod
def discover_crud_scenarios(parsed_spec: ParsedAPISpec) -> List[Dict[str, Any]]:
"""
静态方法:发现所有完整的DMS CRUD场景
返回场景信息列表,每个场景包含resource_name和endpoints
"""
if not isinstance(parsed_spec, ParsedAPISpec):
return []
# 只处理DMS端点
dms_endpoints = [ep for ep in parsed_spec.endpoints if isinstance(ep, DMSEndpoint)]
if not dms_endpoints:
return []
# 按资源名称分组端点
grouped_ops = defaultdict(dict)
for ep in dms_endpoints:
if not ep.operation_id:
continue
parts = ep.operation_id.split('_', 1)
if len(parts) != 2:
continue
op_type, resource_name = parts
grouped_ops[resource_name][op_type] = ep
# Find complete scenarios
# 找到完整的CRUD场景
required_ops = {'create', 'read', 'update', 'delete', 'list'}
scenarios = []
for resource_name, ops in grouped_ops.items():
if required_ops.issubset(ops.keys()):
self.scenarios.append(ops)
self.logger.info(f"Found complete CRUD scenario for DMS resource: '{resource_name}'")
scenarios.append({
'resource_name': resource_name,
'endpoints': ops,
'virtual_group_name': f"dms_crud_{resource_name}"
})
return len(self.scenarios) > 0
return scenarios
def is_applicable_to_api_group(self, api_group_name: Optional[str], global_api_spec: ParsedAPISpec) -> bool:
"""
检查此Stage是否适用于给定的API分组。
支持两种模式:
1. 传统模式:处理所有发现的CRUD场景
2. 单场景模式:只处理指定索引的场景(通过virtual_group_name匹配)
"""
# 使用静态方法发现所有场景
all_scenarios = self.discover_crud_scenarios(global_api_spec)
if not all_scenarios:
return False
# 如果指定了虚拟分组名称,只处理匹配的场景
if api_group_name and api_group_name.startswith('dms_crud_'):
# 单场景模式:只处理匹配的场景
target_scenario = None
for scenario in all_scenarios:
if scenario['virtual_group_name'] == api_group_name:
target_scenario = scenario
break
if target_scenario:
self.scenarios = [target_scenario['endpoints']]
self.logger.info(f"DMS Stage (单场景模式) 匹配到场景: {target_scenario['resource_name']}")
return True
else:
self.logger.info(f"DMS Stage (单场景模式) 未找到匹配的场景: {api_group_name}")
return False
else:
# 传统模式:处理所有场景(向后兼容)
self.scenarios = [scenario['endpoints'] for scenario in all_scenarios]
self.logger.info(f"DMS Stage (传统模式) 发现 {len(self.scenarios)} 个完整的CRUD场景")
return len(self.scenarios) > 0
def before_stage(self, stage_context: dict, global_api_spec: ParsedAPISpec, api_group_name: str | None):
"""
Set up the context for the next scenario to run.
This will be called by the orchestrator. We will use it to prepare for a single scenario execution.
为要运行的场景设置上下文。
在单场景模式下,只处理一个场景。
"""
self.current_scenario_index += 1
if self.current_scenario_index >= len(self.scenarios):
# Should not happen if orchestrator works as expected (one stage instance per scenario)
# but as a safeguard.
raise Exception("No more scenarios to run.")
# 设置当前场景索引
self.current_scenario_index = 0
if len(self.scenarios) == 0:
raise Exception("No CRUD scenarios found to run.")
current_scenario = self.scenarios[self.current_scenario_index]
self.logger.info(f"Setting up before_stage for scenario: {list(current_scenario.keys())}")
# 获取资源名称用于日志
resource_name = "unknown"
if current_scenario:
first_op = next(iter(current_scenario.values()))
if hasattr(first_op, 'operation_id') and first_op.operation_id:
parts = first_op.operation_id.split('_', 1)
if len(parts) == 2:
resource_name = parts[1]
self.logger.info(f"🎯 DMS Stage设置场景上下文: {resource_name} (分组: {api_group_name})")
self.logger.info(f"📋 场景包含操作: {list(current_scenario.keys())}")
# Get the 'create' endpoint to determine the primary key
create_op: DMSEndpoint = current_scenario.get('create')