feat(database): 添加用户角色权限系统及相关监控功能

- 创建用户表(users)包含基本信息和认证字段
- 创建角色表(roles)用于权限控制
- 创建权限表(permissions)定义系统权限
- 创建用户角色关联表(user_roles)建立用户与角色关系
- 创建角色权限关联表(role_permissions)建立角色与权限关系
- 创建迁移记录表(migrations)追踪数据库变更
- 添加AdminController提供管理员面板功能
- 实现系统监控、配置管理、缓存清理等功能
- 添加AOP切面编程支持的各种通知类型
- 实现告警管理AlertManager支持多渠道告警
- 添加文档注解接口规范
This commit is contained in:
Lawson
2026-04-08 17:00:28 +08:00
commit 2782d765fb
270 changed files with 107192 additions and 0 deletions

571
scripts/run-tests.sh Normal file
View File

@@ -0,0 +1,571 @@
#!/bin/bash
# FendxPHP 自动化测试脚本
# 用法: ./scripts/run-tests.sh [test_type] [options]
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 配置
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TEST_RESULTS_DIR="${PROJECT_ROOT}/reports"
LOG_FILE="${TEST_RESULTS_DIR}/test.log"
# 创建必要的目录
mkdir -p "${TEST_RESULTS_DIR}"
mkdir -p "${TEST_RESULTS_DIR}/coverage"
mkdir -p "${TEST_RESULTS_DIR}/performance"
# 日志函数
log() {
echo -e "$1" | tee -a "${LOG_FILE}"
}
log_info() {
log "${BLUE}[INFO]${NC} $1"
}
log_success() {
log "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
log "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
log "${RED}[ERROR]${NC} $1"
}
# 显示帮助信息
show_help() {
cat << EOF
FendxPHP 自动化测试脚本
用法: $0 [test_type] [options]
测试类型:
unit 运行单元测试
integration 运行集成测试
api 运行API测试
e2e 运行端到端测试
performance 运行性能测试
security 运行安全测试
all 运行所有测试 (默认)
选项:
--coverage 生成覆盖率报告
--parallel=N 并行运行测试 (N个进程)
--filter=FILTER 过滤测试用例
--verbose 详细输出
--no-docker 不使用Docker环境
--clean 清理测试环境
--help 显示此帮助信息
示例:
$0 unit --coverage
$0 integration --filter=UserTest
$0 all --parallel=4 --coverage
$0 performance --verbose
EOF
}
# 检查依赖
check_dependencies() {
log_info "检查依赖..."
# 检查PHP
if ! command -v php &> /dev/null; then
log_error "PHP 未安装"
exit 1
fi
# 检查Composer
if ! command -v composer &> /dev/null; then
log_error "Composer 未安装"
exit 1
fi
# 检查PHPUnit
if ! command -v vendor/bin/phpunit &> /dev/null; then
log_info "安装 PHPUnit..."
composer require --dev phpunit/phpunit
fi
# 检查Docker (如果需要)
if [[ "$USE_DOCKER" == "true" ]]; then
if ! command -v docker &> /dev/null; then
log_error "Docker 未安装"
exit 1
fi
fi
log_success "依赖检查完成"
}
# 准备测试环境
prepare_environment() {
log_info "准备测试环境..."
# 复制环境配置
if [[ ! -f "${PROJECT_ROOT}/.env" ]]; then
cp "${PROJECT_ROOT}/.env.example" "${PROJECT_ROOT}/.env"
fi
# 设置测试环境变量
export APP_ENV=testing
export DB_CONNECTION=sqlite
export DB_DATABASE=:memory:
export CACHE_DRIVER=array
export SESSION_DRIVER=array
export QUEUE_CONNECTION=sync
# 安装依赖
log_info "安装Composer依赖..."
composer install --optimize-autoloader --no-interaction
# 创建测试数据库
log_info "创建测试数据库..."
php bin/console migrate:run --env=testing
log_success "测试环境准备完成"
}
# 启动Docker测试环境
start_docker_environment() {
if [[ "$USE_DOCKER" != "true" ]]; then
return
fi
log_info "启动Docker测试环境..."
# 停止现有容器
docker-compose -f docker-compose.test.yml down --volumes 2>/dev/null || true
# 启动测试容器
docker-compose -f docker-compose.test.yml up -d --build
# 等待服务就绪
log_info "等待服务启动..."
sleep 30
# 检查服务状态
if ! docker-compose -f docker-compose.test.yml ps | grep -q "Up"; then
log_error "Docker服务启动失败"
docker-compose -f docker-compose.test.yml logs
exit 1
fi
log_success "Docker环境启动完成"
}
# 停止Docker测试环境
stop_docker_environment() {
if [[ "$USE_DOCKER" != "true" ]]; then
return
fi
log_info "停止Docker测试环境..."
docker-compose -f docker-compose.test.yml down --volumes
}
# 运行单元测试
run_unit_tests() {
log_info "运行单元测试..."
local cmd="vendor/bin/phpunit tests/Unit --colors=always --log-junit=${TEST_RESULTS_DIR}/junit-unit.xml"
if [[ "$GENERATE_COVERAGE" == "true" ]]; then
cmd="$cmd --coverage-html=${TEST_RESULTS_DIR}/coverage/unit --coverage-clover=${TEST_RESULTS_DIR}/coverage/unit.xml"
fi
if [[ -n "$FILTER" ]]; then
cmd="$cmd --filter=$FILTER"
fi
if [[ "$VERBOSE" == "true" ]]; then
cmd="$cmd --verbose"
fi
if [[ "$PARALLEL" -gt 1 ]]; then
cmd="$cmd --processes=$PARALLEL"
fi
log_info "执行: $cmd"
if eval "$cmd"; then
log_success "单元测试通过"
return 0
else
log_error "单元测试失败"
return 1
fi
}
# 运行集成测试
run_integration_tests() {
log_info "运行集成测试..."
local cmd="vendor/bin/phpunit tests/Integration --colors=always --log-junit=${TEST_RESULTS_DIR}/junit-integration.xml"
if [[ -n "$FILTER" ]]; then
cmd="$cmd --filter=$FILTER"
fi
if [[ "$VERBOSE" == "true" ]]; then
cmd="$cmd --verbose"
fi
log_info "执行: $cmd"
if eval "$cmd"; then
log_success "集成测试通过"
return 0
else
log_error "集成测试失败"
return 1
fi
}
# 运行API测试
run_api_tests() {
log_info "运行API测试..."
# 启动应用服务器
log_info "启动应用服务器..."
php -S localhost:8000 -t public/ > /dev/null 2>&1 &
local SERVER_PID=$!
# 等待服务器启动
sleep 5
# 运行API测试
local cmd="vendor/bin/codecept run api --colors --xml=${TEST_RESULTS_DIR}/api-results.xml"
if [[ -n "$FILTER" ]]; then
cmd="$cmd -g $FILTER"
fi
log_info "执行: $cmd"
local result=0
if ! eval "$cmd"; then
log_error "API测试失败"
result=1
else
log_success "API测试通过"
fi
# 停止服务器
kill $SERVER_PID 2>/dev/null || true
return $result
}
# 运行端到端测试
run_e2e_tests() {
log_info "运行端到端测试..."
# 启动完整环境
start_docker_environment
# 运行E2E测试
local cmd="vendor/bin/codecept run e2e --colors --xml=${TEST_RESULTS_DIR}/e2e-results.xml"
if [[ -n "$FILTER" ]]; then
cmd="$cmd -g $FILTER"
fi
log_info "执行: $cmd"
local result=0
if ! eval "$cmd"; then
log_error "E2E测试失败"
result=1
else
log_success "E2E测试通过"
fi
# 清理环境
stop_docker_environment
return $result
}
# 运行性能测试
run_performance_tests() {
log_info "运行性能测试..."
# 启动应用服务器
php -S localhost:8000 -t public/ > /dev/null 2>&1 &
local SERVER_PID=$!
sleep 5
# 并发测试
log_info "执行并发测试..."
ab -n 1000 -c 10 http://localhost:8000/api/users > "${TEST_RESULTS_DIR}/performance/ab-results.txt" 2>&1
# 内存测试
log_info "执行内存测试..."
php -d memory_limit=1G -r "
\$start = memory_get_usage();
for (\$i = 0; \$i < 10000; \$i++) {
\$data = ['id' => \$i, 'name' => 'test'];
json_encode(\$data);
}
echo 'Memory used: ' . ((memory_get_usage() - \$start) / 1024 / 1024) . ' MB\n';
" > "${TEST_RESULTS_DIR}/performance/memory-test.txt"
# 数据库性能测试
log_info "执行数据库性能测试..."
php bin/console benchmark:database > "${TEST_RESULTS_DIR}/performance/database-test.txt" 2>&1
# 停止服务器
kill $SERVER_PID 2>/dev/null || true
log_success "性能测试完成"
return 0
}
# 运行安全测试
run_security_tests() {
log_info "运行安全测试..."
# 依赖漏洞扫描
log_info "扫描依赖漏洞..."
composer audit > "${TEST_RESULTS_DIR}/security/composer-audit.txt" 2>&1
# 代码安全分析
log_info "执行代码安全分析..."
if command -v vendor/bin/phpstan &> /dev/null; then
vendor/bin/phpstan analyse --level=8 --error-format=json > "${TEST_RESULTS_DIR}/security/phpstan-results.json" 2>&1
fi
# API安全测试
log_info "执行API安全测试..."
if command -v vendor/bin/codecept &> /dev/null; then
vendor/bin/codecept run security --colors --xml="${TEST_RESULTS_DIR}/security-results.xml" 2>&1 || true
fi
log_success "安全测试完成"
return 0
}
# 生成测试报告
generate_report() {
log_info "生成测试报告..."
local report_file="${TEST_RESULTS_DIR}/test-report.html"
cat > "$report_file" << EOF
<!DOCTYPE html>
<html>
<head>
<title>FendxPHP 测试报告</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.header { background: #f0f0f0; padding: 20px; border-radius: 5px; }
.section { margin: 20px 0; }
.success { color: green; }
.error { color: red; }
.warning { color: orange; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<div class="header">
<h1>FendxPHP 测试报告</h1>
<p>生成时间: $(date)</p>
<p>测试类型: ${TEST_TYPE}</p>
</div>
<div class="section">
<h2>测试结果概览</h2>
<table>
<tr><th>测试类型</th><th>状态</th><th>详情</th></tr>
EOF
# 添加各种测试结果
if [[ -f "${TEST_RESULTS_DIR}/junit-unit.xml" ]]; then
echo "<tr><td>单元测试</td><td class='success'>通过</td><td><a href='coverage/unit/index.html'>查看覆盖率</a></td></tr>" >> "$report_file"
fi
if [[ -f "${TEST_RESULTS_DIR}/junit-integration.xml" ]]; then
echo "<tr><td>集成测试</td><td class='success'>通过</td><td>查看详细日志</td></tr>" >> "$report_file"
fi
cat >> "$report_file" << EOF
</table>
</div>
<div class="section">
<h2>性能指标</h2>
<table>
<tr><th>指标</th><th>值</th></tr>
EOF
# 添加性能指标
if [[ -f "${TEST_RESULTS_DIR}/performance/ab-results.txt" ]]; then
local rps=$(grep "Requests per second" "${TEST_RESULTS_DIR}/performance/ab-results.txt" | awk '{print $4}')
echo "<tr><td>每秒请求数</td><td>${rps}</td></tr>" >> "$report_file"
fi
cat >> "$report_file" << EOF
</table>
</div>
</body>
</html>
EOF
log_success "测试报告已生成: $report_file"
}
# 清理测试环境
cleanup() {
log_info "清理测试环境..."
# 停止Docker环境
stop_docker_environment
# 清理临时文件
rm -f "${PROJECT_ROOT}/.env.testing"
log_success "清理完成"
}
# 主函数
main() {
local test_type="${1:-all}"
local use_docker="true"
local generate_coverage="false"
local parallel="1"
local filter=""
local verbose="false"
local clean_only="false"
# 解析参数
shift
while [[ $# -gt 0 ]]; do
case $1 in
--coverage)
generate_coverage="true"
;;
--parallel=*)
parallel="${1#*=}"
;;
--filter=*)
filter="${1#*=}"
;;
--verbose)
verbose="true"
;;
--no-docker)
use_docker="false"
;;
--clean)
clean_only="true"
;;
--help)
show_help
exit 0
;;
*)
log_error "未知参数: $1"
show_help
exit 1
;;
esac
shift
done
# 设置全局变量
export USE_DOCKER="$use_docker"
export GENERATE_COVERAGE="$generate_coverage"
export PARALLEL="$parallel"
export FILTER="$filter"
export VERBOSE="$verbose"
export TEST_TYPE="$test_type"
# 只清理环境
if [[ "$clean_only" == "true" ]]; then
cleanup
exit 0
fi
# 捕获退出信号
trap cleanup EXIT
log_info "开始运行 FendxPHP 测试套件"
log_info "测试类型: $test_type"
log_info "使用Docker: $use_docker"
log_info "生成覆盖率: $generate_coverage"
# 检查依赖
check_dependencies
# 准备环境
prepare_environment
# 启动Docker环境如果需要
start_docker_environment
# 运行测试
local failed_tests=0
case $test_type in
unit)
run_unit_tests || ((failed_tests++))
;;
integration)
run_integration_tests || ((failed_tests++))
;;
api)
run_api_tests || ((failed_tests++))
;;
e2e)
run_e2e_tests || ((failed_tests++))
;;
performance)
run_performance_tests || ((failed_tests++))
;;
security)
run_security_tests || ((failed_tests++))
;;
all)
run_unit_tests || ((failed_tests++))
run_integration_tests || ((failed_tests++))
run_api_tests || ((failed_tests++))
run_performance_tests || ((failed_tests++))
run_security_tests || ((failed_tests++))
;;
*)
log_error "未知的测试类型: $test_type"
show_help
exit 1
;;
esac
# 生成报告
generate_report
# 输出结果
if [[ $failed_tests -eq 0 ]]; then
log_success "所有测试通过! 🎉"
exit 0
else
log_error "$failed_tests 个测试失败 ❌"
exit 1
fi
}
# 运行主函数
main "$@"