fix:crud流程测试修复
This commit is contained in:
Binary file not shown.
@@ -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]
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user