Files
java-template/test_alert_rules_implementation.py
T
2025-09-10 20:01:13 +08:00

786 lines
29 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
告警规则系统实施完整性测试和验证
全面测试数据库、后端服务、前端组件和性能监控
@Author: Claude Code
@CreateTime: 2025-09-10
@Description: 验证告警规则系统的完整实施情况
"""
import os
import sys
import json
import time
import requests
import subprocess
from typing import Dict, List, Any, Optional
from pathlib import Path
import logging
from dataclasses import dataclass, asdict
# 配置日志
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
@dataclass
class TestResult:
"""测试结果数据类"""
test_name: str
success: bool
message: str
details: Optional[Dict] = None
execution_time: float = 0.0
@dataclass
class ValidationReport:
"""验证报告数据类"""
total_tests: int = 0
passed_tests: int = 0
failed_tests: int = 0
test_results: List[TestResult] = None
overall_success: bool = False
execution_time: float = 0.0
recommendations: List[str] = None
def __post_init__(self):
if self.test_results is None:
self.test_results = []
if self.recommendations is None:
self.recommendations = []
class AlertRulesImplementationValidator:
"""告警规则系统实施验证器"""
def __init__(self, base_path: str = "/Users/brunogao/work/codes/93/release"):
self.base_path = Path(base_path)
self.results = []
self.start_time = time.time()
# 核心文件路径
self.key_files = {
# 数据库迁移
"database_migration": "database_migrations/alert_rules_comprehensive_upgrade.sql",
# 后端服务 - ljwx-boot
"alert_rule_engine": "ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/AlertRuleEngineService.java",
"cache_manager": "ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/AlertRulesCacheManager.java",
"message_publisher": "ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/UnifiedMessagePublisher.java",
"performance_controller": "ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/admin/controller/monitor/AlertPerformanceController.java",
# 前端服务 - ljwx-bigscreen
"cache_subscriber": "ljwx-bigscreen/bigscreen/bigScreen/alert_rules_cache_subscriber.py",
"high_performance_generator": "ljwx-bigscreen/bigscreen/bigScreen/high_performance_alert_generator.py",
# 前端界面 - ljwx-admin
"alert_rule_wizard": "ljwx-admin/src/views/health/alert-rules/components/AlertRuleWizard.vue",
"rules_management": "ljwx-admin/src/views/health/alert-rules/index.vue",
"performance_dashboard": "ljwx-admin/src/views/monitor/alert-performance/index.vue"
}
def run_comprehensive_validation(self) -> ValidationReport:
"""运行综合验证测试"""
logger.info("开始告警规则系统实施完整性验证...")
# 1. 文件存在性验证
self._validate_file_existence()
# 2. 数据库迁移验证
self._validate_database_migration()
# 3. 后端服务验证
self._validate_backend_services()
# 4. 前端组件验证
self._validate_frontend_components()
# 5. API接口验证
self._validate_api_endpoints()
# 6. 配置完整性验证
self._validate_configuration()
# 7. 性能监控验证
self._validate_performance_monitoring()
# 生成报告
return self._generate_validation_report()
def _validate_file_existence(self):
"""验证关键文件存在性"""
logger.info("验证关键文件存在性...")
for file_key, file_path in self.key_files.items():
start_time = time.time()
full_path = self.base_path / file_path
if full_path.exists():
file_size = full_path.stat().st_size
result = TestResult(
test_name=f"文件存在性检查: {file_key}",
success=True,
message=f"文件存在,大小: {file_size} bytes",
details={"file_path": str(full_path), "size": file_size},
execution_time=time.time() - start_time
)
else:
result = TestResult(
test_name=f"文件存在性检查: {file_key}",
success=False,
message=f"文件不存在: {full_path}",
details={"expected_path": str(full_path)},
execution_time=time.time() - start_time
)
self.results.append(result)
logger.info(f"✓ {result.test_name}: {'PASS' if result.success else 'FAIL'}")
def _validate_database_migration(self):
"""验证数据库迁移脚本"""
logger.info("验证数据库迁移脚本...")
start_time = time.time()
migration_file = self.base_path / self.key_files["database_migration"]
if not migration_file.exists():
self.results.append(TestResult(
test_name="数据库迁移脚本验证",
success=False,
message="迁移脚本文件不存在",
execution_time=time.time() - start_time
))
return
try:
content = migration_file.read_text(encoding='utf-8')
# 检查关键SQL语句
required_elements = [
"ALTER TABLE `t_alert_rules`",
"rule_category",
"condition_expression",
"time_window_seconds",
"priority_level",
"enabled_channels",
"CREATE TABLE `t_alert_cache_sync`",
"CREATE TABLE `t_alert_rule_performance`"
]
missing_elements = []
for element in required_elements:
if element not in content:
missing_elements.append(element)
if not missing_elements:
result = TestResult(
test_name="数据库迁移脚本验证",
success=True,
message="迁移脚本包含所有必要的表结构变更",
details={
"file_size": len(content),
"required_elements": required_elements
},
execution_time=time.time() - start_time
)
else:
result = TestResult(
test_name="数据库迁移脚本验证",
success=False,
message=f"迁移脚本缺少必要元素: {missing_elements}",
details={"missing_elements": missing_elements},
execution_time=time.time() - start_time
)
self.results.append(result)
except Exception as e:
self.results.append(TestResult(
test_name="数据库迁移脚本验证",
success=False,
message=f"读取迁移脚本失败: {str(e)}",
execution_time=time.time() - start_time
))
logger.info(f"✓ 数据库迁移脚本验证: {'PASS' if self.results[-1].success else 'FAIL'}")
def _validate_backend_services(self):
"""验证后端服务实现"""
logger.info("验证后端服务实现...")
service_validations = [
("AlertRuleEngineService", "alert_rule_engine", [
"evaluateRules",
"getCachedRules",
"compileRules",
"getCacheStats"
]),
("AlertRulesCacheManager", "cache_manager", [
"updateAlertRulesCache",
"batchUpdateCache",
"healthCheck"
]),
("UnifiedMessagePublisher", "message_publisher", [
"publishAlert",
"buildUnifiedMessage",
"routeChannels",
"getMessageStats"
]),
("AlertPerformanceController", "performance_controller", [
"getPerformanceStats",
"getCacheHealth",
"clearAllCache",
"getSystemLoad"
])
]
for service_name, file_key, required_methods in service_validations:
self._validate_java_service(service_name, file_key, required_methods)
def _validate_java_service(self, service_name: str, file_key: str, required_methods: List[str]):
"""验证Java服务实现"""
start_time = time.time()
service_file = self.base_path / self.key_files[file_key]
if not service_file.exists():
self.results.append(TestResult(
test_name=f"Java服务验证: {service_name}",
success=False,
message=f"服务文件不存在: {service_file}",
execution_time=time.time() - start_time
))
return
try:
content = service_file.read_text(encoding='utf-8')
# 检查类定义
class_patterns = [
f"class {service_name}",
f"public class {service_name}"
]
has_class = any(pattern in content for pattern in class_patterns)
if not has_class:
self.results.append(TestResult(
test_name=f"Java服务验证: {service_name}",
success=False,
message=f"未找到类定义: {service_name}",
execution_time=time.time() - start_time
))
return
# 检查必要方法
missing_methods = []
for method in required_methods:
if method not in content:
missing_methods.append(method)
# 检查注解
required_annotations = ["@Service", "@Component", "@RestController"]
has_annotation = any(annotation in content for annotation in required_annotations)
success = not missing_methods and has_annotation
message = "服务实现验证通过"
if missing_methods:
message = f"缺少方法: {missing_methods}"
elif not has_annotation:
message = "缺少Spring注解"
result = TestResult(
test_name=f"Java服务验证: {service_name}",
success=success,
message=message,
details={
"file_size": len(content),
"missing_methods": missing_methods,
"has_spring_annotation": has_annotation
},
execution_time=time.time() - start_time
)
self.results.append(result)
except Exception as e:
self.results.append(TestResult(
test_name=f"Java服务验证: {service_name}",
success=False,
message=f"验证失败: {str(e)}",
execution_time=time.time() - start_time
))
def _validate_frontend_components(self):
"""验证前端组件实现"""
logger.info("验证前端组件实现...")
# Python组件验证
python_components = [
("AlertRulesCacheSubscriber", "cache_subscriber", [
"start_subscriber",
"get_alert_rules",
"get_cache_stats",
"health_check"
]),
("HighPerformanceAlertGenerator", "high_performance_generator", [
"start_workers",
"submit_health_data",
"get_performance_stats"
])
]
for component_name, file_key, required_methods in python_components:
self._validate_python_component(component_name, file_key, required_methods)
# Vue组件验证
vue_components = [
("AlertRuleWizard", "alert_rule_wizard", [
"currentStep",
"ruleConfig",
"saveRule",
"nextStep",
"previousStep"
]),
("AlertRulesManagement", "rules_management", [
"rulesList",
"searchRules",
"loadRulesList",
"toggleRuleStatus"
]),
("AlertPerformanceDashboard", "performance_dashboard", [
"performanceData",
"loadPerformanceData",
"initCharts",
"refreshData"
])
]
for component_name, file_key, required_elements in vue_components:
self._validate_vue_component(component_name, file_key, required_elements)
def _validate_python_component(self, component_name: str, file_key: str, required_methods: List[str]):
"""验证Python组件实现"""
start_time = time.time()
component_file = self.base_path / self.key_files[file_key]
if not component_file.exists():
self.results.append(TestResult(
test_name=f"Python组件验证: {component_name}",
success=False,
message=f"组件文件不存在: {component_file}",
execution_time=time.time() - start_time
))
return
try:
content = component_file.read_text(encoding='utf-8')
# 检查类定义
has_class = f"class {component_name}" in content
if not has_class:
self.results.append(TestResult(
test_name=f"Python组件验证: {component_name}",
success=False,
message=f"未找到类定义: {component_name}",
execution_time=time.time() - start_time
))
return
# 检查必要方法
missing_methods = []
for method in required_methods:
if f"def {method}" not in content:
missing_methods.append(method)
success = not missing_methods
message = "Python组件实现验证通过" if success else f"缺少方法: {missing_methods}"
result = TestResult(
test_name=f"Python组件验证: {component_name}",
success=success,
message=message,
details={
"file_size": len(content),
"missing_methods": missing_methods
},
execution_time=time.time() - start_time
)
self.results.append(result)
except Exception as e:
self.results.append(TestResult(
test_name=f"Python组件验证: {component_name}",
success=False,
message=f"验证失败: {str(e)}",
execution_time=time.time() - start_time
))
def _validate_vue_component(self, component_name: str, file_key: str, required_elements: List[str]):
"""验证Vue组件实现"""
start_time = time.time()
component_file = self.base_path / self.key_files[file_key]
if not component_file.exists():
self.results.append(TestResult(
test_name=f"Vue组件验证: {component_name}",
success=False,
message=f"组件文件不存在: {component_file}",
execution_time=time.time() - start_time
))
return
try:
content = component_file.read_text(encoding='utf-8')
# 检查Vue组件结构
has_template = "<template>" in content
has_script = "<script" in content
has_style = "<style" in content or "scoped" in content
if not (has_template and has_script):
self.results.append(TestResult(
test_name=f"Vue组件验证: {component_name}",
success=False,
message="Vue组件缺少基本结构(template/script)",
execution_time=time.time() - start_time
))
return
# 检查必要元素
missing_elements = []
for element in required_elements:
if element not in content:
missing_elements.append(element)
success = not missing_elements
message = "Vue组件实现验证通过" if success else f"缺少元素: {missing_elements}"
result = TestResult(
test_name=f"Vue组件验证: {component_name}",
success=success,
message=message,
details={
"file_size": len(content),
"has_template": has_template,
"has_script": has_script,
"has_style": has_style,
"missing_elements": missing_elements
},
execution_time=time.time() - start_time
)
self.results.append(result)
except Exception as e:
self.results.append(TestResult(
test_name=f"Vue组件验证: {component_name}",
success=False,
message=f"验证失败: {str(e)}",
execution_time=time.time() - start_time
))
def _validate_api_endpoints(self):
"""验证API接口定义"""
logger.info("验证API接口定义...")
start_time = time.time()
# 检查性能监控控制器的API端点
controller_file = self.base_path / self.key_files["performance_controller"]
if not controller_file.exists():
self.results.append(TestResult(
test_name="API接口验证",
success=False,
message="性能监控控制器文件不存在",
execution_time=time.time() - start_time
))
return
try:
content = controller_file.read_text(encoding='utf-8')
# 检查必要的API端点
required_endpoints = [
"@GetMapping(\"/performance/stats\")",
"@GetMapping(\"/cache/health\")",
"@DeleteMapping(\"/cache/all\")",
"@GetMapping(\"/system/load\")",
"@GetMapping(\"/threadpool/status\")"
]
missing_endpoints = []
for endpoint in required_endpoints:
if endpoint not in content:
missing_endpoints.append(endpoint)
success = not missing_endpoints
message = "API接口定义验证通过" if success else f"缺少端点: {missing_endpoints}"
result = TestResult(
test_name="API接口验证",
success=success,
message=message,
details={
"missing_endpoints": missing_endpoints,
"total_endpoints": len(required_endpoints)
},
execution_time=time.time() - start_time
)
self.results.append(result)
except Exception as e:
self.results.append(TestResult(
test_name="API接口验证",
success=False,
message=f"验证失败: {str(e)}",
execution_time=time.time() - start_time
))
def _validate_configuration(self):
"""验证配置完整性"""
logger.info("验证配置完整性...")
start_time = time.time()
# 检查ljwx-bigscreen的缓存订阅器配置
cache_subscriber_file = self.base_path / self.key_files["cache_subscriber"]
config_checks = []
if cache_subscriber_file.exists():
try:
content = cache_subscriber_file.read_text(encoding='utf-8')
# 检查Redis配置
redis_configs = [
"redis_bigscreen",
"redis_boot",
"db=0",
"db=1",
"alert_rules_channel"
]
missing_configs = [config for config in redis_configs if config not in content]
config_checks.append({
"component": "缓存订阅器Redis配置",
"success": not missing_configs,
"details": {"missing": missing_configs}
})
except Exception as e:
config_checks.append({
"component": "缓存订阅器配置",
"success": False,
"details": {"error": str(e)}
})
# 汇总配置验证结果
all_success = all(check["success"] for check in config_checks)
result = TestResult(
test_name="配置完整性验证",
success=all_success,
message="配置验证通过" if all_success else "存在配置问题",
details={"checks": config_checks},
execution_time=time.time() - start_time
)
self.results.append(result)
def _validate_performance_monitoring(self):
"""验证性能监控实现"""
logger.info("验证性能监控实现...")
start_time = time.time()
# 检查性能监控相关文件
monitoring_files = [
("性能监控控制器", "performance_controller"),
("性能监控面板", "performance_dashboard"),
("缓存性能监控", "cache_subscriber")
]
monitoring_results = []
for monitor_name, file_key in monitoring_files:
file_path = self.base_path / self.key_files[file_key]
if file_path.exists():
try:
content = file_path.read_text(encoding='utf-8')
# 根据文件类型检查不同的性能监控元素
if "Controller" in monitor_name:
# Java控制器检查
required_elements = ["getCacheStats", "getSystemLoad", "getPerformanceStats"]
elif "面板" in monitor_name:
# Vue面板检查
required_elements = ["performance_stats", "loadPerformanceData", "echarts"]
else:
# Python组件检查
required_elements = ["get_cache_stats", "performance_stats", "hit_rate"]
missing_elements = [elem for elem in required_elements if elem not in content]
monitoring_results.append({
"monitor": monitor_name,
"success": not missing_elements,
"missing": missing_elements
})
except Exception as e:
monitoring_results.append({
"monitor": monitor_name,
"success": False,
"error": str(e)
})
else:
monitoring_results.append({
"monitor": monitor_name,
"success": False,
"missing_file": True
})
all_success = all(result["success"] for result in monitoring_results)
result = TestResult(
test_name="性能监控实现验证",
success=all_success,
message="性能监控实现验证通过" if all_success else "性能监控实现存在问题",
details={"monitoring_results": monitoring_results},
execution_time=time.time() - start_time
)
self.results.append(result)
def _generate_validation_report(self) -> ValidationReport:
"""生成验证报告"""
logger.info("生成验证报告...")
total_tests = len(self.results)
passed_tests = sum(1 for result in self.results if result.success)
failed_tests = total_tests - passed_tests
overall_success = failed_tests == 0
execution_time = time.time() - self.start_time
# 生成建议
recommendations = []
if failed_tests > 0:
recommendations.append(f"共有 {failed_tests} 个测试失败,需要修复相关问题")
# 分析失败原因并给出具体建议
file_not_found_count = sum(1 for result in self.results
if not result.success and "不存在" in result.message)
if file_not_found_count > 0:
recommendations.append(f"有 {file_not_found_count} 个文件缺失,请检查实施完整性")
missing_methods_count = sum(1 for result in self.results
if not result.success and "缺少" in result.message)
if missing_methods_count > 0:
recommendations.append(f"有 {missing_methods_count} 个组件缺少必要方法,请完善实现")
if overall_success:
recommendations.append("所有核心组件实施完成,可以进行下一步测试")
recommendations.append("建议进行性能测试和端到端集成测试")
else:
recommendations.append("请先修复失败的测试项,再进行后续步骤")
report = ValidationReport(
total_tests=total_tests,
passed_tests=passed_tests,
failed_tests=failed_tests,
test_results=self.results,
overall_success=overall_success,
execution_time=execution_time,
recommendations=recommendations
)
return report
def print_detailed_report(self, report: ValidationReport):
"""打印详细报告"""
print("\n" + "="*80)
print("告警规则系统实施验证报告")
print("="*80)
print(f"\n📊 测试概览:")
print(f" 总测试数: {report.total_tests}")
print(f" 通过测试: {report.passed_tests}")
print(f" 失败测试: {report.failed_tests}")
print(f" 成功率: {report.passed_tests/report.total_tests*100:.1f}%")
print(f" 执行时间: {report.execution_time:.2f}秒")
print(f" 整体状态: {'✅ 成功' if report.overall_success else '❌ 失败'}")
print(f"\n📋 详细测试结果:")
for i, result in enumerate(report.test_results, 1):
status = "✅ PASS" if result.success else "❌ FAIL"
print(f" {i:2d}. {result.test_name}: {status}")
print(f" 消息: {result.message}")
print(f" 耗时: {result.execution_time:.3f}秒")
if result.details:
print(f" 详情: {json.dumps(result.details, ensure_ascii=False, indent=8)}")
print(f"\n💡 建议:")
for i, recommendation in enumerate(report.recommendations, 1):
print(f" {i}. {recommendation}")
print("\n" + "="*80)
def save_report_to_file(self, report: ValidationReport, output_file: str = None):
"""保存报告到文件"""
if output_file is None:
timestamp = time.strftime("%Y%m%d_%H%M%S")
output_file = f"alert_rules_validation_report_{timestamp}.json"
output_path = self.base_path / output_file
# 转换为可序列化的字典
report_dict = asdict(report)
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(report_dict, f, ensure_ascii=False, indent=2, default=str)
logger.info(f"验证报告已保存到: {output_path}")
return output_path
def main():
"""主函数"""
print("🚀 开始告警规则系统实施完整性验证...")
# 创建验证器
validator = AlertRulesImplementationValidator()
try:
# 运行验证
report = validator.run_comprehensive_validation()
# 打印报告
validator.print_detailed_report(report)
# 保存报告
report_file = validator.save_report_to_file(report)
# 返回状态码
sys.exit(0 if report.overall_success else 1)
except Exception as e:
logger.error(f"验证过程发生异常: {e}")
print(f"❌ 验证失败: {e}")
sys.exit(1)
if __name__ == "__main__":
main()