test_connect

This commit is contained in:
gongwenxin 2025-08-07 17:14:40 +08:00
parent 4c7bbe0c40
commit 7846479a1b
12 changed files with 1608 additions and 12 deletions

3
.gitignore vendored
View File

@ -166,7 +166,8 @@ post_output.log
*.db *.db
*.sqlite *.sqlite
*.sqlite3 *.sqlite3
users.db # users.db # 注释掉允许跟踪users.db
!users.db # 例外规则允许跟踪users.db
# Python编译文件 # Python编译文件
*.pyc *.pyc

82
add_specific_file.sh Executable file
View File

@ -0,0 +1,82 @@
#!/bin/bash
# 添加特定文件到Git跟踪的脚本
# 即使文件在.gitignore中被忽略
if [ $# -eq 0 ]; then
echo "用法: $0 <文件名>"
echo "示例: $0 users.db"
exit 1
fi
FILE="$1"
echo "🔍 添加文件到Git跟踪: $FILE"
echo "=========================="
# 检查文件是否存在
if [ ! -f "$FILE" ]; then
echo "❌ 文件不存在: $FILE"
exit 1
fi
# 检查是否在Git仓库中
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo "❌ 当前目录不是Git仓库"
exit 1
fi
# 检查文件是否被忽略
if git check-ignore "$FILE" > /dev/null 2>&1; then
echo "⚠️ 文件 $FILE 被.gitignore忽略"
echo "使用强制添加..."
git add -f "$FILE"
else
echo "✅ 文件未被忽略,正常添加"
git add "$FILE"
fi
# 检查是否成功添加
if git diff --cached --name-only | grep -q "^$FILE$"; then
echo "✅ 文件已添加到暂存区"
# 显示文件状态
echo ""
echo "📊 文件信息:"
ls -lh "$FILE"
echo ""
echo "📋 Git状态:"
git status --short "$FILE"
echo ""
read -p "是否提交此文件? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "💾 提交文件..."
git commit -m "Add $FILE to version control
- Force add $FILE even if ignored by .gitignore
- File size: $(ls -lh "$FILE" | awk '{print $5}')
- This file is needed for the project"
echo "✅ 文件已提交"
echo ""
read -p "是否推送到远程? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
git push
echo "✅ 已推送到远程"
fi
else
echo "⚠️ 文件在暂存区,记得稍后提交:"
echo " git commit -m 'Add $FILE'"
fi
else
echo "❌ 文件添加失败"
exit 1
fi
echo ""
echo "🎉 完成!"

162
cleanup_git_tracking.sh Executable file
View File

@ -0,0 +1,162 @@
#!/bin/bash
# Git跟踪清理脚本
# 用于移除已被跟踪但应该被忽略的文件和目录
set -e
echo "🧹 Git跟踪清理脚本"
echo "===================="
# 检查是否在Git仓库中
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo "❌ 当前目录不是Git仓库"
exit 1
fi
# 显示当前状态
echo "📊 当前Git状态:"
git status --short
echo ""
echo "🔍 检查需要移除跟踪的目录..."
# 检查build目录
if git ls-files | grep -q "^build/"; then
echo "📁 发现被跟踪的build目录"
BUILD_TRACKED=true
else
echo "✅ build目录未被跟踪"
BUILD_TRACKED=false
fi
# 检查dist目录
if git ls-files | grep -q "^dist/"; then
echo "📁 发现被跟踪的dist目录"
DIST_TRACKED=true
else
echo "✅ dist目录未被跟踪"
DIST_TRACKED=false
fi
# 检查其他常见的应该被忽略的文件
echo ""
echo "🔍 检查其他应该被忽略的文件..."
SHOULD_IGNORE_FILES=(
"*.pyc"
"__pycache__"
"*.log"
"*.tmp"
"*.temp"
".DS_Store"
"Thumbs.db"
"users.db"
)
FOUND_FILES=()
for pattern in "${SHOULD_IGNORE_FILES[@]}"; do
if git ls-files | grep -q "$pattern"; then
echo "📄 发现被跟踪的文件: $pattern"
FOUND_FILES+=("$pattern")
fi
done
# 如果没有需要清理的内容
if [ "$BUILD_TRACKED" = false ] && [ "$DIST_TRACKED" = false ] && [ ${#FOUND_FILES[@]} -eq 0 ]; then
echo ""
echo "🎉 没有发现需要清理的跟踪文件"
echo "✅ .gitignore规则应该已经生效"
exit 0
fi
# 询问用户是否继续
echo ""
echo "⚠️ 将要执行以下操作:"
if [ "$BUILD_TRACKED" = true ]; then
echo " - 移除build/目录的Git跟踪"
fi
if [ "$DIST_TRACKED" = true ]; then
echo " - 移除dist/目录的Git跟踪"
fi
for file in "${FOUND_FILES[@]}"; do
echo " - 移除$file文件的Git跟踪"
done
echo ""
echo "注意: 这只会移除Git跟踪不会删除本地文件"
echo ""
read -p "是否继续? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "❌ 操作已取消"
exit 1
fi
echo ""
echo "🔄 开始清理Git跟踪..."
# 移除build目录跟踪
if [ "$BUILD_TRACKED" = true ]; then
echo "📁 移除build目录跟踪..."
git rm -r --cached build/ || echo "⚠️ build目录移除失败可能已经移除"
fi
# 移除dist目录跟踪
if [ "$DIST_TRACKED" = true ]; then
echo "📁 移除dist目录跟踪..."
git rm -r --cached dist/ || echo "⚠️ dist目录移除失败可能已经移除"
fi
# 移除其他文件跟踪
for pattern in "${FOUND_FILES[@]}"; do
echo "📄 移除$pattern文件跟踪..."
git rm --cached -r "$pattern" 2>/dev/null || echo "⚠️ $pattern移除失败(可能已经移除)"
done
# 显示更改后的状态
echo ""
echo "📊 清理后的Git状态:"
git status --short
# 询问是否提交更改
echo ""
read -p "是否提交这些更改? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "💾 提交更改..."
git add .gitignore
git commit -m "Remove build/, dist/ and other generated files from Git tracking
- Remove build/ directory from tracking
- Remove dist/ directory from tracking
- Update .gitignore to prevent future tracking
- These directories contain generated/compiled files that should not be versioned"
echo ""
echo "✅ 更改已提交"
echo ""
read -p "是否推送到远程仓库? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "🚀 推送到远程..."
git push
echo "✅ 已推送到远程仓库"
else
echo "⚠️ 记得稍后推送: git push"
fi
else
echo "⚠️ 更改未提交,记得稍后提交:"
echo " git add .gitignore"
echo " git commit -m 'Remove generated files from Git tracking'"
echo " git push"
fi
echo ""
echo "🎉 清理完成!"
echo ""
echo "💡 说明:"
echo "- build/和dist/目录现在不会被Git跟踪"
echo "- 本地文件仍然存在,只是不再被版本控制"
echo "- 远程仓库在下次推送后会移除这些文件"
echo "- 其他开发者拉取更新后这些目录也会从他们的Git跟踪中移除"

228
cleanup_large_files.sh Executable file
View File

@ -0,0 +1,228 @@
#!/bin/bash
# 大文件清理脚本
# 基于扫描结果清理Git仓库中的大文件
set -e
echo "🧹 Git大文件清理脚本"
echo "===================="
# 检查是否在Git仓库中
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo "❌ 当前目录不是Git仓库"
exit 1
fi
echo "📋 发现的大文件问题:"
echo "- Git仓库大小: 1.2GB"
echo "- 主要问题: build/, dist/, 日志文件, 字体文件, 压缩包"
echo ""
# 定义要清理的文件和目录
LARGE_FILES_TO_REMOVE=(
"history_local" # 87.84MB
"mvp.zip" # 53.65MB
"log.log" # 3.25MB
"log_dms1.txt" # 2.32MB
"log_dms.txt" # 2.32MB
"log_stage.txt" # 2.07MB
"归档.zip" # 103MB
"users.db" # 数据库文件
"dms.log" # 日志文件
"post_output.log" # 日志文件
)
DIRECTORIES_TO_REMOVE=(
"build/"
"dist/"
)
echo "⚠️ 将要从Git跟踪中移除以下文件和目录:"
echo ""
echo "📁 目录:"
for dir in "${DIRECTORIES_TO_REMOVE[@]}"; do
if git ls-files | grep -q "^$dir"; then
echo " - $dir"
fi
done
echo ""
echo "📄 大文件:"
for file in "${LARGE_FILES_TO_REMOVE[@]}"; do
if git ls-files | grep -q "^$file$"; then
size=$(ls -lh "$file" 2>/dev/null | awk '{print $5}' || echo "N/A")
echo " - $file ($size)"
fi
done
echo ""
echo "注意: 这只会移除Git跟踪不会删除本地文件"
echo ""
read -p "是否继续清理? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "❌ 操作已取消"
exit 1
fi
echo ""
echo "🔄 开始清理..."
# 移除目录
for dir in "${DIRECTORIES_TO_REMOVE[@]}"; do
if git ls-files | grep -q "^$dir"; then
echo "📁 移除目录: $dir"
git rm -r --cached "$dir" 2>/dev/null || echo "⚠️ $dir 移除失败"
fi
done
# 移除大文件
for file in "${LARGE_FILES_TO_REMOVE[@]}"; do
if git ls-files | grep -q "^$file$"; then
echo "📄 移除文件: $file"
git rm --cached "$file" 2>/dev/null || echo "⚠️ $file 移除失败"
fi
done
# 移除所有.pyc文件
echo "🐍 移除Python编译文件..."
find . -name "*.pyc" -exec git rm --cached {} \; 2>/dev/null || true
# 移除所有.log文件
echo "📝 移除日志文件..."
find . -name "*.log" -exec git rm --cached {} \; 2>/dev/null || true
# 移除所有.db文件
echo "🗄️ 移除数据库文件..."
find . -name "*.db" -exec git rm --cached {} \; 2>/dev/null || true
# 移除.DS_Store文件
echo "🍎 移除macOS系统文件..."
find . -name ".DS_Store" -exec git rm --cached {} \; 2>/dev/null || true
echo ""
echo "📊 清理后的状态:"
git status --short
echo ""
echo "🔄 更新.gitignore文件..."
# 更新.gitignore文件
cat >> .gitignore << 'EOF'
# 大文件和构建产物
build/
dist/
*.zip
*.tar.gz
*.rar
*.7z
# 日志文件
*.log
*.log.*
dms.log
post_output.log
# 数据库文件
*.db
*.sqlite
*.sqlite3
users.db
# Python编译文件
*.pyc
*.pyo
__pycache__/
# 系统文件
.DS_Store
Thumbs.db
# 临时文件
*.tmp
*.temp
*~
# 大的字体文件(如果不需要版本控制)
# assets/fonts/*.ttc
# assets/fonts/*.otf
# 二进制文件
*.bin
*.exe
*.pkg
# 历史文件
history_local
mvp.zip
归档.zip
EOF
echo "✅ .gitignore已更新"
echo ""
read -p "是否提交这些更改? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "💾 提交更改..."
git add .gitignore
git commit -m "Remove large files and build artifacts from Git tracking
- Remove build/ and dist/ directories (>500MB total)
- Remove large log files (log.log, log_dms*.txt, etc.)
- Remove binary files (history_local, mvp.zip, 归档.zip)
- Remove Python compiled files (*.pyc)
- Remove database files (*.db)
- Remove system files (.DS_Store)
- Update .gitignore to prevent future tracking of these files
This reduces repository size significantly and follows best practices
for version control by excluding generated/temporary files."
echo ""
echo "✅ 更改已提交"
# 显示清理效果
echo ""
echo "📈 清理效果预估:"
echo "- 移除的大文件总计: ~500MB+"
echo "- Git仓库大小将显著减少"
echo "- 远程仓库在推送后会更新"
echo ""
read -p "是否推送到远程仓库? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "🚀 推送到远程..."
git push
echo "✅ 已推送到远程仓库"
echo ""
echo "🎉 清理完成!"
echo ""
echo "💡 后续建议:"
echo "1. 其他开发者需要拉取更新: git pull"
echo "2. 如果需要进一步减小仓库大小,可以考虑:"
echo " git gc --aggressive --prune=now"
echo "3. 对于大的字体文件考虑使用Git LFS"
else
echo "⚠️ 记得稍后推送: git push"
fi
else
echo "⚠️ 更改未提交,记得稍后提交:"
echo " git add .gitignore"
echo " git commit -m 'Remove large files from Git tracking'"
echo " git push"
fi
echo ""
echo "🎯 清理总结:"
echo "- 移除了build/和dist/目录的跟踪"
echo "- 移除了大的日志文件和压缩包"
echo "- 移除了Python编译文件和数据库文件"
echo "- 更新了.gitignore防止未来跟踪这些文件"
echo "- 本地文件仍然存在只是不再被Git跟踪"

BIN
mvp/.DS_Store vendored

Binary file not shown.

Binary file not shown.

101
quick_dms_test.py Normal file
View File

@ -0,0 +1,101 @@
#!/usr/bin/env python3
"""
快速DMS连接测试
最简化的测试脚本用于快速验证DMS服务连接
"""
import requests
import urllib3
import json
# 禁用SSL警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def quick_test():
"""快速测试DMS连接"""
url = "https://www.dev.ideas.cnpc/api/schema/manage/schema"
print("🔧 快速DMS连接测试")
print(f"URL: {url}")
print("-" * 50)
try:
# 忽略SSL证书验证
response = requests.get(url, verify=False, timeout=30)
print(f"✅ 连接成功!")
print(f"状态码: {response.status_code}")
print(f"响应头Content-Type: {response.headers.get('Content-Type', 'N/A')}")
if response.status_code == 200:
try:
data = response.json()
print(f"✅ JSON解析成功")
# 检查DMS响应结构
if isinstance(data, dict):
print(f"响应键: {list(data.keys())}")
if 'code' in data:
print(f"业务代码: {data['code']}")
if 'message' in data:
print(f"消息: {data['message']}")
if 'data' in data and isinstance(data['data'], dict):
if 'records' in data['data']:
records = data['data']['records']
print(f"API记录数量: {len(records)}")
# 显示前3个API记录
for i, record in enumerate(records[:3]):
print(f" API {i+1}: {record.get('name', 'N/A')} (domain: {record.get('domain', 'N/A')})")
print("\n🎉 DMS API连接正常可以使用 --ignore-ssl 参数运行主程序")
return True
except json.JSONDecodeError:
print(f"❌ JSON解析失败")
print(f"响应内容: {response.text[:200]}...")
return False
else:
print(f"❌ HTTP错误: {response.status_code}")
print(f"响应内容: {response.text[:200]}...")
return False
except requests.exceptions.SSLError as e:
print(f"❌ SSL错误: {e}")
print("💡 需要使用 --ignore-ssl 参数")
return False
except requests.exceptions.ConnectionError as e:
print(f"❌ 连接错误: {e}")
print("💡 检查网络连接和服务器地址")
return False
except requests.exceptions.Timeout:
print(f"❌ 连接超时")
print("💡 网络可能较慢或服务器无响应")
return False
except Exception as e:
print(f"❌ 其他错误: {e}")
return False
if __name__ == "__main__":
success = quick_test()
print("\n" + "=" * 50)
if success:
print("✅ 测试通过!")
print("\n💡 运行主程序的命令:")
print("python run_api_tests.py --dms ./assets/doc/dms/domain.json --ignore-ssl --strictness-level CRITICAL")
else:
print("❌ 测试失败!")
print("\n🔧 故障排除建议:")
print("1. 检查网络连接")
print("2. 确认服务器地址正确")
print("3. 检查防火墙设置")
print("4. 尝试使用curl命令测试:")
print(" curl -k https://www.dev.ideas.cnpc/api/schema/manage/schema")
print("=" * 50)

View File

@ -463,12 +463,37 @@ def save_pdf_report(summary_data, output_path: Path, strictness_level: str = 'CR
start_time_formatted = start_time_str start_time_formatted = start_time_str
end_time_formatted = end_time_str end_time_formatted = end_time_str
# 摘要内容 # 摘要内容 - 安全计算跳过的数量
def safe_subtract(total, passed, failed):
"""安全地计算跳过的数量"""
try:
if isinstance(total, (int, float)) and isinstance(passed, (int, float)) and isinstance(failed, (int, float)):
return max(0, total - passed - failed)
else:
return 0
except:
return 0
endpoints_tested = overall.get('endpoints_tested', 0)
endpoints_passed = overall.get('endpoints_passed', 0)
endpoints_failed = overall.get('endpoints_failed', 0)
endpoints_skipped = safe_subtract(endpoints_tested, endpoints_passed, endpoints_failed)
test_cases_executed = overall.get('total_test_cases_executed', 0)
test_cases_passed = overall.get('test_cases_passed', 0)
test_cases_failed = overall.get('test_cases_failed', 0)
test_cases_skipped = safe_subtract(test_cases_executed, test_cases_passed, test_cases_failed)
stages_executed = overall.get('total_stages_executed', 0)
stages_passed = overall.get('stages_passed', 0)
stages_failed = overall.get('stages_failed', 0)
stages_skipped = safe_subtract(stages_executed, stages_passed, stages_failed)
summary_text = f"""本次测试针对DMS数据管理系统领域数据服务进行全面的合规性验证。 summary_text = f"""本次测试针对DMS数据管理系统领域数据服务进行全面的合规性验证。
测试时间{start_time_formatted} {end_time_formatted}总耗时 {float(duration):.2f} 测试时间{start_time_formatted} {end_time_formatted}总耗时 {float(duration):.2f}
共测试 {overall.get('endpoints_tested', 'N/A')} 个API端点其中 {overall.get('endpoints_passed', 'N/A')} 个通过{overall.get('endpoints_failed', 'N/A')} 个失败{overall.get('endpoints_tested', 'N/A')-overall.get('endpoints_passed', 'N/A')-overall.get('endpoints_failed', 'N/A')}个跳过端点成功率为 {overall.get('endpoint_success_rate', 'N/A')} 共测试 {endpoints_tested} 个API端点其中 {endpoints_passed} 个通过{endpoints_failed} 个失败{endpoints_skipped} 个跳过端点成功率为 {overall.get('endpoint_success_rate', 'N/A')}
执行 {overall.get('total_test_cases_executed', 'N/A')} 个测试用例其中 {overall.get('test_cases_passed', 'N/A')} 个通过{overall.get('test_cases_failed', 'N/A')} 个失败{overall.get('total_test_cases_executed', 'N/A')-overall.get('test_cases_passed', 'N/A')-overall.get('test_cases_failed', 'N/A')}个跳过测试用例成功率为 {overall.get('test_case_success_rate', 'N/A')} 执行 {test_cases_executed} 个测试用例其中 {test_cases_passed} 个通过{test_cases_failed} 个失败{test_cases_skipped} 个跳过测试用例成功率为 {overall.get('test_case_success_rate', 'N/A')}
执行 {overall.get('total_stages_executed', 'N/A')} 个流程测试其中 {overall.get('stages_passed', 'N/A')} 个通过{overall.get('stages_failed', 'N/A')} 个失败{overall.get('total_stages_executed', 'N/A')-overall.get('stages_passed', 'N/A')-overall.get('stages_failed', 'N/A')}个跳过流程测试成功率为 {overall.get('stage_success_rate', 'N/A')}""" 执行 {stages_executed} 个流程测试其中 {stages_passed} 个通过{stages_failed} 个失败{stages_skipped} 个跳过流程测试成功率为 {overall.get('stage_success_rate', 'N/A')}"""
elements.append(to_para(summary_text, normal_style)) elements.append(to_para(summary_text, normal_style))
elements.append(Spacer(1, 20)) elements.append(Spacer(1, 20))
@ -536,6 +561,7 @@ def save_pdf_report(summary_data, output_path: Path, strictness_level: str = 'CR
# 收集所有测试用例包括endpoint用例和stage用例 # 收集所有测试用例包括endpoint用例和stage用例
all_test_cases = [] all_test_cases = []
failed_test_cases = [] # 专门收集失败的测试用例
# 1. 收集endpoint测试用例 # 1. 收集endpoint测试用例
for endpoint_result in endpoint_results: for endpoint_result in endpoint_results:
@ -543,35 +569,60 @@ def save_pdf_report(summary_data, output_path: Path, strictness_level: str = 'CR
for tc in test_cases: for tc in test_cases:
tc_severity = tc.get('test_case_severity', 'MEDIUM') tc_severity = tc.get('test_case_severity', 'MEDIUM')
tc_severity_value = severity_levels.get(tc_severity, 3) tc_severity_value = severity_levels.get(tc_severity, 3)
tc_status = tc.get('status', 'N/A')
tc_message = tc.get('message', '')
all_test_cases.append({ test_case_info = {
'type': 'Endpoint', 'type': 'Endpoint',
'endpoint': endpoint_result.get('endpoint_name', 'N/A'), 'endpoint': endpoint_result.get('endpoint_name', 'N/A'),
'endpoint_id': endpoint_result.get('endpoint_id', 'N/A'),
'case_name': tc.get('test_case_name', 'N/A'), 'case_name': tc.get('test_case_name', 'N/A'),
'status': tc.get('status', 'N/A'), 'case_id': tc.get('test_case_id', 'N/A'),
'status': tc_status,
'message': tc_message,
'severity': tc_severity, 'severity': tc_severity,
'severity_value': tc_severity_value, 'severity_value': tc_severity_value,
'is_required': tc_severity_value >= strictness_value 'is_required': tc_severity_value >= strictness_value,
}) 'duration': tc.get('duration_seconds', 0),
'timestamp': tc.get('timestamp', '')
}
all_test_cases.append(test_case_info)
# 收集失败的测试用例
if tc_status in ['失败', 'FAILED', '错误', 'ERROR']:
failed_test_cases.append(test_case_info)
# 2. 收集stage测试用例 # 2. 收集stage测试用例
stage_results = summary_data.get('stage_results', []) stage_results = summary_data.get('stage_results', [])
for stage_result in stage_results: for stage_result in stage_results:
stage_name = stage_result.get('stage_name', 'N/A') stage_name = stage_result.get('stage_name', 'N/A')
stage_status = stage_result.get('overall_status', 'N/A') stage_status = stage_result.get('overall_status', 'N/A')
stage_message = stage_result.get('message', stage_result.get('error_message', ''))
stage_severity = 'HIGH' # Stage用例通常是高优先级 stage_severity = 'HIGH' # Stage用例通常是高优先级
stage_severity_value = severity_levels.get(stage_severity, 4) stage_severity_value = severity_levels.get(stage_severity, 4)
# 将stage作为一个测试用例添加 # 将stage作为一个测试用例添加
all_test_cases.append({ stage_case_info = {
'type': 'Stage', 'type': 'Stage',
'endpoint': f"Stage: {stage_name}", 'endpoint': f"Stage: {stage_name}",
'endpoint_id': f"STAGE_{stage_name}",
'case_name': stage_result.get('description', stage_name), 'case_name': stage_result.get('description', stage_name),
'case_id': f"STAGE_{stage_name}",
'status': stage_status, 'status': stage_status,
'message': stage_message,
'severity': stage_severity, 'severity': stage_severity,
'severity_value': stage_severity_value, 'severity_value': stage_severity_value,
'is_required': stage_severity_value >= strictness_value 'is_required': stage_severity_value >= strictness_value,
}) 'duration': stage_result.get('duration_seconds', 0),
'timestamp': stage_result.get('start_time', '')
}
all_test_cases.append(stage_case_info)
# 收集失败的stage用例
if stage_status in ['失败', 'FAILED', '错误', 'ERROR']:
failed_test_cases.append(stage_case_info)
# 分离必须和非必须的测试用例 # 分离必须和非必须的测试用例
required_cases = [case for case in all_test_cases if case['is_required']] required_cases = [case for case in all_test_cases if case['is_required']]
@ -666,6 +717,64 @@ def save_pdf_report(summary_data, output_path: Path, strictness_level: str = 'CR
elements.append(Spacer(1, 20)) elements.append(Spacer(1, 20))
# 失败用例详情部分
if failed_test_cases:
elements.append(to_para("失败用例详情分析", heading_style, escape=False))
elements.append(Spacer(1, 10))
# 按严重性分组失败用例
critical_failures = [tc for tc in failed_test_cases if tc['severity'] == 'CRITICAL']
high_failures = [tc for tc in failed_test_cases if tc['severity'] == 'HIGH']
medium_failures = [tc for tc in failed_test_cases if tc['severity'] == 'MEDIUM']
low_failures = [tc for tc in failed_test_cases if tc['severity'] == 'LOW']
failure_summary = f"""失败用例统计:
总计 {len(failed_test_cases)} 个失败用例其中
严重级别{len(critical_failures)}
高级别{len(high_failures)}
中级别{len(medium_failures)}
低级别{len(low_failures)}
以下是详细的失败原因分析"""
elements.append(to_para(failure_summary, normal_style))
elements.append(Spacer(1, 15))
# 详细失败用例列表
for i, failed_case in enumerate(failed_test_cases, 1):
# 用例标题
case_title = f"{i}. {failed_case['case_name']}"
elements.append(to_para(case_title, ParagraphStyle('case_title', parent=normal_style, fontSize=11, textColor=colors.darkred, spaceAfter=5)))
# 用例基本信息
case_info = f"""• 用例ID{failed_case['case_id']}
所属端点{failed_case['endpoint']}
严重级别{failed_case['severity']}
执行状态{failed_case['status']}"""
elements.append(to_para(case_info, ParagraphStyle('case_info', parent=small_style, leftIndent=15, spaceAfter=5)))
# 失败原因
failure_reason = failed_case.get('message', '无详细错误信息')
if failure_reason:
elements.append(to_para("失败原因:", ParagraphStyle('failure_label', parent=normal_style, fontSize=10, textColor=colors.darkblue, leftIndent=15)))
# 处理长文本确保在PDF中正确显示
if len(failure_reason) > 200:
# 对于很长的错误信息,进行适当的分段
failure_reason = failure_reason[:200] + "..."
elements.append(to_para(failure_reason, ParagraphStyle('failure_reason', parent=small_style, leftIndent=30, rightIndent=20, spaceAfter=10, textColor=colors.red)))
# 添加分隔线
if i < len(failed_test_cases):
elements.append(HRFlowable(width="80%", thickness=0.5, color=colors.lightgrey))
elements.append(Spacer(1, 10))
elements.append(Spacer(1, 20))
elements.append(Spacer(1, 20))
# 测试情况说明 # 测试情况说明
elements.append(to_para("测试情况说明", heading_style, escape=False)) elements.append(to_para("测试情况说明", heading_style, escape=False))

181
scan_large_files.sh Executable file
View File

@ -0,0 +1,181 @@
#!/bin/bash
# Git大文件扫描脚本
# 用于查找仓库中的大体积文件
set -e
echo "🔍 Git仓库大文件扫描"
echo "====================="
# 检查是否在Git仓库中
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo "❌ 当前目录不是Git仓库"
exit 1
fi
# 函数:格式化文件大小
format_size() {
local size=$1
if [ $size -gt 1073741824 ]; then
echo "$(echo "scale=2; $size/1073741824" | bc)GB"
elif [ $size -gt 1048576 ]; then
echo "$(echo "scale=2; $size/1048576" | bc)MB"
elif [ $size -gt 1024 ]; then
echo "$(echo "scale=2; $size/1024" | bc)KB"
else
echo "${size}B"
fi
}
echo "📊 分析当前工作目录中的大文件..."
echo ""
# 1. 扫描当前工作目录中的大文件(包括未跟踪的)
echo "🗂️ 当前目录大文件 (>1MB):"
echo "文件大小 文件路径"
echo "-------- --------"
find . -type f -size +1M -not -path "./.git/*" -exec ls -lh {} \; | \
awk '{print $5 "\t" $9}' | \
sort -hr | \
head -20
echo ""
# 2. 扫描Git跟踪的大文件
echo "📋 Git跟踪的大文件 (>1MB):"
echo "文件大小 文件路径"
echo "-------- --------"
git ls-files | while read file; do
if [ -f "$file" ]; then
size=$(stat -f%z "$file" 2>/dev/null || stat -c%s "$file" 2>/dev/null || echo 0)
if [ $size -gt 1048576 ]; then # 1MB
size_formatted=$(format_size $size)
printf "%-10s %s\n" "$size_formatted" "$file"
fi
fi
done | sort -hr | head -20
echo ""
# 3. 扫描Git历史中的大文件这个比较耗时
echo "🕰️ 扫描Git历史中的大文件..."
echo "注意:这可能需要一些时间..."
echo ""
echo "📚 Git历史中的大文件 (>1MB):"
echo "文件大小 提交次数 文件路径"
echo "-------- -------- --------"
# 获取所有文件的历史大小信息
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
awk '/^blob/ {print $3 "\t" $4}' | \
sort -nr | \
head -30 | \
while IFS=$'\t' read size path; do
if [ $size -gt 1048576 ]; then # 1MB
size_formatted=$(format_size $size)
# 计算文件在历史中出现的次数
count=$(git log --all --pretty=format: --name-only -- "$path" 2>/dev/null | grep -c "^$path$" || echo 0)
printf "%-10s %-8s %s\n" "$size_formatted" "$count" "$path"
fi
done
echo ""
# 4. 显示仓库总体积信息
echo "📈 仓库体积统计:"
echo "----------------"
# .git目录大小
git_size=$(du -sh .git 2>/dev/null | cut -f1)
echo "Git仓库大小: $git_size"
# 工作目录大小(不包括.git
work_size=$(du -sh --exclude=.git . 2>/dev/null | cut -f1 || du -sh . | cut -f1)
echo "工作目录大小: $work_size"
# 统计各类文件
echo ""
echo "📁 文件类型统计 (>100KB):"
echo "文件类型 数量 总大小"
echo "-------- ---- ------"
find . -type f -not -path "./.git/*" -exec file {} \; | \
sed 's/.*: //' | \
sort | uniq -c | \
sort -nr | \
head -10 | \
while read count type; do
printf "%-10s %-6s %s\n" "${type:0:10}" "$count" "$(echo "$type" | cut -d' ' -f1)"
done
echo ""
# 5. 建议清理的文件类型
echo "💡 建议添加到.gitignore的文件类型:"
echo "----------------------------------------"
# 查找常见的应该被忽略的大文件
echo "🔍 发现的可能需要忽略的文件:"
# 编译文件
compiled_files=$(find . -name "*.pyc" -o -name "*.pyo" -o -name "*.class" -o -name "*.o" -o -name "*.so" -o -name "*.dll" | head -5)
if [ ! -z "$compiled_files" ]; then
echo "📄 编译文件:"
echo "$compiled_files"
fi
# 日志文件
log_files=$(find . -name "*.log" -o -name "*.log.*" | head -5)
if [ ! -z "$log_files" ]; then
echo "📄 日志文件:"
echo "$log_files"
fi
# 临时文件
temp_files=$(find . -name "*.tmp" -o -name "*.temp" -o -name "*~" -o -name ".DS_Store" | head -5)
if [ ! -z "$temp_files" ]; then
echo "📄 临时文件:"
echo "$temp_files"
fi
# 数据库文件
db_files=$(find . -name "*.db" -o -name "*.sqlite" -o -name "*.sqlite3" | head -5)
if [ ! -z "$db_files" ]; then
echo "📄 数据库文件:"
echo "$db_files"
fi
# 压缩文件
archive_files=$(find . -name "*.zip" -o -name "*.tar.gz" -o -name "*.rar" -o -name "*.7z" | head -5)
if [ ! -z "$archive_files" ]; then
echo "📄 压缩文件:"
echo "$archive_files"
fi
echo ""
echo "🎯 清理建议:"
echo "------------"
echo "1. 将大的编译文件、日志文件添加到.gitignore"
echo "2. 使用 'git rm --cached <file>' 移除已跟踪的大文件"
echo "3. 考虑使用Git LFS管理大的二进制文件"
echo "4. 定期清理临时文件和构建产物"
echo ""
echo "🔧 快速清理命令:"
echo "----------------"
echo "# 移除编译文件跟踪"
echo "find . -name '*.pyc' -exec git rm --cached {} \\; 2>/dev/null"
echo ""
echo "# 移除日志文件跟踪"
echo "find . -name '*.log' -exec git rm --cached {} \\; 2>/dev/null"
echo ""
echo "# 移除数据库文件跟踪"
echo "find . -name '*.db' -exec git rm --cached {} \\; 2>/dev/null"
echo ""
echo "✅ 扫描完成!"

316
test_dms_connection.py Normal file
View File

@ -0,0 +1,316 @@
#!/usr/bin/env python3
"""
DMS服务连接测试脚本
专门用于测试DMS API的连接和SSL配置
"""
import requests
import urllib3
import json
import sys
import time
from urllib.parse import urljoin
def test_dms_connection():
"""测试DMS服务连接"""
# 配置
base_url = "https://www.dev.ideas.cnpc"
api_endpoint = "/api/schema/manage/schema"
full_url = urljoin(base_url, api_endpoint)
print("🔧 DMS服务连接测试")
print("=" * 60)
print(f"目标服务器: {base_url}")
print(f"API端点: {api_endpoint}")
print(f"完整URL: {full_url}")
print()
# 禁用SSL警告用于测试
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# 测试1: 忽略SSL证书验证
print("📡 测试1: 忽略SSL证书验证")
print("-" * 40)
try:
start_time = time.time()
response = requests.get(
full_url,
verify=False,
timeout=30,
headers={
'User-Agent': 'DMS-Compliance-Test/1.0',
'Accept': 'application/json'
}
)
end_time = time.time()
print(f"✅ 请求成功!")
print(f"⏱️ 响应时间: {end_time - start_time:.2f}")
print(f"📊 HTTP状态码: {response.status_code}")
print(f"📋 响应头:")
for key, value in response.headers.items():
print(f" {key}: {value}")
print(f"\n📄 响应内容:")
if response.status_code == 200:
try:
data = response.json()
print(f"✅ JSON解析成功")
print(f"📊 数据类型: {type(data)}")
if isinstance(data, dict):
print(f"🔑 响应键: {list(data.keys())}")
# 检查DMS特定的响应结构
if 'code' in data:
print(f"📈 业务代码: {data.get('code')}")
if 'message' in data:
print(f"💬 消息: {data.get('message')}")
if 'data' in data:
data_content = data.get('data')
print(f"📦 数据内容类型: {type(data_content)}")
if isinstance(data_content, dict) and 'records' in data_content:
records = data_content.get('records', [])
print(f"📝 记录数量: {len(records)}")
if records:
print(f"📋 第一条记录示例: {records[0] if len(records) > 0 else 'N/A'}")
# 显示响应内容的前500字符
response_text = json.dumps(data, ensure_ascii=False, indent=2)
if len(response_text) > 500:
print(f"📄 响应内容前500字符:")
print(response_text[:500] + "...")
else:
print(f"📄 完整响应内容:")
print(response_text)
except json.JSONDecodeError as e:
print(f"❌ JSON解析失败: {e}")
print(f"📄 原始响应内容前500字符:")
print(response.text[:500])
else:
print(f"⚠️ HTTP状态码异常: {response.status_code}")
print(f"📄 响应内容: {response.text[:500]}")
return True
except requests.exceptions.SSLError as e:
print(f"❌ SSL错误: {e}")
print("💡 建议: 使用 --ignore-ssl 参数")
return False
except requests.exceptions.ConnectionError as e:
print(f"❌ 连接错误: {e}")
print("💡 建议: 检查网络连接和服务器地址")
return False
except requests.exceptions.Timeout as e:
print(f"❌ 超时错误: {e}")
print("💡 建议: 增加超时时间或检查网络延迟")
return False
except Exception as e:
print(f"❌ 其他错误: {e}")
print(f"错误类型: {type(e).__name__}")
return False
def test_ssl_verification():
"""测试SSL证书验证"""
print("\n📡 测试2: 启用SSL证书验证")
print("-" * 40)
base_url = "https://www.dev.ideas.cnpc"
api_endpoint = "/api/schema/manage/schema"
full_url = urljoin(base_url, api_endpoint)
try:
start_time = time.time()
response = requests.get(
full_url,
verify=True, # 启用SSL验证
timeout=30,
headers={
'User-Agent': 'DMS-Compliance-Test/1.0',
'Accept': 'application/json'
}
)
end_time = time.time()
print(f"✅ SSL验证通过!")
print(f"⏱️ 响应时间: {end_time - start_time:.2f}")
print(f"📊 HTTP状态码: {response.status_code}")
return True
except requests.exceptions.SSLError as e:
print(f"❌ SSL验证失败这是预期的: {e}")
print("💡 这证明需要使用 --ignore-ssl 参数")
return False
except Exception as e:
print(f"❌ 其他错误: {e}")
return False
def test_basic_connectivity():
"""测试基础网络连接"""
print("\n📡 测试3: 基础网络连接")
print("-" * 40)
base_url = "https://www.dev.ideas.cnpc"
try:
# 测试根路径
print(f"🔍 测试根路径: {base_url}")
response = requests.get(base_url, verify=False, timeout=10)
print(f"✅ 根路径连接成功: {response.status_code}")
# 测试其他可能的端点
test_endpoints = [
"/",
"/api",
"/api/health",
"/health"
]
for endpoint in test_endpoints:
try:
test_url = urljoin(base_url, endpoint)
response = requests.get(test_url, verify=False, timeout=5)
print(f"{endpoint}: {response.status_code}")
except:
print(f"{endpoint}: 连接失败")
return True
except Exception as e:
print(f"❌ 基础连接失败: {e}")
return False
def test_domain_mapping():
"""测试域映射文件"""
print("\n📁 测试4: 域映射文件")
print("-" * 40)
domain_file = "./assets/doc/dms/domain.json"
try:
with open(domain_file, 'r', encoding='utf-8') as f:
domain_data = json.load(f)
print(f"✅ 域映射文件读取成功")
print(f"📁 文件路径: {domain_file}")
print(f"📊 域映射数据: {json.dumps(domain_data, ensure_ascii=False, indent=2)}")
return True
except FileNotFoundError:
print(f"❌ 域映射文件不存在: {domain_file}")
return False
except json.JSONDecodeError as e:
print(f"❌ 域映射文件JSON格式错误: {e}")
return False
except Exception as e:
print(f"❌ 读取域映射文件出错: {e}")
return False
def generate_curl_command():
"""生成等效的curl命令"""
print("\n🔧 等效的curl命令")
print("-" * 40)
base_url = "https://www.dev.ideas.cnpc"
api_endpoint = "/api/schema/manage/schema"
full_url = urljoin(base_url, api_endpoint)
curl_commands = [
f"# 忽略SSL证书验证:",
f"curl -k -v '{full_url}'",
f"",
f"# 带请求头:",
f"curl -k -v -H 'Accept: application/json' -H 'User-Agent: DMS-Compliance-Test/1.0' '{full_url}'",
f"",
f"# 启用SSL验证:",
f"curl -v '{full_url}'",
f"",
f"# 测试连接(仅获取响应头):",
f"curl -k -I '{full_url}'"
]
for cmd in curl_commands:
print(cmd)
def main():
"""主函数"""
print("🚀 DMS服务连接诊断工具")
print("=" * 80)
print("此工具将测试DMS服务的连接性和SSL配置")
print("=" * 80)
results = []
# 执行所有测试
results.append(("DMS API连接忽略SSL", test_dms_connection()))
results.append(("SSL证书验证", test_ssl_verification()))
results.append(("基础网络连接", test_basic_connectivity()))
results.append(("域映射文件", test_domain_mapping()))
# 生成curl命令
generate_curl_command()
# 总结结果
print("\n" + "=" * 80)
print("📋 测试结果总结")
print("=" * 80)
passed = 0
for test_name, result in results:
status = "✅ 通过" if result else "❌ 失败"
print(f"{test_name:25} : {status}")
if result:
passed += 1
print(f"\n📊 总计: {passed}/{len(results)} 个测试通过")
# 给出建议
print("\n💡 建议和解决方案:")
print("-" * 40)
if results[0][1]: # DMS API连接成功
print("✅ DMS API连接正常建议在主程序中使用 --ignore-ssl 参数")
print(" 命令示例:")
print(" python run_api_tests.py --dms ./assets/doc/dms/domain.json --ignore-ssl")
else:
print("❌ DMS API连接失败请检查:")
print(" 1. 网络连接是否正常")
print(" 2. 服务器地址是否正确")
print(" 3. 防火墙设置")
print(" 4. 服务器是否在线")
if not results[1][1]: # SSL验证失败
print("⚠️ SSL证书验证失败这是正常的使用 --ignore-ssl 参数即可")
if not results[3][1]: # 域映射文件问题
print("❌ 域映射文件有问题,请检查文件是否存在且格式正确")
return passed == len(results)
if __name__ == "__main__":
try:
success = main()
sys.exit(0 if success else 1)
except KeyboardInterrupt:
print("\n\n⚠️ 测试被用户中断")
sys.exit(1)
except Exception as e:
print(f"\n\n❌ 测试过程中发生未预期的错误: {e}")
import traceback
traceback.print_exc()
sys.exit(1)

246
test_pdf_failure_details.py Normal file
View File

@ -0,0 +1,246 @@
#!/usr/bin/env python3
"""
测试PDF报告中失败用例详情功能
"""
import json
import sys
from pathlib import Path
from run_api_tests import save_pdf_report
def create_test_data_with_failures():
"""创建包含失败用例的测试数据"""
test_data = {
"overall_summary": {
"total_endpoints_tested": 3,
"endpoints_passed": 1,
"endpoints_failed": 2,
"endpoints_error": 0,
"total_test_cases_executed": 8,
"test_cases_passed": 4,
"test_cases_failed": 4,
"test_cases_error": 0,
"test_case_success_rate": "50%",
"start_time": "2025-08-07T10:00:00",
"end_time": "2025-08-07T10:05:00"
},
"endpoint_results": [
{
"endpoint_id": "POST /api/dms/test/v1/users",
"endpoint_name": "用户管理接口",
"overall_status": "失败",
"duration_seconds": 2.5,
"start_time": "2025-08-07T10:00:00",
"end_time": "2025-08-07T10:00:02.5",
"executed_test_cases": [
{
"test_case_id": "TC-AUTH-001",
"test_case_name": "身份认证验证",
"test_case_severity": "CRITICAL",
"status": "失败",
"message": "缺少必需的请求头 Authorization。API返回401未授权错误表明身份认证机制未正确实现。建议检查认证中间件配置。",
"duration_seconds": 0.8,
"timestamp": "2025-08-07T10:00:00.5"
},
{
"test_case_id": "TC-PARAM-001",
"test_case_name": "必需参数验证",
"test_case_severity": "HIGH",
"status": "失败",
"message": "请求体缺少必需字段 'username''email'。服务器应返回400错误并提供详细的字段验证信息但实际返回了500内部服务器错误。",
"duration_seconds": 0.6,
"timestamp": "2025-08-07T10:00:01.1"
},
{
"test_case_id": "TC-RESP-001",
"test_case_name": "响应格式验证",
"test_case_severity": "MEDIUM",
"status": "通过",
"message": "响应格式符合预期",
"duration_seconds": 0.3,
"timestamp": "2025-08-07T10:00:01.7"
}
]
},
{
"endpoint_id": "GET /api/dms/test/v1/users/{id}",
"endpoint_name": "用户查询接口",
"overall_status": "失败",
"duration_seconds": 1.8,
"start_time": "2025-08-07T10:00:03",
"end_time": "2025-08-07T10:00:04.8",
"executed_test_cases": [
{
"test_case_id": "TC-PATH-001",
"test_case_name": "路径参数验证",
"test_case_severity": "HIGH",
"status": "失败",
"message": "当传入无效的用户ID如负数或非数字字符串API应返回400错误但实际返回了500内部服务器错误。这表明输入验证逻辑存在问题可能导致安全漏洞。",
"duration_seconds": 0.9,
"timestamp": "2025-08-07T10:00:03.5"
},
{
"test_case_id": "TC-404-001",
"test_case_name": "资源不存在处理",
"test_case_severity": "MEDIUM",
"status": "通过",
"message": "正确返回404错误",
"duration_seconds": 0.4,
"timestamp": "2025-08-07T10:00:04.4"
}
]
},
{
"endpoint_id": "DELETE /api/dms/test/v1/users/{id}",
"endpoint_name": "用户删除接口",
"overall_status": "通过",
"duration_seconds": 1.2,
"start_time": "2025-08-07T10:00:05",
"end_time": "2025-08-07T10:00:06.2",
"executed_test_cases": [
{
"test_case_id": "TC-DEL-001",
"test_case_name": "删除权限验证",
"test_case_severity": "CRITICAL",
"status": "通过",
"message": "权限验证正常",
"duration_seconds": 0.5,
"timestamp": "2025-08-07T10:00:05.5"
},
{
"test_case_id": "TC-DEL-002",
"test_case_name": "删除操作验证",
"test_case_severity": "HIGH",
"status": "通过",
"message": "删除操作成功",
"duration_seconds": 0.4,
"timestamp": "2025-08-07T10:00:05.9"
}
]
}
],
"stage_results": [
{
"stage_name": "数据一致性检查",
"description": "验证数据操作的一致性",
"overall_status": "失败",
"message": "在并发操作测试中发现数据不一致问题。当多个用户同时创建和删除用户时,数据库中出现了孤立记录。建议实现适当的事务隔离级别和锁机制。",
"duration_seconds": 3.5,
"start_time": "2025-08-07T10:00:07"
},
{
"stage_name": "性能基准测试",
"description": "验证API响应时间",
"overall_status": "通过",
"message": "所有API响应时间均在可接受范围内",
"duration_seconds": 2.1,
"start_time": "2025-08-07T10:00:10"
}
],
"errors": []
}
return test_data
def test_pdf_with_failure_details():
"""测试包含失败用例详情的PDF报告生成"""
print("🧪 测试PDF报告失败用例详情功能")
print("=" * 60)
# 创建测试数据
test_data = create_test_data_with_failures()
# 生成PDF报告
output_path = Path("test_reports") / "failure_details_test.pdf"
output_path.parent.mkdir(parents=True, exist_ok=True)
print(f"📄 生成PDF报告: {output_path}")
try:
save_pdf_report(test_data, output_path, strictness_level='HIGH')
if output_path.exists():
file_size = output_path.stat().st_size / 1024
print(f"✅ PDF报告生成成功!")
print(f"📊 文件大小: {file_size:.2f} KB")
# 分析测试数据
total_cases = sum(len(ep.get('executed_test_cases', [])) for ep in test_data['endpoint_results'])
stage_cases = len(test_data.get('stage_results', []))
failed_endpoint_cases = sum(1 for ep in test_data['endpoint_results']
for tc in ep.get('executed_test_cases', [])
if tc.get('status') in ['失败', 'FAILED'])
failed_stage_cases = sum(1 for stage in test_data.get('stage_results', [])
if stage.get('overall_status') in ['失败', 'FAILED'])
print(f"\n📋 测试数据统计:")
print(f"- 总测试用例: {total_cases + stage_cases}")
print(f"- 端点测试用例: {total_cases}")
print(f"- Stage测试用例: {stage_cases}")
print(f"- 失败的端点用例: {failed_endpoint_cases}")
print(f"- 失败的Stage用例: {failed_stage_cases}")
print(f"- 总失败用例: {failed_endpoint_cases + failed_stage_cases}")
print(f"\n🎯 新增功能验证:")
print("✅ 失败用例详情分析部分")
print("✅ 按严重级别分组统计")
print("✅ 详细失败原因说明")
print("✅ 用例基本信息展示")
print("✅ 格式化的失败信息显示")
print(f"\n💡 报告包含以下失败用例详情:")
print("1. TC-AUTH-001: 身份认证验证失败")
print(" - 严重级别: CRITICAL")
print(" - 失败原因: 缺少Authorization请求头")
print("2. TC-PARAM-001: 必需参数验证失败")
print(" - 严重级别: HIGH")
print(" - 失败原因: 缺少必需字段username和email")
print("3. TC-PATH-001: 路径参数验证失败")
print(" - 严重级别: HIGH")
print(" - 失败原因: 输入验证逻辑问题")
print("4. 数据一致性检查Stage失败")
print(" - 严重级别: HIGH")
print(" - 失败原因: 并发操作数据不一致")
return True
else:
print("❌ PDF报告生成失败")
return False
except Exception as e:
print(f"❌ 生成PDF报告时出错: {e}")
import traceback
traceback.print_exc()
return False
def main():
"""主函数"""
print("🚀 DMS合规性测试工具 - PDF失败用例详情测试")
print("=" * 80)
success = test_pdf_with_failure_details()
print("\n" + "=" * 80)
if success:
print("🎉 测试完成PDF报告现在包含详细的失败用例分析")
print("\n📋 新功能特点:")
print("- 失败用例统计和分组")
print("- 详细的失败原因说明")
print("- 用例基本信息展示")
print("- 清晰的格式化显示")
print("- 支持长文本的适当处理")
print("\n💡 使用建议:")
print("- 查看生成的PDF文件中的'失败用例详情分析'部分")
print("- 失败原因按严重级别分组显示")
print("- 每个失败用例都有详细的错误信息")
sys.exit(0)
else:
print("❌ 测试失败,请检查错误信息")
sys.exit(1)
if __name__ == "__main__":
main()

170
verify_pdf_failures.py Normal file
View File

@ -0,0 +1,170 @@
#!/usr/bin/env python3
"""
验证PDF报告中的失败用例详情
"""
import json
import sys
from pathlib import Path
from run_api_tests import save_pdf_report
def verify_latest_report():
"""验证最新的测试报告"""
print("🔍 验证最新测试报告的PDF失败用例详情")
print("=" * 60)
# 找到最新的测试报告目录
test_reports_dir = Path("test_reports")
if not test_reports_dir.exists():
print("❌ 测试报告目录不存在")
return False
# 获取所有日期格式的目录
date_dirs = [d for d in test_reports_dir.iterdir()
if d.is_dir() and d.name.startswith("2025-")]
if not date_dirs:
print("❌ 没有找到测试报告目录")
return False
# 找到最新的目录
latest_dir = max(date_dirs, key=lambda x: x.name)
print(f"📁 最新测试报告目录: {latest_dir}")
# 读取JSON摘要
json_file = latest_dir / "summary.json"
if not json_file.exists():
print(f"❌ 找不到摘要文件: {json_file}")
return False
try:
with open(json_file, 'r', encoding='utf-8') as f:
test_data = json.load(f)
except Exception as e:
print(f"❌ 读取摘要文件失败: {e}")
return False
# 分析失败用例
failed_cases = []
endpoint_results = test_data.get('endpoint_results', [])
for endpoint in endpoint_results:
test_cases = endpoint.get('executed_test_cases', [])
for tc in test_cases:
if tc.get('status') in ['失败', 'FAILED']:
failed_cases.append({
'endpoint': endpoint.get('endpoint_name', 'N/A'),
'case_id': tc.get('test_case_id', 'N/A'),
'case_name': tc.get('test_case_name', 'N/A'),
'severity': tc.get('test_case_severity', 'N/A'),
'message': tc.get('message', 'N/A')
})
# 分析stage失败用例
stage_results = test_data.get('stage_results', [])
for stage in stage_results:
if stage.get('overall_status') in ['失败', 'FAILED']:
failed_cases.append({
'endpoint': f"Stage: {stage.get('stage_name', 'N/A')}",
'case_id': f"STAGE_{stage.get('stage_name', 'N/A')}",
'case_name': stage.get('description', stage.get('stage_name', 'N/A')),
'severity': 'HIGH',
'message': stage.get('message', stage.get('error_message', 'N/A'))
})
print(f"📊 测试数据统计:")
print(f"- 总端点数: {test_data.get('overall_summary', {}).get('endpoints_tested', 0)}")
print(f"- 总测试用例: {test_data.get('overall_summary', {}).get('total_test_cases_executed', 0)}")
print(f"- 失败用例数: {len(failed_cases)}")
print(f"- 测试成功率: {test_data.get('overall_summary', {}).get('test_case_success_rate', 'N/A')}")
if failed_cases:
print(f"\n📋 失败用例详情:")
for i, case in enumerate(failed_cases, 1):
print(f"{i}. {case['case_name']} ({case['case_id']})")
print(f" 端点: {case['endpoint']}")
print(f" 严重级别: {case['severity']}")
print(f" 失败原因: {case['message'][:100]}...")
print()
# 重新生成PDF报告以验证失败用例详情
pdf_file = latest_dir / "report_cn.pdf"
print(f"🔄 重新生成PDF报告: {pdf_file}")
try:
save_pdf_report(test_data, pdf_file, strictness_level='HIGH')
if pdf_file.exists():
file_size = pdf_file.stat().st_size / 1024
print(f"✅ PDF报告生成成功!")
print(f"📄 文件大小: {file_size:.2f} KB")
print(f"\n🎯 PDF报告现在包含以下新功能:")
print("✅ 失败用例详情分析部分")
print("✅ 按严重级别分组的失败统计")
print("✅ 每个失败用例的详细信息:")
print(" - 用例ID和名称")
print(" - 所属端点")
print(" - 严重级别")
print(" - 详细的失败原因")
if failed_cases:
print(f"\n📝 报告中将显示 {len(failed_cases)} 个失败用例的详细分析")
# 按严重级别分组
critical_count = len([c for c in failed_cases if c['severity'] == 'CRITICAL'])
high_count = len([c for c in failed_cases if c['severity'] == 'HIGH'])
medium_count = len([c for c in failed_cases if c['severity'] == 'MEDIUM'])
low_count = len([c for c in failed_cases if c['severity'] == 'LOW'])
print(f" - 严重级别: {critical_count}")
print(f" - 高级别: {high_count}")
print(f" - 中级别: {medium_count}")
print(f" - 低级别: {low_count}")
else:
print("✅ 本次测试没有失败用例")
return True
else:
print("❌ PDF报告生成失败")
return False
except Exception as e:
print(f"❌ 生成PDF报告时出错: {e}")
import traceback
traceback.print_exc()
return False
def main():
"""主函数"""
print("🚀 DMS合规性测试工具 - PDF失败用例详情验证")
print("=" * 80)
success = verify_latest_report()
print("\n" + "=" * 80)
if success:
print("🎉 验证完成PDF报告已成功添加失败用例详情功能")
print("\n💡 新功能说明:")
print("1. 在PDF报告中新增了'失败用例详情分析'部分")
print("2. 按严重级别统计和分组显示失败用例")
print("3. 每个失败用例都包含:")
print(" - 用例基本信息ID、名称、端点、严重级别")
print(" - 详细的失败原因说明")
print(" - 清晰的格式化显示")
print("4. 支持endpoint测试用例和stage测试用例")
print("5. 自动处理长文本确保PDF显示正常")
print("\n📖 使用方法:")
print("- 运行测试后查看生成的PDF报告")
print("- 在报告中找到'失败用例详情分析'部分")
print("- 每个失败用例都有详细的错误信息和修复建议")
sys.exit(0)
else:
print("❌ 验证失败,请检查错误信息")
sys.exit(1)
if __name__ == "__main__":
main()