mirror of
https://devops.lemonos.cn/lawson/FendxPHP.git
synced 2026-06-15 15:02:49 +08:00
- 创建用户表(users)包含基本信息和认证字段 - 创建角色表(roles)用于权限控制 - 创建权限表(permissions)定义系统权限 - 创建用户角色关联表(user_roles)建立用户与角色关系 - 创建角色权限关联表(role_permissions)建立角色与权限关系 - 创建迁移记录表(migrations)追踪数据库变更 - 添加AdminController提供管理员面板功能 - 实现系统监控、配置管理、缓存清理等功能 - 添加AOP切面编程支持的各种通知类型 - 实现告警管理AlertManager支持多渠道告警 - 添加文档注解接口规范
572 lines
14 KiB
Bash
572 lines
14 KiB
Bash
#!/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 "$@"
|