mirror of
https://github.com/hpd840321/starRiverProperty.git
synced 2026-06-09 16:30:29 +08:00
7b2bd307f1
- backend/: 13 Maven modules (cw-elevator-application, cloudwalk-cloud, intelligent-cwoscomponent, ninca-crk, etc.) - frontend/: 4 Vue projects (elevator-front, cwos-portal, alarm-front, front_acs) + decompiled + scripts - scripts/: build, test-env, tools (Docker Compose, service templates, API parity) - docs/: AGENTS.md, superpowers specs, architecture docs - .gitignore: standard Java/Maven exclusions Moved from legacy maven-*/ root layout to backend/ organized structure.
1307 lines
40 KiB
Markdown
1307 lines
40 KiB
Markdown
# V2 全系统功能测试环境搭建 — 实施计划
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
||
**Goal:** 搭建 cw-elevator-application V2 (v2.0.7) 的全系统集成功能测试环境,一键搭建 17 个组件并在 15-20 分钟内完成全部功能验证。
|
||
|
||
**Architecture:** Docker Compose 管理基础组件 (Consul+Redis+Kafka+Nginx),Bash 脚本编排 13 个本机 Java 服务,复用现有 MySQL (192.168.3.12:3307),配置模板驱动 + 环境变量统一管理。
|
||
|
||
**Tech Stack:** Bash 4+, Docker Compose v2, JDK 8, Maven 3.5+, Python 3.8+ (pytest), MySQL 5.7
|
||
|
||
**关联 Spec:** `docs/superpowers/specs/2026-05-01-v2-test-env-setup-design.md`
|
||
|
||
---
|
||
|
||
## 文件映射
|
||
|
||
| 产出文件 | 职责 |
|
||
|---------|------|
|
||
| `源码/scripts/test-env/config/env.sh` | 统一环境变量 (IP/端口/密码/路径) |
|
||
| `源码/scripts/test-env/docker-compose.infra.yml` | 基础组件容器编排 (Consul+Redis+Kafka+Nginx) |
|
||
| `源码/scripts/test-env/prepare-db.sh` | 数据库恢复 (11 个库从 data_backup/) |
|
||
| `源码/scripts/test-env/prepare-services.sh` | 解压 tar.gz + 从模板生成配置 |
|
||
| `源码/scripts/test-env/build-elevator-v2.sh` | 编译 V2 电梯应用 |
|
||
| `源码/scripts/test-env/config/service-templates/elevator-v2.properties` | V2 电梯配置模板 |
|
||
| `源码/scripts/test-env/config/service-templates/crk-std.properties` | CRK 后端配置模板 |
|
||
| `源码/scripts/test-env/config/service-templates/alarm.properties` | 报警应用配置模板 |
|
||
| `源码/scripts/test-env/config/service-templates/ninca-common.properties` | ninca-common 配置模板 |
|
||
| `源码/scripts/test-env/config/service-templates/component-org.properties` | component-org 配置模板 |
|
||
| `源码/scripts/test-env/start-all.sh` | 按拓扑序启动全部服务 |
|
||
| `源码/scripts/test-env/stop-all.sh` | 按逆序停止全部服务 |
|
||
| `源码/scripts/test-env/health-check.sh` | 探活检查 |
|
||
| `源码/scripts/test-env/verify-functional.sh` | 功能验证 (对拍+策略+联动) |
|
||
| `源码/scripts/test-env/setup.sh` | 主入口脚本 (编排所有 Phase) |
|
||
|
||
---
|
||
|
||
### Task 1: 创建目录结构和 env.sh
|
||
|
||
**Files:**
|
||
- Create: `源码/scripts/test-env/config/env.sh`
|
||
- Create: `源码/scripts/test-env/config/service-templates/`
|
||
|
||
- [ ] **Step 1: 创建目录结构**
|
||
|
||
```bash
|
||
mkdir -p 源码/scripts/test-env/config/service-templates
|
||
```
|
||
|
||
- [ ] **Step 2: 编写 env.sh**
|
||
|
||
编辑 `源码/scripts/test-env/config/env.sh`,内容如下:
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# V2 测试环境 — 统一环境变量
|
||
# 所有脚本 source 此文件获取统一配置
|
||
|
||
set -euo pipefail
|
||
|
||
# ============================================
|
||
# 路径
|
||
# ============================================
|
||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
||
STAR_CENTER="$REPO_ROOT/../星中心"
|
||
DATA_BACKUP="$REPO_ROOT/../data_backup"
|
||
TEST_ENV_DIR="$REPO_ROOT/scripts/test-env"
|
||
SERVICE_DIR="$TEST_ENV_DIR/services"
|
||
LOG_DIR="$TEST_ENV_DIR/logs"
|
||
|
||
# ============================================
|
||
# Java
|
||
# ============================================
|
||
JAVA_HOME="${DEPLOY_JDK8:-/usr/lib/jvm/java-8-openjdk-amd64}"
|
||
JAVA="$JAVA_HOME/bin/java"
|
||
JAVA_OPTS_HEAVY="-Xmx3072m -Xms3072m -Xmn1024m" # CRK, alarm, elevator
|
||
JAVA_OPTS_LIGHT="-Xmx2048m -Xms512m" # common, org, portal
|
||
JAVA_OPTS_DEBUG="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n"
|
||
|
||
# ============================================
|
||
# 基础设施地址
|
||
# ============================================
|
||
MYSQL_HOST=192.168.3.12
|
||
MYSQL_PORT=3307
|
||
MYSQL_USER=root
|
||
MYSQL_PASS=123456
|
||
REDIS_HOST=127.0.0.1
|
||
REDIS_PORT=6379
|
||
REDIS_PASS="1qaz!QAZ"
|
||
CONSUL_HOST=127.0.0.1
|
||
CONSUL_PORT=8500
|
||
KAFKA_HOST=127.0.0.1
|
||
KAFKA_PORT=9092
|
||
ZK_HOST=127.0.0.1
|
||
ZK_PORT=2181
|
||
|
||
# ============================================
|
||
# 服务端口
|
||
# ============================================
|
||
PORT_ELEVATOR_V2=18081
|
||
PORT_ELEVATOR_V1=18080
|
||
PORT_CRK_STD=16106
|
||
PORT_CRK_MGMT=16114
|
||
PORT_ALARM=17011
|
||
PORT_ALARM_MGMT=17211
|
||
PORT_CWOS_PORTAL=33008
|
||
PORT_COMPONENT_ORG=33011
|
||
PORT_NINCA_COMMON=33010
|
||
PORT_CWOS_MANAGER=3721
|
||
PORT_SYSTEM_API=3333
|
||
PORT_SNAP_APP=33012
|
||
PORT_VEHICLE_APP=33013
|
||
PORT_PERSON_FILE=33014
|
||
PORT_MONITOR_APP=33015
|
||
PORT_NGINX=8090
|
||
|
||
# ============================================
|
||
# 数据库名
|
||
# ============================================
|
||
DB_ELEVATOR="cw-elevator-application"
|
||
DB_CRK="ninca_crk_std"
|
||
DB_ALARM="alarm_deploy"
|
||
DB_MANAGER="cwos_manager"
|
||
DB_PORTAL="cwos_portal"
|
||
DB_COMMON="ninca_common"
|
||
DB_COMPONENT_ORG="component-organization"
|
||
DB_ODS="ods"
|
||
DB_THIRDPARTY="cloudwalk_device_thirdparty"
|
||
DB_G="g"
|
||
DB_P="p"
|
||
DB_12="12"
|
||
DB_34="34"
|
||
|
||
# ============================================
|
||
# Maven
|
||
# ============================================
|
||
MVN="mvn"
|
||
MVN_OPTS="-DskipTests -Dformatter-maven-plugin.version=2.16.0"
|
||
ELEVATOR_POM="$REPO_ROOT/maven-cw-elevator-application/pom.xml"
|
||
|
||
# ============================================
|
||
# 日志颜色
|
||
# ============================================
|
||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
|
||
log_info() { echo -e "${BLUE}[INFO]${NC} $*"; }
|
||
log_ok() { echo -e "${GREEN}[OK]${NC} $*"; }
|
||
log_warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
|
||
```
|
||
|
||
- [ ] **Step 3: 测试 env.sh 可被 source**
|
||
|
||
```bash
|
||
bash -c 'source 源码/scripts/test-env/config/env.sh && echo "MYSQL=$MYSQL_HOST:$MYSQL_PORT"'
|
||
# 预期: MYSQL=192.168.3.12:3307
|
||
```
|
||
|
||
- [ ] **Step 4: Commit**
|
||
|
||
```bash
|
||
git add 源码/scripts/test-env/config/env.sh
|
||
git commit -m "feat: add test environment unified config (env.sh)"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 2: Docker Compose — 合并基础组件
|
||
|
||
**Files:**
|
||
- Create: `源码/scripts/test-env/docker-compose.infra.yml`
|
||
|
||
- [ ] **Step 1: 编写合并后的 docker-compose.infra.yml**
|
||
|
||
```yaml
|
||
# V2 测试环境 — 基础组件 (Consul + Redis + Kafka + ZK + Nginx)
|
||
# 合并自: deploy/consul-docker/docker-compose.yml, docker-compose.frontend-local.yml
|
||
version: '3.8'
|
||
|
||
services:
|
||
consul:
|
||
image: hashicorp/consul:1.22
|
||
container_name: v2test-consul
|
||
restart: unless-stopped
|
||
ports:
|
||
- "${CONSUL_PORT:-8500}:8500"
|
||
command: >
|
||
agent -server -bootstrap-expect=1 -ui
|
||
-client=0.0.0.0 -bind=0.0.0.0
|
||
-data-dir=/consul/data
|
||
volumes:
|
||
- consul-data:/consul/data
|
||
|
||
redis:
|
||
image: redis:7-alpine
|
||
container_name: v2test-redis
|
||
restart: unless-stopped
|
||
ports:
|
||
- "${REDIS_PORT:-6379}:6379"
|
||
command: redis-server --requirepass "${REDIS_PASS:-1qaz!QAZ}"
|
||
|
||
zookeeper:
|
||
image: bitnami/zookeeper:3.9
|
||
container_name: v2test-zookeeper
|
||
restart: unless-stopped
|
||
ports:
|
||
- "${ZK_PORT:-2181}:2181"
|
||
environment:
|
||
ALLOW_ANONYMOUS_LOGIN: "yes"
|
||
|
||
kafka:
|
||
image: bitnami/kafka:3.6
|
||
container_name: v2test-kafka
|
||
restart: unless-stopped
|
||
ports:
|
||
- "${KAFKA_PORT:-9092}:9092"
|
||
environment:
|
||
KAFKA_CFG_NODE_ID: 1
|
||
KAFKA_CFG_PROCESS_ROLES: "broker,controller"
|
||
KAFKA_CFG_CONTROLLER_QUORUM_VOTERS: "1@localhost:9093"
|
||
KAFKA_CFG_LISTENERS: "PLAINTEXT://:9092,CONTROLLER://:9093"
|
||
KAFKA_CFG_ADVERTISED_LISTENERS: "PLAINTEXT://localhost:9092"
|
||
KAFKA_CFG_CONTROLLER_LISTENER_NAMES: "CONTROLLER"
|
||
KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP: "PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT"
|
||
KAFKA_CFG_AUTO_CREATE_TOPICS_ENABLE: "true"
|
||
depends_on:
|
||
- zookeeper
|
||
|
||
nginx:
|
||
image: nginx:alpine
|
||
container_name: v2test-nginx
|
||
restart: unless-stopped
|
||
ports:
|
||
- "${PORT_NGINX:-8090}:80"
|
||
extra_hosts:
|
||
- "host.docker.internal:host-gateway"
|
||
volumes:
|
||
- ../../frontend:/data/cwos/frontend:ro
|
||
- ../../nginx.frontend-local.conf:/etc/nginx/conf.d/default.conf:ro
|
||
|
||
volumes:
|
||
consul-data:
|
||
```
|
||
|
||
- [ ] **Step 2: 验证 Docker Compose 语法**
|
||
|
||
```bash
|
||
cd 源码/scripts/test-env
|
||
source config/env.sh
|
||
docker compose -f docker-compose.infra.yml config --quiet
|
||
# 预期: 无输出 (语法正确)
|
||
```
|
||
|
||
- [ ] **Step 3: 启动并验证所有容器**
|
||
|
||
```bash
|
||
docker compose -f 源码/scripts/test-env/docker-compose.infra.yml up -d
|
||
# 等待启动
|
||
sleep 15
|
||
|
||
# 验证 Consul
|
||
curl -sf http://127.0.0.1:8500/v1/status/leader && echo "Consul OK"
|
||
|
||
# 验证 Redis
|
||
docker exec v2test-redis redis-cli -a 1qaz!QAZ PING | grep PONG && echo "Redis OK"
|
||
|
||
# 验证 Kafka
|
||
docker exec v2test-kafka kafka-topics.sh --bootstrap-server localhost:9092 --list && echo "Kafka OK"
|
||
|
||
# 验证 Nginx
|
||
curl -sf http://localhost:8090/ && echo "Nginx OK"
|
||
```
|
||
|
||
- [ ] **Step 4: 清理并 commit**
|
||
|
||
```bash
|
||
docker compose -f 源码/scripts/test-env/docker-compose.infra.yml down
|
||
git add 源码/scripts/test-env/docker-compose.infra.yml
|
||
git commit -m "feat: add Docker Compose for test infra (Consul+Redis+Kafka+ZK+Nginx)"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 3: prepare-db.sh — 数据库恢复
|
||
|
||
**Files:**
|
||
- Create: `源码/scripts/test-env/prepare-db.sh`
|
||
|
||
- [ ] **Step 1: 编写数据库恢复脚本**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# prepare-db.sh — 恢复 11 个数据库 SQL 备份到 MySQL
|
||
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
|
||
|
||
log_info "Phase 2: Database preparation"
|
||
log_info "Target: $MYSQL_HOST:$MYSQL_PORT (user: $MYSQL_USER)"
|
||
|
||
MYSQL_CMD="mysql -h $MYSQL_HOST -P $MYSQL_PORT -u $MYSQL_USER -p${MYSQL_PASS}"
|
||
|
||
# 检查 MySQL 连通性
|
||
if ! $MYSQL_CMD -e "SELECT 1" &>/dev/null; then
|
||
log_error "Cannot connect to MySQL at $MYSQL_HOST:$MYSQL_PORT"
|
||
exit 1
|
||
fi
|
||
log_ok "MySQL connection OK"
|
||
|
||
# 数据库名 → 备份文件映射
|
||
declare -A DB_MAP=(
|
||
["$DB_ELEVATOR"]="12_2026_04_23_17_28_33.sql.gz"
|
||
["$DB_ALARM"]="alarm_deploy_2026_04_23_17_28_33.sql.gz"
|
||
["$DB_MANAGER"]="cwos_manager_2026_04_23_17_28_33.sql.gz"
|
||
["$DB_PORTAL"]="cwos_portal_2026_04_23_17_28_33.sql.gz"
|
||
["$DB_COMMON"]="ninca_common_2026_04_23_17_28_33.sql.gz"
|
||
["$DB_COMPONENT_ORG"]="component-organization_2026_04_23_17_28_33.sql.gz"
|
||
["$DB_ODS"]="ods_2026_04_23_17_28_33.sql.gz"
|
||
["$DB_THIRDPARTY"]="cloudwalk_device_thirdparty_2026_04_23_17_28_33.sql.gz"
|
||
["$DB_G"]="g_2026_04_23_17_28_33.sql.gz"
|
||
["$DB_P"]="p_2026_04_23_17_28_33.sql.gz"
|
||
)
|
||
|
||
for db_name in "${!DB_MAP[@]}"; do
|
||
backup_file="${DB_MAP[$db_name]}"
|
||
backup_path="$DATA_BACKUP/$backup_file"
|
||
|
||
if [[ ! -f "$backup_path" ]]; then
|
||
log_warn "Backup not found: $backup_path — skipping $db_name"
|
||
continue
|
||
fi
|
||
|
||
log_info "Restoring $db_name from $backup_file ($(du -h "$backup_path" | cut -f1))..."
|
||
|
||
# 建库 (如不存在)
|
||
$MYSQL_CMD -e "CREATE DATABASE IF NOT EXISTS \`$db_name\` DEFAULT CHARACTER SET utf8mb4;"
|
||
|
||
# 导入
|
||
zcat "$backup_path" | $MYSQL_CMD "$db_name" 2>&1 | tail -1
|
||
|
||
if [[ ${PIPESTATUS[0]} -eq 0 ]]; then
|
||
log_ok " $db_name restored successfully"
|
||
else
|
||
log_error " $db_name restore FAILED"
|
||
fi
|
||
done
|
||
|
||
# 电梯应用还需要第二个备份 (34_*.sql.gz)
|
||
if [[ -f "$DATA_BACKUP/34_2026_04_23_17_28_33.sql.gz" ]]; then
|
||
log_info "Restoring elevator DB partition 34..."
|
||
zcat "$DATA_BACKUP/34_2026_04_23_17_28_33.sql.gz" | $MYSQL_CMD "$DB_ELEVATOR"
|
||
log_ok " $DB_ELEVATOR partition 34 restored"
|
||
fi
|
||
|
||
# 执行 V2.0.7 DDL (tenant_visitor_floor_policy)
|
||
log_info "Applying V2.0.7 DDL (tenant_visitor_floor_policy)..."
|
||
$MYSQL_CMD "$DB_ELEVATOR" < "$REPO_ROOT/docs/sql/tenant_visitor_floor_policy.sql"
|
||
log_ok " V2 DDL applied"
|
||
|
||
log_info "Database preparation complete"
|
||
```
|
||
|
||
- [ ] **Step 2: 测试脚本 (dry-run: 仅检查连通性)**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/prepare-db.sh
|
||
# 预期: MySQL connection OK, 然后恢复各个库
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add 源码/scripts/test-env/prepare-db.sh
|
||
git commit -m "feat: add database restoration script for 11 databases"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 4: 配置模板 + prepare-services.sh
|
||
|
||
**Files:**
|
||
- Create: `源码/scripts/test-env/config/service-templates/elevator-v2.properties`
|
||
- Create: `源码/scripts/test-env/config/service-templates/crk-std.properties`
|
||
- Create: `源码/scripts/test-env/config/service-templates/alarm.properties`
|
||
- Create: `源码/scripts/test-env/config/service-templates/ninca-common.properties`
|
||
- Create: `源码/scripts/test-env/config/service-templates/component-org.properties`
|
||
- Create: `源码/scripts/test-env/prepare-services.sh`
|
||
|
||
- [ ] **Step 1: 创建 V2 电梯配置模板**
|
||
|
||
`源码/scripts/test-env/config/service-templates/elevator-v2.properties`:
|
||
|
||
```properties
|
||
# V2 elevator test config — auto-generated from template
|
||
# Variables: __MYSQL_HOST__ __MYSQL_PORT__ __REDIS_HOST__ __REDIS_PASS__
|
||
# __CONSUL_HOST__ __CONSUL_PORT__ __KAFKA_HOST__ __KAFKA_PORT__
|
||
# __CRK_HOST__ __CRK_PORT__
|
||
server.port=18081
|
||
spring.application.name=elevator-app
|
||
spring.profiles.active=access-control
|
||
|
||
# Consul
|
||
spring.cloud.consul.host=__CONSUL_HOST__
|
||
spring.cloud.consul.port=__CONSUL_PORT__
|
||
spring.cloud.consul.enabled=true
|
||
spring.cloud.consul.discovery.register=true
|
||
spring.cloud.consul.discovery.enabled=false
|
||
|
||
# MySQL (ShardingSphere)
|
||
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/cw-elevator-application?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
|
||
spring.shardingsphere.datasource.ds0.username=root
|
||
spring.shardingsphere.datasource.ds0.password=123456
|
||
|
||
# Redis
|
||
spring.redis.host=__REDIS_HOST__
|
||
spring.redis.port=6379
|
||
spring.redis.password=__REDIS_PASS__
|
||
spring.redis.database=5
|
||
|
||
# Kafka
|
||
cloudwalk.event.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
|
||
cloudwalk.event.group-id=cw-elevator-application-test
|
||
|
||
# Feign targets
|
||
feign.device.name=cwos-portal
|
||
feign.cwos-portal.name=cwos-portal
|
||
feign.ninca-crk-std.name=ninca-crk-std
|
||
ninca-crk-std.ribbon.NIWSServerListClassName=com.netflix.loadbalancer.ConfigurationBasedServerList
|
||
ninca-crk-std.ribbon.listOfServers=__CRK_HOST__:__CRK_PORT__
|
||
ninca-crk-std.ip=__CRK_HOST__:__CRK_PORT__
|
||
|
||
# Other
|
||
feign.hystrix.enable=true
|
||
feign.okhttp.enable=true
|
||
ribbon.ReadTimeout=10000
|
||
ribbon.ConnectTimeout=10000
|
||
elevator.application.key=xinghewan
|
||
elevator.application.time=600
|
||
elevator.application.keyA=5B7DEF88FF04
|
||
floor.building.id=605560539791228928
|
||
sendRecord.boolean=false
|
||
```
|
||
|
||
- [ ] **Step 2: 创建 CRK 后端配置模板**
|
||
|
||
`源码/scripts/test-env/config/service-templates/crk-std.properties`:
|
||
|
||
```properties
|
||
# CRK-std test config
|
||
spring.application.name=ninca-crk-std
|
||
server.port=__CRK_PORT__
|
||
spring.profiles.active=smart-attendance,visitor-management,access-control,conference-attendance
|
||
|
||
# Consul
|
||
spring.cloud.consul.host=__CONSUL_HOST__
|
||
spring.cloud.consul.port=__CONSUL_PORT__
|
||
spring.cloud.consul.discovery.register=true
|
||
spring.cloud.consul.discovery.ip-address=127.0.0.1
|
||
|
||
# MySQL
|
||
spring.shardingsphere.datasource.ds0.jdbc-url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/ninca_crk_std?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
|
||
spring.shardingsphere.datasource.ds0.username=root
|
||
spring.shardingsphere.datasource.ds0.password=123456
|
||
|
||
# Redis
|
||
spring.redis.host=__REDIS_HOST__
|
||
spring.redis.port=6379
|
||
spring.redis.password=__REDIS_PASS__
|
||
spring.redis.database=5
|
||
|
||
# Kafka
|
||
kafka.producer.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
|
||
kafka.consumer.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
|
||
spring.kafka.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
|
||
spring.kafka.consumer.group-id=crk_std_test
|
||
cloudwalk.event.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
|
||
cloudwalk.event.group-id=crk_std
|
||
|
||
# Feign service names
|
||
feign.device.name=cwos-portal
|
||
feign.resource.name=cwos-portal
|
||
feign.cwos-portal.name=cwos-portal
|
||
feign.portal.name=cwos-portal
|
||
feign.component-organization.name=ninca-common-component-organization
|
||
feign.davinci-portal.name=cwos-portal
|
||
feign.ninca-common.name=ninca-common
|
||
feign.elevator.name=elevator-app
|
||
|
||
# Quartz
|
||
quartz.driver=com.mysql.jdbc.Driver
|
||
quartz.url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/ninca_crk_std?zeroDateTimeBehavior=convertToNull&useUnicode=TRUE&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true
|
||
quartz.user=root
|
||
quartz.password=123456
|
||
|
||
# Management
|
||
management.port=__CRK_MGMT_PORT__
|
||
management.context-path=/actuator
|
||
management.security.enabled=false
|
||
|
||
xinhewan.businessid=2524639890ba4f2cba9ba1a4eeaa4015
|
||
push.method=1
|
||
sendRecord.boolean=false
|
||
```
|
||
|
||
- [ ] **Step 3: 创建 alarm 配置模板**
|
||
|
||
`源码/scripts/test-env/config/service-templates/alarm.properties`:
|
||
|
||
```properties
|
||
# Alarm app test config
|
||
spring.application.name=ninca-qk-alarm-app
|
||
server.port=__ALARM_PORT__
|
||
spring.main.allow-bean-definition-overriding=true
|
||
|
||
# Consul
|
||
spring.cloud.consul.host=__CONSUL_HOST__
|
||
spring.cloud.consul.port=__CONSUL_PORT__
|
||
spring.cloud.consul.discovery.register=true
|
||
spring.cloud.consul.discovery.ip-address=127.0.0.1
|
||
|
||
# MySQL
|
||
spring.datasource.url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/alarm_deploy?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
|
||
spring.datasource.username=root
|
||
spring.datasource.password=123456
|
||
|
||
# Redis
|
||
spring.redis.host=__REDIS_HOST__
|
||
spring.redis.port=6379
|
||
spring.redis.password=__REDIS_PASS__
|
||
spring.redis.database=7
|
||
|
||
# Kafka
|
||
kafka.producer.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
|
||
kafka.consumer.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
|
||
spring.kafka.bootstrap-servers=__KAFKA_HOST__:__KAFKA_PORT__
|
||
spring.kafka.consumer.group-id=alarm_test
|
||
|
||
# Feign names
|
||
cloudwalk.alarm-app.feign.name.cwos-portal=cwos-portal
|
||
cloudwalk.alarm-app.feign.name.component-organization=ninca-common-component-organization
|
||
cloudwalk.alarm-app.feign.name.ninca-common=ninca-common
|
||
|
||
# Management
|
||
management.port=__ALARM_MGMT_PORT__
|
||
management.context-path=/actuator
|
||
management.security.enabled=false
|
||
|
||
# Disable non-essential features for test
|
||
swagger.enable=false
|
||
sendRecord.boolean=false
|
||
```
|
||
|
||
- [ ] **Step 4: 创建 ninca-common 和 component-org 配置模板**
|
||
|
||
`源码/scripts/test-env/config/service-templates/ninca-common.properties`:
|
||
|
||
```properties
|
||
server.port=__NINCA_COMMON_PORT__
|
||
spring.application.name=ninca-common
|
||
spring.datasource.url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/ninca_common?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
|
||
spring.datasource.username=root
|
||
spring.datasource.password=123456
|
||
spring.cloud.consul.host=__CONSUL_HOST__
|
||
spring.cloud.consul.port=__CONSUL_PORT__
|
||
spring.cloud.consul.discovery.register=true
|
||
spring.redis.host=__REDIS_HOST__
|
||
spring.redis.port=6379
|
||
spring.redis.password=__REDIS_PASS__
|
||
```
|
||
|
||
`源码/scripts/test-env/config/service-templates/component-org.properties`:
|
||
|
||
```properties
|
||
server.port=__COMPONENT_ORG_PORT__
|
||
spring.application.name=ninca-common-component-organization
|
||
spring.datasource.url=jdbc:mysql://__MYSQL_HOST__:__MYSQL_PORT__/component-organization?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
|
||
spring.datasource.username=root
|
||
spring.datasource.password=123456
|
||
spring.cloud.consul.host=__CONSUL_HOST__
|
||
spring.cloud.consul.port=__CONSUL_PORT__
|
||
spring.cloud.consul.discovery.register=true
|
||
spring.redis.host=__REDIS_HOST__
|
||
spring.redis.port=6379
|
||
spring.redis.password=__REDIS_PASS__
|
||
```
|
||
|
||
- [ ] **Step 5: 编写 prepare-services.sh (解压 + 配置注入)**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# prepare-services.sh — 解压 tar.gz + 从模板生成配置
|
||
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
|
||
|
||
log_info "Phase 4: Service preparation"
|
||
mkdir -p "$SERVICE_DIR" "$LOG_DIR"
|
||
|
||
# 需要解压的 tar.gz 列表
|
||
TARBALLS=(
|
||
"$STAR_CENTER/ninca_common_01-ninca_common_backend.tar.gz:ninca-common"
|
||
"$STAR_CENTER/ninca_common_component_organization_01-ninca_common_component_organization.tar.gz:component-org"
|
||
"$STAR_CENTER/ninca_common_snap_app_01-ninca_common_snap_app.tar.gz:snap-app"
|
||
"$STAR_CENTER/ninca_common_vehicle_app_01-ninca_common_vehicle_app.tar.gz:vehicle-app"
|
||
"$STAR_CENTER/ninca_common_monitor_app_01-ninca_common_monitor_app.tar.gz:monitor-app"
|
||
"$STAR_CENTER/ninca-person-file-app-V2.9.2_20210216.tar.gz:person-file"
|
||
)
|
||
|
||
for item in "${TARBALLS[@]}"; do
|
||
tarball="${item%%:*}"
|
||
svc_name="${item##*:}"
|
||
svc_dir="$SERVICE_DIR/$svc_name"
|
||
|
||
if [[ -d "$svc_dir" ]]; then
|
||
log_info "Already extracted: $svc_name — skipping"
|
||
continue
|
||
fi
|
||
|
||
log_info "Extracting $tarball → $svc_dir ..."
|
||
mkdir -p "$svc_dir"
|
||
tar -xzf "$tarball" -C "$svc_dir" --strip-components=1
|
||
log_ok " $svc_name extracted"
|
||
done
|
||
|
||
# 配置模板变量替换函数
|
||
render_template() {
|
||
local template="$1"
|
||
local output="$2"
|
||
sed \
|
||
-e "s|__MYSQL_HOST__|$MYSQL_HOST|g" \
|
||
-e "s|__MYSQL_PORT__|$MYSQL_PORT|g" \
|
||
-e "s|__REDIS_HOST__|$REDIS_HOST|g" \
|
||
-e "s|__REDIS_PASS__|$REDIS_PASS|g" \
|
||
-e "s|__CONSUL_HOST__|$CONSUL_HOST|g" \
|
||
-e "s|__CONSUL_PORT__|$CONSUL_PORT|g" \
|
||
-e "s|__KAFKA_HOST__|$KAFKA_HOST|g" \
|
||
-e "s|__KAFKA_PORT__|$KAFKA_PORT|g" \
|
||
-e "s|__CRK_HOST__|127.0.0.1|g" \
|
||
-e "s|__CRK_PORT__|$PORT_CRK_STD|g" \
|
||
-e "s|__CRK_MGMT_PORT__|$PORT_CRK_MGMT|g" \
|
||
-e "s|__ALARM_PORT__|$PORT_ALARM|g" \
|
||
-e "s|__ALARM_MGMT_PORT__|$PORT_ALARM_MGMT|g" \
|
||
-e "s|__NINCA_COMMON_PORT__|$PORT_NINCA_COMMON|g" \
|
||
-e "s|__COMPONENT_ORG_PORT__|$PORT_COMPONENT_ORG|g" \
|
||
"$template" > "$output"
|
||
}
|
||
|
||
# 为各服务生成配置文件
|
||
render_template "$TEST_ENV_DIR/config/service-templates/elevator-v2.properties" \
|
||
"$REPO_ROOT/maven-cw-elevator-application/deploy/v2-maven/application-test.properties"
|
||
log_ok " elevator-v2 config generated"
|
||
|
||
render_template "$TEST_ENV_DIR/config/service-templates/crk-std.properties" \
|
||
"$STAR_CENTER/ninca_crk_std_01-ninca_crk_std_backend/application-test.properties"
|
||
log_ok " crk-std config generated"
|
||
|
||
render_template "$TEST_ENV_DIR/config/service-templates/alarm.properties" \
|
||
"$STAR_CENTER/ninca_qk_alarm_app_01-ninca_qk_alarm_app/application-test.properties"
|
||
log_ok " alarm config generated"
|
||
|
||
# 为解压的 tarball 服务生成配置
|
||
if [[ -d "$SERVICE_DIR/ninca-common" ]]; then
|
||
render_template "$TEST_ENV_DIR/config/service-templates/ninca-common.properties" \
|
||
"$SERVICE_DIR/ninca-common/application-test.properties"
|
||
log_ok " ninca-common config generated"
|
||
fi
|
||
|
||
if [[ -d "$SERVICE_DIR/component-org" ]]; then
|
||
render_template "$TEST_ENV_DIR/config/service-templates/component-org.properties" \
|
||
"$SERVICE_DIR/component-org/application-test.properties"
|
||
log_ok " component-org config generated"
|
||
fi
|
||
|
||
log_info "Service preparation complete"
|
||
```
|
||
|
||
- [ ] **Step 6: 测试 prepare-services.sh**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/prepare-services.sh
|
||
# 预期: 解压 6 个 tar.gz, 生成 5 个配置文件
|
||
```
|
||
|
||
- [ ] **Step 7: Commit**
|
||
|
||
```bash
|
||
git add 源码/scripts/test-env/config/service-templates/ 源码/scripts/test-env/prepare-services.sh
|
||
git commit -m "feat: add service config templates and extraction script"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 5: build-elevator-v2.sh — 编译 V2 电梯应用
|
||
|
||
**Files:**
|
||
- Create: `源码/scripts/test-env/build-elevator-v2.sh`
|
||
|
||
- [ ] **Step 1: 编写 V2 编译脚本**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# build-elevator-v2.sh — 编译 cw-elevator-application V2
|
||
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
|
||
|
||
log_info "Building V2 elevator application..."
|
||
|
||
cd "$REPO_ROOT/maven-cw-elevator-application"
|
||
|
||
export JAVA_HOME
|
||
export PATH="$JAVA_HOME/bin:$PATH"
|
||
|
||
log_info "JDK: $($JAVA -version 2>&1 | head -1)"
|
||
|
||
# 编译 (跳过测试)
|
||
$MVN clean install $MVN_OPTS 2>&1 | tail -5
|
||
|
||
if [[ ${PIPESTATUS[0]} -eq 0 ]]; then
|
||
log_ok "V2 elevator build SUCCESS"
|
||
else
|
||
log_error "V2 elevator build FAILED — check logs"
|
||
exit 1
|
||
fi
|
||
|
||
# 同步 JAR 到 deploy/
|
||
if [[ -f "cw-elevator-application-starter/target/cw-elevator-application-2.0.7.jar" ]]; then
|
||
cp cw-elevator-application-starter/target/cw-elevator-application-2.0.7.jar \
|
||
deploy/v2-maven/cw-elevator-application-2.0.7.jar
|
||
log_ok "JAR synced to deploy/v2-maven/"
|
||
else
|
||
# Fallback: 用脚本同步
|
||
cd deploy && bash sync-jars.sh
|
||
log_ok "JAR synced via sync-jars.sh"
|
||
fi
|
||
```
|
||
|
||
- [ ] **Step 2: 测试编译**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/build-elevator-v2.sh
|
||
# 预期: BUILD SUCCESS, JAR synced
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add 源码/scripts/test-env/build-elevator-v2.sh
|
||
git commit -m "feat: add V2 elevator build script"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 6: start-all.sh / stop-all.sh — 服务启停
|
||
|
||
**Files:**
|
||
- Create: `源码/scripts/test-env/start-all.sh`
|
||
- Create: `源码/scripts/test-env/stop-all.sh`
|
||
|
||
- [ ] **Step 1: 编写 start-all.sh**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# start-all.sh — 按拓扑序启动所有 Java 服务
|
||
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
|
||
export JAVA_HOME
|
||
export PATH="$JAVA_HOME/bin:$PATH"
|
||
|
||
log_info "Phase 5: Starting all services..."
|
||
mkdir -p "$LOG_DIR"
|
||
|
||
# 启动函数: start_service <name> <jar_path> <port> <java_opts> <extra_args>
|
||
start_service() {
|
||
local name="$1"; local jar="$2"; local port="$3"
|
||
local opts="${4:-$JAVA_OPTS_LIGHT}"; shift 4
|
||
|
||
log_info "Starting $name (port $port)..."
|
||
|
||
if [[ ! -f "$jar" ]]; then
|
||
log_error " JAR not found: $jar"
|
||
return 1
|
||
fi
|
||
|
||
nohup $JAVA -jar $opts "$jar" "$@" \
|
||
--spring.config.location="$(dirname "$jar")/" \
|
||
> "$LOG_DIR/${name}.log" 2>&1 &
|
||
|
||
local pid=$!
|
||
echo $pid > "$LOG_DIR/${name}.pid"
|
||
|
||
# 等待服务就绪 (最多 60s)
|
||
for i in $(seq 1 30); do
|
||
sleep 2
|
||
if curl -sf "http://127.0.0.1:$port/actuator/health" &>/dev/null; then
|
||
log_ok " $name (pid=$pid, port=$port) STARTED"
|
||
return 0
|
||
fi
|
||
done
|
||
|
||
log_warn " $name health check timeout after 60s (pid=$pid)"
|
||
return 1
|
||
}
|
||
|
||
# ============================================
|
||
# 启动顺序 (拓扑序)
|
||
# ============================================
|
||
|
||
# A1: ninca-common
|
||
COMMON_JAR=$(find "$SERVICE_DIR/ninca-common" -name "*.jar" -not -name "*-sources*" | head -1)
|
||
if [[ -n "$COMMON_JAR" ]]; then
|
||
start_service "ninca-common" "$COMMON_JAR" "$PORT_NINCA_COMMON" \
|
||
"$JAVA_OPTS_LIGHT" \
|
||
--spring.config.additional-location="$TEST_ENV_DIR/config/service-templates/ninca-common.properties"
|
||
fi
|
||
|
||
# A2: component-organization
|
||
ORG_JAR=$(find "$SERVICE_DIR/component-org" -name "*.jar" -not -name "*-sources*" | head -1)
|
||
if [[ -n "$ORG_JAR" ]]; then
|
||
start_service "component-org" "$ORG_JAR" "$PORT_COMPONENT_ORG" \
|
||
"$JAVA_OPTS_LIGHT" \
|
||
--spring.config.additional-location="$TEST_ENV_DIR/config/service-templates/component-org.properties"
|
||
fi
|
||
|
||
# A10: CRK-std
|
||
CRK_DIR="$STAR_CENTER/ninca_crk_std_01-ninca_crk_std_backend/ninca-crk-std-backend-V2.9.2_20210730"
|
||
CRK_JAR="$STAR_CENTER/ninca_crk_std_01-ninca_crk_std_backend/ninca-crk-std-backend-V2.9.2_20210730.jar"
|
||
if [[ -f "$CRK_JAR" ]]; then
|
||
start_service "crk-std" "$CRK_JAR" "$PORT_CRK_STD" \
|
||
"$JAVA_OPTS_HEAVY" \
|
||
--spring.config.location="$CRK_DIR/"
|
||
fi
|
||
|
||
# A11: alarm-app
|
||
ALARM_JAR="$STAR_CENTER/ninca_qk_alarm_app_01-ninca_qk_alarm_app/ninca-qk-alarm-app-V2.9.2_20210730.jar"
|
||
if [[ -f "$ALARM_JAR" ]]; then
|
||
start_service "alarm-app" "$ALARM_JAR" "$PORT_ALARM" \
|
||
"$JAVA_OPTS_HEAVY" \
|
||
--spring.config.location="$STAR_CENTER/ninca_qk_alarm_app_01-ninca_qk_alarm_app/"
|
||
fi
|
||
|
||
# A12: elevator V2 (最后启动,依赖 CRK+portal+org)
|
||
ELEVATOR_V2_JAR="$REPO_ROOT/maven-cw-elevator-application/deploy/v2-maven/cw-elevator-application-2.0.7.jar"
|
||
if [[ -f "$ELEVATOR_V2_JAR" ]]; then
|
||
start_service "elevator-v2" "$ELEVATOR_V2_JAR" "$PORT_ELEVATOR_V2" \
|
||
"$JAVA_OPTS_HEAVY" \
|
||
--spring.config.location="$REPO_ROOT/maven-cw-elevator-application/deploy/v2-maven/"
|
||
fi
|
||
|
||
# A13: elevator V1 (对拍对照)
|
||
ELEVATOR_V1_JAR="$REPO_ROOT/maven-cw-elevator-application/deploy/v1-legacy/cw-elevator-application-V1.0.0.20211103.jar"
|
||
if [[ -f "$ELEVATOR_V1_JAR" ]]; then
|
||
start_service "elevator-v1" "$ELEVATOR_V1_JAR" "$PORT_ELEVATOR_V1" \
|
||
"$JAVA_OPTS_HEAVY" \
|
||
--spring.config.location="$REPO_ROOT/maven-cw-elevator-application/deploy/v1-legacy/"
|
||
fi
|
||
|
||
log_info "All services started"
|
||
```
|
||
|
||
- [ ] **Step 2: 编写 stop-all.sh**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# stop-all.sh — 按逆序停止所有服务
|
||
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
|
||
|
||
log_info "Stopping all services..."
|
||
|
||
for pid_file in "$LOG_DIR"/*.pid; do
|
||
if [[ -f "$pid_file" ]]; then
|
||
pid=$(cat "$pid_file")
|
||
svc=$(basename "$pid_file" .pid)
|
||
if kill -0 "$pid" 2>/dev/null; then
|
||
log_info "Stopping $svc (pid=$pid)..."
|
||
kill "$pid"
|
||
sleep 2
|
||
kill -9 "$pid" 2>/dev/null || true
|
||
log_ok " $svc stopped"
|
||
fi
|
||
rm -f "$pid_file"
|
||
fi
|
||
done
|
||
|
||
log_info "All services stopped"
|
||
```
|
||
|
||
- [ ] **Step 3: 测试启动/停止流程**
|
||
|
||
```bash
|
||
# 先确保 Docker infra 已启动
|
||
# 然后:
|
||
bash 源码/scripts/test-env/start-all.sh
|
||
sleep 30
|
||
bash 源码/scripts/test-env/stop-all.sh
|
||
```
|
||
|
||
- [ ] **Step 4: Commit**
|
||
|
||
```bash
|
||
git add 源码/scripts/test-env/start-all.sh 源码/scripts/test-env/stop-all.sh
|
||
git commit -m "feat: add service start/stop orchestration scripts"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 7: health-check.sh — 探活检查
|
||
|
||
**Files:**
|
||
- Create: `源码/scripts/test-env/health-check.sh`
|
||
|
||
- [ ] **Step 1: 编写探活脚本**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# health-check.sh — 全组件探活检查
|
||
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
|
||
|
||
log_info "=== Health Check ==="
|
||
FAILED=0
|
||
PASSED=0
|
||
|
||
check_http() {
|
||
local name="$1"; local url="$2"
|
||
if curl -sf --max-time 5 "$url" &>/dev/null; then
|
||
log_ok " $name ($url)"
|
||
((PASSED++))
|
||
else
|
||
log_error " $name ($url) FAILED"
|
||
((FAILED++))
|
||
fi
|
||
}
|
||
|
||
check_tcp() {
|
||
local name="$1"; local host="$2"; local port="$3"
|
||
if nc -z -w3 "$host" "$port" &>/dev/null; then
|
||
log_ok " $name ($host:$port)"
|
||
((PASSED++))
|
||
else
|
||
log_error " $name ($host:$port) FAILED"
|
||
((FAILED++))
|
||
fi
|
||
}
|
||
|
||
log_info "--- Infrastructure ---"
|
||
check_http "Consul" "http://$CONSUL_HOST:$CONSUL_PORT/v1/status/leader"
|
||
check_tcp "Redis" "$REDIS_HOST" "$REDIS_PORT"
|
||
check_tcp "Kafka" "$KAFKA_HOST" "$KAFKA_PORT"
|
||
check_http "Nginx" "http://$CONSUL_HOST:$PORT_NGINX"
|
||
|
||
log_info "--- Application Services ---"
|
||
check_http "elevator-v2" "http://127.0.0.1:$PORT_ELEVATOR_V2/actuator/health"
|
||
check_http "elevator-v1" "http://127.0.0.1:$PORT_ELEVATOR_V1/actuator/health"
|
||
check_http "crk-std" "http://127.0.0.1:$PORT_CRK_MGMT/actuator/health"
|
||
check_http "alarm-app" "http://127.0.0.1:$PORT_ALARM_MGMT/actuator/health"
|
||
|
||
log_info "--- Databases ---"
|
||
check_tcp "MySQL" "$MYSQL_HOST" "$MYSQL_PORT"
|
||
|
||
log_info "--- Consul Registration ---"
|
||
CONSUL_SVCS=$(curl -sf "http://$CONSUL_HOST:$CONSUL_PORT/v1/agent/services" | python3 -c "import sys,json; print(len(json.load(sys.stdin)))" 2>/dev/null || echo "0")
|
||
log_info " Registered services: $CONSUL_SVCS"
|
||
|
||
echo ""
|
||
log_info "=== Result: $PASSED passed, $FAILED failed ==="
|
||
|
||
[[ $FAILED -eq 0 ]] && exit 0 || exit 1
|
||
```
|
||
|
||
- [ ] **Step 2: 测试探活**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/health-check.sh
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add 源码/scripts/test-env/health-check.sh
|
||
git commit -m "feat: add health-check script for all components"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 8: verify-functional.sh — 功能验证
|
||
|
||
**Files:**
|
||
- Create: `源码/scripts/test-env/verify-functional.sh`
|
||
|
||
- [ ] **Step 1: 编写功能验证脚本**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# verify-functional.sh — V2 全系统功能验证
|
||
source "$(dirname "${BASH_SOURCE[0]}")/config/env.sh"
|
||
|
||
log_info "=== V2 Functional Verification ==="
|
||
FAILED=0
|
||
|
||
verify() {
|
||
local desc="$1"; shift
|
||
if "$@"; then
|
||
log_ok " $desc"
|
||
else
|
||
log_error " $desc FAILED"
|
||
((FAILED++))
|
||
fi
|
||
}
|
||
|
||
# F1: 电梯 V2 探活
|
||
log_info "[F1] Elevator V2 health"
|
||
verify "elevator-v2 /actuator/health" \
|
||
curl -sf "http://127.0.0.1:$PORT_ELEVATOR_V2/actuator/health"
|
||
|
||
# F2: V1 vs V2 API 对拍
|
||
log_info "[F2] V1/V2 API parity test"
|
||
cd "$REPO_ROOT/maven-cw-elevator-application/tools/elevator_api_parity"
|
||
verify "pytest elevator_api_parity" \
|
||
pytest tests/test_smoke_catalog.py -q --tb=short
|
||
|
||
# F3: V2.0.7 租户策略 — UC-01 基线 (无策略表 → floorList 全集)
|
||
log_info "[F3] Tenant visitor policy — UC-01 baseline"
|
||
# 注意: 需要先插入策略表测试数据; 基线测试确认无策略时行为不变
|
||
RESP=$(curl -sf -X POST "http://127.0.0.1:$PORT_ELEVATOR_V2/elevator/person/add/visitor" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"personId":"test-person","visitorName":"test-visitor"}' 2>/dev/null || echo '{"code":-1}')
|
||
verify "UC-01 baseline (no policy)" echo "$RESP" | python3 -c "import sys,json; d=json.load(sys.stdin); assert d.get('code')!=76260532"
|
||
|
||
# F4: V2.0.7 — UC-02 显式传 floorIds
|
||
log_info "[F4] Tenant visitor policy — UC-02 explicit floorIds"
|
||
RESP2=$(curl -sf -X POST "http://127.0.0.1:$PORT_ELEVATOR_V2/elevator/person/add/visitor" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"personId":"test-person","visitorName":"test-visitor2","floorIds":["zone-001"]}' 2>/dev/null || echo '{"code":-1}')
|
||
verify "UC-02 (explicit floorIds)" echo "$RESP2" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('code'))"
|
||
|
||
# F7: CRK 联动
|
||
log_info "[F7] CRK integration"
|
||
verify "crk-std /actuator/health" \
|
||
curl -sf "http://127.0.0.1:$PORT_CRK_MGMT/actuator/health"
|
||
|
||
# F8: 报警 Kafka 消费
|
||
log_info "[F8] Alarm Kafka — Consul registration check"
|
||
verify "alarm registered in Consul" \
|
||
curl -sf "http://$CONSUL_HOST:$CONSUL_PORT/v1/agent/services" | python3 -c "import sys,json; services=json.load(sys.stdin); assert any('alarm' in k.lower() for k in services)"
|
||
|
||
# F9: Nginx 前端代理
|
||
log_info "[F9] Frontend Nginx"
|
||
verify "nginx serves cwos-portal" \
|
||
curl -sf -o /dev/null -w "%{http_code}" "http://$CONSUL_HOST:$PORT_NGINX/" | grep -q 200
|
||
|
||
# I1: MySQL 连通
|
||
log_info "[I1] MySQL connectivity"
|
||
verify "mysql SELECT 1" \
|
||
mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SELECT 1" &>/dev/null
|
||
|
||
echo ""
|
||
log_info "=== Verification Complete: $FAILED failures ==="
|
||
[[ $FAILED -eq 0 ]] && exit 0 || exit 1
|
||
```
|
||
|
||
- [ ] **Step 2: 测试验证脚本 (需要服务已运行)**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/verify-functional.sh
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add 源码/scripts/test-env/verify-functional.sh
|
||
git commit -m "feat: add functional verification script (API parity + tenant policy + integration)"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 9: setup.sh — 主入口一键搭建
|
||
|
||
**Files:**
|
||
- Create: `源码/scripts/test-env/setup.sh`
|
||
|
||
- [ ] **Step 1: 编写主入口脚本**
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# setup.sh — V2 测试环境一键搭建入口
|
||
set -euo pipefail
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
source "$SCRIPT_DIR/config/env.sh"
|
||
|
||
cat << 'BANNER'
|
||
╔══════════════════════════════════════════════╗
|
||
║ V2 Full-System Test Environment Setup ║
|
||
║ cw-elevator-application v2.0.7 ║
|
||
╚══════════════════════════════════════════════╝
|
||
BANNER
|
||
|
||
START_TIME=$(date +%s)
|
||
|
||
# ============================================
|
||
# Phase 1: 环境检查
|
||
# ============================================
|
||
log_info "Phase 1/6: Environment check"
|
||
|
||
# JDK 8
|
||
if [[ ! -x "$JAVA_HOME/bin/java" ]]; then
|
||
log_error "JDK 8 not found at $JAVA_HOME"
|
||
log_info "Set DEPLOY_JDK8 environment variable to correct path"
|
||
exit 1
|
||
fi
|
||
JAVA_VER=$("$JAVA_HOME/bin/java" -version 2>&1 | head -1)
|
||
log_ok "JDK: $JAVA_VER"
|
||
|
||
# Maven
|
||
if ! command -v mvn &>/dev/null; then
|
||
log_error "Maven not found"
|
||
exit 1
|
||
fi
|
||
log_ok "Maven: $(mvn --version 2>&1 | head -1)"
|
||
|
||
# Docker
|
||
if ! docker compose version &>/dev/null; then
|
||
log_error "Docker Compose not found"
|
||
exit 1
|
||
fi
|
||
log_ok "Docker: $(docker compose version)"
|
||
|
||
# MySQL
|
||
if ! mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SELECT 1" &>/dev/null; then
|
||
log_error "Cannot connect to MySQL at $MYSQL_HOST:$MYSQL_PORT"
|
||
exit 1
|
||
fi
|
||
log_ok "MySQL: $MYSQL_HOST:$MYSQL_PORT OK"
|
||
|
||
# 端口冲突
|
||
CONFLICT_PORTS=""
|
||
for port in 8500 6379 9092 2181 8090 18080 18081 16106 17011 3721; do
|
||
if ss -tlnp 2>/dev/null | grep -q ":$port "; then
|
||
CONFLICT_PORTS="$CONFLICT_PORTS $port"
|
||
fi
|
||
done
|
||
if [[ -n "$CONFLICT_PORTS" ]]; then
|
||
log_warn "Ports already in use:$CONFLICT_PORTS"
|
||
log_warn "These services may fail to start. Stop existing processes first."
|
||
fi
|
||
|
||
log_ok "Phase 1 complete"
|
||
|
||
# ============================================
|
||
# Phase 2: 数据库准备
|
||
# ============================================
|
||
log_info "Phase 2/6: Database preparation"
|
||
bash "$SCRIPT_DIR/prepare-db.sh"
|
||
log_ok "Phase 2 complete"
|
||
|
||
# ============================================
|
||
# Phase 3: Docker 基础组件启动
|
||
# ============================================
|
||
log_info "Phase 3/6: Docker infrastructure"
|
||
cd "$SCRIPT_DIR"
|
||
docker compose -f docker-compose.infra.yml up -d
|
||
|
||
log_info "Waiting for Consul..."
|
||
for i in $(seq 1 30); do
|
||
if curl -sf "http://$CONSUL_HOST:$CONSUL_PORT/v1/status/leader" &>/dev/null; then
|
||
break
|
||
fi
|
||
sleep 2
|
||
done
|
||
log_ok "Consul ready"
|
||
|
||
log_info "Waiting for Kafka..."
|
||
sleep 15 # Kafka 启动较慢
|
||
log_ok "Kafka ready"
|
||
log_ok "Phase 3 complete"
|
||
|
||
# ============================================
|
||
# Phase 4: 服务准备
|
||
# ============================================
|
||
log_info "Phase 4/6: Service preparation"
|
||
bash "$SCRIPT_DIR/prepare-services.sh"
|
||
bash "$SCRIPT_DIR/build-elevator-v2.sh"
|
||
log_ok "Phase 4 complete"
|
||
|
||
# ============================================
|
||
# Phase 5: 服务启动
|
||
# ============================================
|
||
log_info "Phase 5/6: Service startup"
|
||
bash "$SCRIPT_DIR/start-all.sh"
|
||
log_ok "Phase 5 complete"
|
||
|
||
# ============================================
|
||
# Phase 6: 验证
|
||
# ============================================
|
||
log_info "Phase 6/6: Verification"
|
||
bash "$SCRIPT_DIR/health-check.sh"
|
||
bash "$SCRIPT_DIR/verify-functional.sh"
|
||
log_ok "Phase 6 complete"
|
||
|
||
# ============================================
|
||
# 汇总
|
||
# ============================================
|
||
END_TIME=$(date +%s)
|
||
DURATION=$((END_TIME - START_TIME))
|
||
|
||
cat << SUMMARY
|
||
|
||
╔══════════════════════════════════════════════╗
|
||
║ Setup Complete! ║
|
||
║ ║
|
||
║ Duration: ${DURATION}s ║
|
||
║ Consul: http://$CONSUL_HOST:$CONSUL_PORT/ui/ ║
|
||
║ Nginx: http://$CONSUL_HOST:$PORT_NGINX/ ║
|
||
║ Elevator V2: http://127.0.0.1:$PORT_ELEVATOR_V2 ║
|
||
║ Elevator V1: http://127.0.0.1:$PORT_ELEVATOR_V1 ║
|
||
║ CRK std: http://127.0.0.1:$PORT_CRK_STD ║
|
||
║ Alarm: http://127.0.0.1:$PORT_ALARM ║
|
||
╚══════════════════════════════════════════════╝
|
||
|
||
To stop: bash scripts/test-env/stop-all.sh && docker compose -f scripts/test-env/docker-compose.infra.yml down
|
||
|
||
SUMMARY
|
||
```
|
||
|
||
- [ ] **Step 2: 端到端测试**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/setup.sh
|
||
# 预期: 所有 6 个 Phase 完成, 显示 Setup Complete!
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add 源码/scripts/test-env/setup.sh
|
||
git commit -m "feat: add one-click test environment setup script (setup.sh)"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 10: 集成测试 — 完整搭建验证
|
||
|
||
**Files:**
|
||
- (无新文件,验证所有脚本正确协作)
|
||
|
||
- [ ] **Step 1: 清理环境**
|
||
|
||
```bash
|
||
# 停止所有之前的进程
|
||
bash 源码/scripts/test-env/stop-all.sh 2>/dev/null || true
|
||
docker compose -f 源码/scripts/test-env/docker-compose.infra.yml down -v 2>/dev/null || true
|
||
```
|
||
|
||
- [ ] **Step 2: 执行一键搭建**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/setup.sh 2>&1 | tee /tmp/v2test-setup.log
|
||
```
|
||
|
||
- [ ] **Step 3: 验证日志**
|
||
|
||
```bash
|
||
# 检查关键日志标记
|
||
grep -c "ERROR" /tmp/v2test-setup.log # 预期: 0
|
||
grep "Setup Complete" /tmp/v2test-setup.log # 预期: 找到
|
||
grep "Duration:" /tmp/v2test-setup.log # 预期: 找到耗时
|
||
```
|
||
|
||
- [ ] **Step 4: 验证关键端口**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/health-check.sh
|
||
# 预期: 全部 PASSED, FAILED=0
|
||
```
|
||
|
||
- [ ] **Step 5: 验证功能**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/verify-functional.sh
|
||
# 预期: 全部通过, 0 failures
|
||
```
|
||
|
||
- [ ] **Step 6: 清理**
|
||
|
||
```bash
|
||
bash 源码/scripts/test-env/stop-all.sh
|
||
docker compose -f 源码/scripts/test-env/docker-compose.infra.yml down
|
||
```
|
||
|
||
- [ ] **Step 7: Commit (如无代码变更则跳过)**
|
||
|
||
---
|
||
|
||
## 实施顺序依赖
|
||
|
||
```
|
||
Task 1 (env.sh) ← 所有后续 Task 的基础
|
||
↓
|
||
Task 2 (docker-compose) ← 可并行
|
||
↓
|
||
Task 3 (prepare-db.sh) ← 依赖 MySQL 地址 (env.sh)
|
||
Task 4 (templates + extract) ← 依赖 env.sh
|
||
↓
|
||
Task 5 (build V2) ← 依赖 env.sh
|
||
↓
|
||
Task 6 (start-all/stop-all) ← 依赖 Task 2,3,4,5
|
||
Task 7 (health-check) ← 独立
|
||
Task 8 (verify-functional) ← 独立 (但运行需服务已启动)
|
||
↓
|
||
Task 9 (setup.sh) ← 依赖 Task 2-8
|
||
↓
|
||
Task 10 (integration test) ← 依赖 Task 9
|
||
```
|
||
|
||
可并行执行: Task 3, 4, 5 (均只依赖 Task 1);Task 6, 7, 8 (均只依赖 Task 1-5)
|