fix:stage
This commit is contained in:
@@ -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')
|
||||
|
||||
Reference in New Issue
Block a user