fix:crud流程测试修复

This commit is contained in:
gongwenxin
2025-07-12 19:53:21 +08:00
parent 25789568a2
commit 6fb15f1840
33 changed files with 26857 additions and 52894 deletions
+73 -18
View File
@@ -1,5 +1,6 @@
import uuid
import logging
import copy
from typing import List, Dict, Any, Optional, Union
from collections import defaultdict
@@ -7,7 +8,9 @@ from ddms_compliance_suite.stage_framework import BaseAPIStage, StageStepDefinit
from ddms_compliance_suite.input_parser.parser import Endpoint, DMSEndpoint, ParsedAPISpec
from ddms_compliance_suite.test_framework_core import ValidationResult, APIResponseContext
from ddms_compliance_suite.api_caller.caller import APICaller
from ddms_compliance_suite.utils.data_generator import DataGenerator
from ddms_compliance_suite.input_parser.parser import ParsedAPISpec, YAPIEndpoint, SwaggerEndpoint
from ddms_compliance_suite.input_parser.parser import BaseEndpoint, DMSEndpoint
# --- Helper function to get value from nested dict ---
def _get_value_by_path(data: Optional[Dict[str, Any]], path_str: Optional[str]):
if data is None or not path_str:
@@ -56,6 +59,26 @@ def validate_resource_details(response_ctx: APIResponseContext, stage_ctx: dict)
return ValidationResult(passed=True, message="Resource details successfully validated against payload.")
def validate_resource_details_after_update(response_ctx: APIResponseContext, stage_ctx: dict) -> ValidationResult:
"""Validates the details of a resource against the *update* payload from the context."""
pk_name = stage_ctx.get("pk_name")
pk_value = stage_ctx.get("pk_value")
payload = stage_ctx.get("update_payload") # Use the specific update payload
response_data = _get_value_by_path(response_ctx.json_content, "data")
if not isinstance(response_data, dict):
return ValidationResult(passed=False, message=f"Response 'data' field is not a JSON object. Got: {response_data}")
# Check if all fields from the payload exist in the response and match
for key, expected_value in payload.items():
if key not in response_data:
return ValidationResult(passed=False, message=f"Field '{key}' from update_payload not found in response.")
if response_data[key] != expected_value:
return ValidationResult(passed=False, message=f"Field '{key}' mismatch. Expected '{expected_value}' from update_payload, got '{response_data[key]}'.")
return ValidationResult(passed=True, message="Resource details successfully validated against update_payload.")
def validate_resource_is_deleted(response_ctx: APIResponseContext, stage_ctx: dict) -> ValidationResult:
"""Checks if the resource is no longer in the list response."""
pk_name = stage_ctx.get("pk_name")
@@ -139,21 +162,51 @@ class DmsCrudScenarioStage(BaseAPIStage):
self.logger.info(f"Setting up before_stage for scenario: {list(current_scenario.keys())}")
# Get the 'create' endpoint to determine the primary key
create_op = current_scenario['create']
# This is a bit of a hack. The primary key should ideally be discoverable
# from the schema without relying on request body definitions.
# Based on our parser, the delete request body contains the PK.
delete_op = current_scenario['delete']
pk_name = next(iter(delete_op.request_body['content']['application/json']['schema']['properties']['data']['items']['properties']))
create_op: DMSEndpoint = current_scenario.get('create')
if not create_op or not isinstance(create_op, DMSEndpoint):
raise Exception(f"Could not find a valid DMS 'create' operation for scenario.")
# The primary key name is now passed by the parser.
pk_name = create_op.model_pk_name
if not pk_name:
# Fallback for safety, though parser should always provide it
self.logger.warning("Could not find 'model_pk_name' on create endpoint. Falling back to inspecting delete request.")
delete_op = current_scenario['delete']
pk_name = next(iter(delete_op.request_body['content']['application/json']['schema']['properties']['data']['items']['properties']))
pk_value = str(uuid.uuid4())
# Prepare a sample payload. We'd need a proper data generator for this.
# For now, let's create a placeholder. The test framework should handle generation.
# Let's assume the framework's parameter generator will handle the real payload.
# We just need to provide the PK.
create_payload = { pk_name: pk_value, "description": "test-entry-from-scenario" }
update_payload = { pk_name: pk_value, "description": "updated-test-entry-from-scenario" }
# 使用测试框架的数据生成器生成完整有效的请求负载
# from ddms_compliance_suite.utils.schema_utils import DataGenerator
# 获取创建操作的请求体模式
create_schema = None
if create_op.request_body and 'content' in create_op.request_body:
content = create_op.request_body['content']
if 'application/json' in content and 'schema' in content['application/json']:
create_schema = content['application/json']['schema']
# 生成创建请求负载
data_generator = DataGenerator(logger_param=self.logger)
if create_schema:
# 生成基于模式的数据
generated_data = data_generator.generate_data_from_schema(create_schema)
# 确保主键字段存在且被正确设置
if isinstance(generated_data, dict) and 'data' in generated_data and isinstance(generated_data['data'], list) and len(generated_data['data']) > 0:
generated_data['data'][0][pk_name] = pk_value
create_payload = generated_data['data'][0]
else:
# 如果生成的数据结构不符合预期,使用基本负载
self.logger.warning("Generated data structure was not as expected. Falling back to a minimal payload.")
create_payload = { pk_name: pk_value }
else:
# 如果没有模式,使用基本负载
self.logger.warning("No create schema found. Falling back to a minimal payload.")
create_payload = { pk_name: pk_value }
# 更新负载基于创建负载,但修改描述字段
update_payload = copy.deepcopy(create_payload)
update_payload["description"] = "updated-test-entry-from-scenario"
# Populate stage context
stage_context["pk_name"] = pk_name
@@ -161,6 +214,10 @@ class DmsCrudScenarioStage(BaseAPIStage):
stage_context["current_payload"] = create_payload
stage_context["update_payload"] = update_payload
stage_context["scenario_endpoints"] = current_scenario
# Pre-build the delete body to avoid key-templating issues later
# Per user request, the delete body should be an array of PK values
stage_context["delete_request_body"] = {"data": [pk_value]}
def get_api_spec_for_operation(self, lookup_key: str, *args, **kwargs) -> Optional[Endpoint]:
"""
@@ -201,8 +258,6 @@ class DmsCrudScenarioStage(BaseAPIStage):
endpoint_spec_lookup_key="UPDATE",
request_overrides={
"body": {"data": ["{{stage_context.update_payload}}"]},
# The context needs to be updated for the next validation step
"context_updates": {"current_payload": "{{stage_context.update_payload}}"}
},
response_assertions=[validate_response_is_true]
),
@@ -212,13 +267,13 @@ class DmsCrudScenarioStage(BaseAPIStage):
request_overrides={
"path_params": {"id": "{{stage_context.pk_value}}"}
},
response_assertions=[validate_resource_details]
response_assertions=[validate_resource_details_after_update]
),
StageStepDefinition(
name="Step 5: Delete Resource",
endpoint_spec_lookup_key="DELETE",
request_overrides={
"body": {"data": [{"{{stage_context.pk_name}}": "{{stage_context.pk_value}}"}]}
"body": "{{stage_context.delete_request_body}}"
},
response_assertions=[validate_response_is_true]
),